4 using System.Collections.Generic;
7 using SiliconStudio.Paradox.Shaders.Parser.Analysis;
8 using SiliconStudio.Paradox.Shaders.Parser.Ast;
9 using SiliconStudio.Paradox.Shaders.Parser.Utility;
10 using SiliconStudio.Shaders.Ast;
11 using SiliconStudio.Shaders.Ast.Hlsl;
12 using SiliconStudio.Shaders.Utility;
16 namespace SiliconStudio.Paradox.Shaders.Parser.Mixins
18 internal class ParadoxShaderMixer
20 private readonly
static string FlipRendertargetVariableName =
"ParadoxFlipRendertarget";
22 #region Public members
36 #region Private members
41 private ModuleMixin mainModuleMixin = null;
46 private Dictionary<Variable, List<ModuleMixin>> CompositionsPerVariable;
51 private HashSet<List<MethodDeclaration>> StageMethodInheritance =
new HashSet<List<MethodDeclaration>>();
56 private List<ModuleMixin> MixinInheritance =
new List<ModuleMixin>();
61 private Dictionary<string, ModuleMixin> mixContext;
87 public ParadoxShaderMixer(ModuleMixin moduleMixin,
LoggerResult log, Dictionary<string, ModuleMixin> context, Dictionary<
Variable, List<ModuleMixin>> compositionsPerVariable,
CloneContext cloneContext = null)
89 if (moduleMixin == null)
90 throw new ArgumentNullException(
"moduleMixin");
93 throw new ArgumentNullException(
"log");
96 throw new ArgumentNullException(
"context");
100 mixContext = context;
101 mainModuleMixin = moduleMixin;
102 defaultCloneContext = cloneContext;
104 if (compositionsPerVariable != null)
105 CompositionsPerVariable = compositionsPerVariable;
107 CompositionsPerVariable =
new Dictionary<Variable, List<ModuleMixin>>();
109 var mixinsToAnalyze =
new Stack<ModuleMixin>(CompositionsPerVariable.SelectMany(x => x.Value));
110 mixinsToAnalyze.Push(mainModuleMixin);
112 while (mixinsToAnalyze.Count > 0)
113 AddDefaultCompositions(mixinsToAnalyze);
118 #region Public methods
125 CreateReferencesStructures();
127 mainModuleMixin.ClassReferences.RegenKeys();
128 mainModuleMixin.ExternReferences.RegenKeys();
129 mainModuleMixin.StaticReferences.RegenKeys();
130 mainModuleMixin.StageInitReferences.RegenKeys();
132 foreach (var externMix
in CompositionsPerVariable.SelectMany(externMixes => externMixes.Value))
134 externMix.ClassReferences.RegenKeys();
135 externMix.ExternReferences.RegenKeys();
136 externMix.StaticReferences.RegenKeys();
137 externMix.StageInitReferences.RegenKeys();
140 BuildMixinInheritance(mainModuleMixin);
141 MixinInheritance = MixinInheritance.Distinct().ToList();
143 ComputeMixinOccurence();
144 BuildStageInheritance();
146 LinkVariables(mainModuleMixin,
"",
new List<ModuleMixin>());
150 PatchAllMethodInferences(mainModuleMixin);
155 RenameAllVariables();
162 public Shader GetMixedShader()
164 var shader =
new Shader();
165 shader.Declarations.AddRange(MixedShader.Members);
172 #region Private methods
178 private void AddDefaultCompositions(Stack<ModuleMixin> mixinsToAnalyze)
180 var nextMixin = mixinsToAnalyze.Pop();
182 foreach (var externVar
in nextMixin.VariableDependencies)
184 if (!CompositionsPerVariable.ContainsKey(externVar.Key))
186 var newComp = externVar.Value.DeepClone(defaultCloneContext);
187 mixinsToAnalyze.Push(newComp);
188 CompositionsPerVariable.Add(externVar.Key,
new List<ModuleMixin> { newComp });
191 foreach (var dep
in nextMixin.InheritanceList)
192 mixinsToAnalyze.Push(dep);
198 private void RedoSematicAnalysis()
201 foreach (var composition
in CompositionsPerVariable.Where(x => x.Key.Type is
ArrayType))
203 var arrayType = composition.Key.Type as ArrayType;
204 if (arrayType.Dimensions.Count > 1)
206 log.Error(ParadoxMessageCode.ErrorMultidimensionalCompositionArray, arrayType.Span, arrayType, composition.Value.First().MixinName);
213 foreach (var composition
in CompositionsPerVariable.Where(x => x.Key.Type is
ArrayType))
216 var compilationContext = moduleMixin.MinimalContext.Where(x => !(moduleMixin.InheritanceList.Contains(x) || x == moduleMixin)).ToList();
219 foreach (var inheritedMixin
in moduleMixin.InheritanceList)
220 inheritedMixin.ParsingInfo = ParadoxSemanticAnalysis.RunAnalysis(inheritedMixin, compilationContext,
true);
221 moduleMixin.ParsingInfo = ParadoxSemanticAnalysis.RunAnalysis(moduleMixin, compilationContext,
true);
223 if (moduleMixin.ParsingInfo.ErrorsWarnings.HasErrors)
232 private void CreateReferencesStructures()
234 RedoSematicAnalysis();
235 CreateReferencesStructures(mainModuleMixin);
236 foreach (var compositions
in CompositionsPerVariable)
238 foreach (var comp
in compositions.Value)
239 CreateReferencesStructures(comp);
247 private void CreateReferencesStructures(ModuleMixin mixin)
249 GetStaticReferences(mixin, mixin);
252 mixin.ClassReferences.Merge(mixin.ParsingInfo.ClassReferences);
253 foreach (var dep
in mixin.InheritanceList)
254 mixin.ClassReferences.Merge(dep.ParsingInfo.ClassReferences);
256 mixin.StaticReferences.Merge(mixin.ParsingInfo.StaticReferences);
257 foreach (var dep
in mixin.InheritanceList)
258 mixin.StaticReferences.Merge(dep.ParsingInfo.StaticReferences);
260 mixin.ExternReferences.Merge(mixin.ParsingInfo.ExternReferences);
261 foreach (var dep
in mixin.InheritanceList)
262 mixin.ExternReferences.Merge(dep.ParsingInfo.ExternReferences);
264 mixin.StageInitReferences.Merge(mixin.ParsingInfo.StageInitReferences);
265 foreach (var dep
in mixin.InheritanceList)
266 mixin.StageInitReferences.Merge(dep.ParsingInfo.StageInitReferences);
274 private void GetStaticReferences(ModuleMixin topMixin, ModuleMixin staticMixin)
276 foreach (var staticDep
in staticMixin.ParsingInfo.StaticClasses)
277 GetStaticReferences(topMixin, staticDep);
278 foreach (var staticDep
in staticMixin.InheritanceList)
279 GetStaticReferences(topMixin, staticDep);
281 topMixin.StaticReferences.Merge(staticMixin.ParsingInfo.StaticReferences);
290 private void LinkVariables(ModuleMixin mixin,
string context, List<ModuleMixin> visitedMixins)
292 if (visitedMixins.Contains(mixin))
295 visitedMixins.Add(mixin);
297 foreach (var variable
in mixin.LocalVirtualTable.Variables.Select(x => x.Variable))
301 var baselink = context +
"." + variable.Name.Text;
302 List<ModuleMixin> mixins;
303 if (CompositionsPerVariable.TryGetValue(variable, out mixins))
307 for (var i = 0; i < mixins.Count; ++i)
309 LinkVariables(mixins[i], baselink +
"[" + i +
"]", visitedMixins);
314 LinkVariables(mixins[0], baselink, visitedMixins);
320 || variable.Qualifiers.Values.Contains(ParadoxStorageQualifier.PatchStream)
323 var attribute = variable.Attributes.OfType<
AttributeDeclaration>().FirstOrDefault(x => x.Name ==
"Link");
324 if (attribute == null)
335 var mapAttribute = variable.Attributes.OfType<AttributeDeclaration>().FirstOrDefault(x => x.Name ==
"Map");
336 if (mapAttribute != null)
338 linkName = (string)mapAttribute.Parameters[0].Value;
340 linkName = linkName.Replace(
"Keys.",
".");
344 linkName = mixin.MixinGenericName +
"." + variable.Name.Text;
347 attribute =
new AttributeDeclaration { Name =
new Identifier(
"Link"), Parameters =
new List<Literal> {
new Literal(linkName) } };
348 variable.Attributes.Add(attribute);
354 attribute.Parameters[0].SubLiterals = null;
355 attribute.Parameters[0].Value = (string)attribute.Parameters[0].
Value + context;
360 foreach (var variable
in mixin.StaticReferences.VariablesReferences.Select(x => x.Key))
362 var attribute = variable.Attributes.OfType<
AttributeDeclaration>().FirstOrDefault(x => x.Name ==
"Link");
363 if (attribute == null)
365 var baseClassName = (variable.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinGenericName;
367 attribute =
new AttributeDeclaration { Name =
new Identifier(
"Link"), Parameters =
new List<Literal> {
new Literal(baseClassName +
"." + variable.Name.Text) } };
368 variable.Attributes.Add(attribute);
372 mixin.InheritanceList.ForEach(x => LinkVariables(x, context, visitedMixins));
378 private void MergeReferences()
380 foreach (var externMixes
in CompositionsPerVariable)
382 foreach (var externMix
in externMixes.Value)
383 mainModuleMixin.ClassReferences.Merge(externMix.ClassReferences);
386 mainModuleMixin.ClassReferences.Merge(mainModuleMixin.StaticReferences);
393 private void AddStageVariables(ModuleMixin mixin)
395 mixin.InheritanceList.ForEach(AddStageVariables);
396 CompositionsPerVariable.Where(x => mixin.LocalVirtualTable.Variables.Any(
y => y.Variable == x.Key)).ToList().ForEach(externMixes => externMixes.Value.ForEach(AddStageVariables));
398 foreach (var variable
in mixin.LocalVirtualTable.Variables)
402 var shaderName = variable.Shader.Name.Text;
403 var sameVar = mainModuleMixin.ClassReferences.VariablesReferences.FirstOrDefault(x => x.Key.Name.Text == variable.Variable.Name.Text && (x.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinName == shaderName).Key;
407 if (!mainModuleMixin.ClassReferences.VariablesReferences.ContainsKey(variable.Variable))
408 mainModuleMixin.ClassReferences.VariablesReferences.Add(variable.Variable,
new HashSet<ExpressionNodeCouple>());
416 private void BuildMixinInheritance(ModuleMixin mixin)
418 mixin.InheritanceList.ForEach(BuildMixinInheritance);
419 MixinInheritance.Add(mixin);
420 CompositionsPerVariable.Where(x => mixin.LocalVirtualTable.Variables.Any(
y => y.Variable == x.Key)).ToList().ForEach(externMixes => externMixes.Value.ForEach(BuildMixinInheritance));
426 private void ComputeMixinOccurence()
428 foreach (var mixin
in MixinInheritance)
430 foreach (var mixin2
in MixinInheritance)
432 if (mixin.MixinName == mixin2.MixinName)
433 ++(mixin.OccurenceId);
452 result = FindVariableInMixin((expression as VariableReferenceExpression).Name.Text, mixin);
456 var memberExpression = expression as MemberReferenceExpression;
457 var target = memberExpression.Target;
459 if (target.TypeInference.Declaration is
Variable)
460 FindVariable(target, ref mixin);
462 FindShader(target, ref mixin);
464 result = FindVariableInMixin(memberExpression.Member.Text, mixin);
468 var indexerExpression = expression as IndexerExpression;
469 var target = indexerExpression.Target;
471 if (target.TypeInference.Declaration is
Variable)
472 result = FindVariable(target, ref mixin);
477 if (result is
Variable && (result as
Variable).Qualifiers.Contains(ParadoxStorageQualifier.Extern) && !((result as Variable).Type is
ArrayType))
478 mixin = CompositionsPerVariable[result as Variable][index];
483 private Variable FindVariableInMixin(
string varName, ModuleMixin mixin)
485 if (varName ==
"streams")
488 var foundVar = mixin.VirtualTable.Variables.FirstOrDefault(x => x.Variable.Name.Text == varName);
489 if (foundVar != null)
490 return foundVar.Variable;
492 log.Error(ParadoxMessageCode.ErrorVariableNotFound,
new SourceSpan(), varName, mixin.MixinName);
500 var memberExpression = expression as MemberReferenceExpression;
501 var target = memberExpression.Target;
503 if (target.TypeInference.Declaration is
Variable)
504 FindVariable(target, ref mixin);
506 FindShader(target, ref mixin);
509 var topMixin = GetTopMixin(mixin);
510 if (topMixin == null)
512 log.Error(ParadoxMessageCode.ErrorTopMixinNotFound, expression.Span, expression);
515 var foundMethod = topMixin.GetMethodFromExpression(expression);
516 if (foundMethod == null)
518 log.Error(ParadoxMessageCode.ErrorCallNotFound, expression.Span, expression);
523 log.Error(ParadoxMessageCode.ErrorCallToAbstractMethod, expression.Span, expression, foundMethod);
529 private void FindShader(
Expression expression, ref ModuleMixin mixin)
533 var memberExpression = expression as MemberReferenceExpression;
534 var target = memberExpression.Target;
536 if (target.TypeInference.Declaration is
Variable)
537 FindVariable(target, ref mixin);
539 var mixinName = (expression.TypeInference.Declaration as
ShaderClassType).Name.Text;
540 mixin = mixin.MixinName == mixinName ? mixin : mixin.InheritanceList.FirstOrDefault(x => x.MixinName == mixinName);
544 var indexerExpression = expression as IndexerExpression;
545 var target = indexerExpression.Target;
549 if (target.TypeInference.Declaration is
Variable)
550 result = FindVariable(target, ref mixin);
553 if (result is Variable && (result as Variable).Qualifiers.Contains(ParadoxStorageQualifier.Extern))
554 mixin = CompositionsPerVariable[result as Variable][index];
561 private void BuildStageInheritance()
563 foreach (var mixin
in MixinInheritance)
564 InsertStageMethods(mixin.LocalVirtualTable.Methods.Select(x => x.Method).Where(x => x.Qualifiers.Values.Contains(ParadoxStorageQualifier.Stage)).ToList(), GetTopMixin(mixin));
572 public void InsertStageMethods(List<MethodDeclaration> extMethodList, ModuleMixin mixin)
574 foreach (var extMethod
in extMethodList)
578 var isClone = extMethod.Qualifiers.Values.Contains(ParadoxStorageQualifier.Clone);
582 var vtReference = mixin.VirtualTable.GetBaseDeclaration(extMethod);
583 foreach (var stageMethodList
in StageMethodInheritance)
588 if (stageMethodList == null || stageMethodList.Count == 0)
591 var firstOccurence = stageMethodList.First();
592 var occurenceMixin = firstOccurence.GetTag(ParadoxTags.ShaderScope) as ModuleMixin;
593 var listVTReference = occurenceMixin.VirtualTable.GetBaseDeclaration(firstOccurence);
595 if (vtReference.Slot != listVTReference.Slot || vtReference.Shader != listVTReference.Shader)
599 var extMixin = extMethod.GetTag(ParadoxTags.ShaderScope) as ModuleMixin;
600 if (isClone || extMixin.OccurenceId == 1)
601 stageMethodList.Add(extMethod);
606 var list =
new List<MethodDeclaration>();
608 StageMethodInheritance.Add(list);
611 var externClassRef = GetTopMixin(mixin).ClassReferences;
612 if (externClassRef != null && !mainModuleMixin.ClassReferences.MethodsReferences.ContainsKey(extMethod))
614 externClassRef.RegenKeys();
615 mainModuleMixin.ClassReferences.MethodsReferences.Add(extMethod, externClassRef.MethodsReferences[extMethod]);
616 externClassRef.MethodsReferences.Remove(extMethod);
631 if (!mainModuleMixin.ClassReferences.MethodsReferences.ContainsKey(decl))
632 mainModuleMixin.ClassReferences.MethodsReferences.Add(decl,
new HashSet<MethodInvocationExpression>());
633 mainModuleMixin.ClassReferences.MethodsReferences[decl].Add(expression);
643 foreach (var refList
in mixin.ClassReferences.MethodsReferences)
644 refList.Value.RemoveWhere(x => x == expression);
646 foreach (var refList
in mainModuleMixin.ClassReferences.MethodsReferences)
647 refList.Value.RemoveWhere(x => x == expression);
655 private ModuleMixin GetTopMixin(ModuleMixin mixin)
657 var topMixin = mainModuleMixin == mixin || mainModuleMixin.InheritanceList.Any(x => x == mixin) ? mainModuleMixin : null;
658 if (topMixin == null)
660 foreach (var externMixes
in CompositionsPerVariable)
662 foreach (var externMix
in externMixes.Value)
664 topMixin = externMix == mixin || externMix.InheritanceList.Any(x => x == mixin) ? externMix : null;
665 if (topMixin != null)
668 if (topMixin != null)
683 defMixin = mixContext[defMixin.MixinName];
684 return defMixin.GetMethodFromExpression(expression.Target);
694 var mixin = methodCall.GetTag(ParadoxTags.CurrentShader) as ModuleMixin;
695 var vtReference = mixin.VirtualTable.GetBaseDeclaration(methodCall.Target.TypeInference.Declaration as
MethodDeclaration);
696 foreach (var stageMethodList
in StageMethodInheritance)
698 if (stageMethodList == null || stageMethodList.Count == 0)
701 var firstOccurence = stageMethodList.First();
702 var occurenceMixin = firstOccurence.GetTag(ParadoxTags.ShaderScope) as ModuleMixin;
703 var listVTReference = occurenceMixin.VirtualTable.GetBaseDeclaration(firstOccurence);
705 if (vtReference.Slot != listVTReference.Slot || vtReference.Shader != listVTReference.Shader)
709 for (
int j = stageMethodList.Count - 1; j > 0; --j)
711 var decl = stageMethodList[j];
713 return stageMethodList[j - 1];
736 var mixin = methodCall.GetTag(ParadoxTags.CurrentShader) as ModuleMixin;
737 var vtReference = mixin.VirtualTable.GetBaseDeclaration(methodCall.Target.TypeInference.Declaration as
MethodDeclaration);
738 foreach (var stageMethodList
in StageMethodInheritance)
740 if (stageMethodList == null || stageMethodList.Count == 0)
743 var firstOccurence = stageMethodList.First();
744 var occurenceMixin = firstOccurence.GetTag(ParadoxTags.ShaderScope) as ModuleMixin;
745 var listVTReference = occurenceMixin.VirtualTable.GetBaseDeclaration(firstOccurence);
747 if (vtReference.Slot != listVTReference.Slot || vtReference.Shader != listVTReference.Shader)
750 return stageMethodList.Last();
759 private void PatchAllMethodInferences(ModuleMixin mixin)
761 mixin.InheritanceList.ForEach(PatchAllMethodInferences);
762 CompositionsPerVariable.Where(x => mixin.LocalVirtualTable.Variables.Any(
y => y.Variable == x.Key)).ToList().ForEach(externMixes => externMixes.Value.ForEach(PatchAllMethodInferences));
764 var topMixin = GetTopMixin(mixin);
766 foreach (var baseCall
in mixin.ParsingInfo.BaseMethodCalls)
770 decl = GetBaseStageMethod(baseCall);
772 decl = topMixin.GetBaseMethodFromExpression(baseCall.Target, mixin);
776 RemoveFromMethodsReferences(baseCall, topMixin);
778 baseCall.TypeInference.TargetType = decl.ReturnType;
779 baseCall.Target.TypeInference.Declaration = decl;
781 AddToMethodsReferences(baseCall);
784 log.Error(ParadoxMessageCode.ErrorImpossibleBaseCall, baseCall.Span, baseCall, mixin.MixinName);
788 foreach (var thisCall
in mixin.ParsingInfo.ThisMethodCalls)
791 if ((thisCall.Target.TypeInference.Declaration as
MethodDeclaration).Qualifiers.Contains(ParadoxStorageQualifier.Stage))
792 decl = GetThisStageMethod(thisCall);
794 decl = FindStaticMethod(thisCall);
796 decl = topMixin.GetMethodFromExpression(thisCall.Target);
800 RemoveFromMethodsReferences(thisCall, topMixin);
802 thisCall.TypeInference.TargetType = decl.ReturnType;
803 thisCall.Target.TypeInference.Declaration = decl;
806 AddToMethodsReferences(thisCall);
809 log.Error(ParadoxMessageCode.ErrorImpossibleVirtualCall, thisCall.Span, thisCall, mixin.MixinName, mainModuleMixin.MixinName);
817 private void InferStageVariables(ModuleMixin externMix)
819 var stageDict = externMix.ClassReferences.VariablesReferences.Where(x => x.Key.Qualifiers.Contains(ParadoxStorageQualifier.Stage)).ToDictionary(x => x.Key, x => x.Value);
820 foreach (var variable
in stageDict)
822 var shaderName = (variable.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinName;
823 var foundDeclaration = mainModuleMixin.ClassReferences.VariablesReferences.FirstOrDefault(x => x.Key.Name.Text == variable.Key.Name.Text && (x.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinName == shaderName).Key;
824 if (foundDeclaration == null)
826 var semantic = variable.Key.Qualifiers.Values.OfType<
Semantic>().FirstOrDefault();
827 if (semantic != null)
829 foundDeclaration = mainModuleMixin.ClassReferences.VariablesReferences.FirstOrDefault(
832 var varSemantic = x.Key.Qualifiers.Values.OfType<Semantic>().FirstOrDefault();
833 if (varSemantic != null && semantic.Name.Text == varSemantic.Name.Text)
840 if (foundDeclaration != null)
842 mainModuleMixin.ClassReferences.VariablesReferences[foundDeclaration].UnionWith(variable.Value);
843 foreach (var varRef
in variable.Value)
845 varRef.Expression.TypeInference.Declaration = foundDeclaration;
846 varRef.Expression.TypeInference.TargetType = foundDeclaration.Type;
851 log.Error(ParadoxMessageCode.ErrorMissingStageVariable, variable.Key.Span, variable, externMix.MixinName);
856 foreach (var key
in stageDict.Keys)
857 externMix.ClassReferences.VariablesReferences.Remove(key);
864 private void ProcessExternReferences(ModuleMixin mixin)
866 mixin.InheritanceList.ForEach(ProcessExternReferences);
867 CompositionsPerVariable.Where(x => mixin.LocalVirtualTable.Variables.Any(
y => y.Variable == x.Key)).ToList().ForEach(externMixes => externMixes.Value.ForEach(ProcessExternReferences));
869 foreach (var externReferences
in mixin.ExternReferences.VariablesReferences)
871 foreach (var expression
in externReferences.Value)
873 var searchMixin = mixin;
874 var foundDefinition = FindVariable(expression.Expression, ref searchMixin);
875 if (foundDefinition != null)
881 mixin.ClassReferences.VariablesReferences.FirstOrDefault(
882 x => x.Key.Name.Text == foundDefinition.Name.Text && (x.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinName == (foundDefinition.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinName).Key;
885 mixin.ClassReferences.VariablesReferences.Add(foundDefinition,
new HashSet<ExpressionNodeCouple>());
886 sameVar = foundDefinition;
888 mixin.ClassReferences.VariablesReferences[sameVar].Add(expression);
889 expression.Expression.TypeInference.Declaration = sameVar;
890 expression.Expression.TypeInference.TargetType = sameVar.Type.ResolveType();
894 if (!mixin.ClassReferences.VariablesReferences.ContainsKey(foundDefinition))
895 mixin.ClassReferences.VariablesReferences.Add(foundDefinition,
new HashSet<ExpressionNodeCouple>());
896 mixin.ClassReferences.VariablesReferences[foundDefinition].Add(expression);
897 expression.Expression.TypeInference.Declaration = foundDefinition;
898 expression.Expression.TypeInference.TargetType = foundDefinition.Type.ResolveType();
902 log.Error(ParadoxMessageCode.ErrorExternReferenceNotFound, expression.Expression.Span, expression, mixin.MixinName);
905 mixin.ExternReferences.VariablesReferences.Clear();
907 foreach (var externReferences
in mixin.ExternReferences.MethodsReferences)
909 foreach (var methodInvoc
in externReferences.Value)
911 var searchMixin = mixin;
912 var foundDefinition = FindMethod(methodInvoc.Target, ref searchMixin);
913 if (foundDefinition != null)
915 if (!mixin.ClassReferences.MethodsReferences.ContainsKey(foundDefinition))
916 mixin.ClassReferences.MethodsReferences.Add(foundDefinition,
new HashSet<MethodInvocationExpression>());
917 mixin.ClassReferences.MethodsReferences[foundDefinition].Add(methodInvoc);
918 methodInvoc.Target.TypeInference.Declaration = foundDefinition;
921 log.Error(ParadoxMessageCode.ErrorExternReferenceNotFound, methodInvoc.Span, methodInvoc, mixin.MixinName);
924 mixin.ExternReferences.MethodsReferences.Clear();
931 private void ProcessStageInitReferences(ModuleMixin moduleMixin)
933 foreach (var variable
in moduleMixin.StageInitReferences.VariablesReferences)
936 var mixin = MixinInheritance.FirstOrDefault(x => x.MixinName == varMixinName);
939 log.Error(ParadoxMessageCode.ErrorStageMixinNotFound,
new SourceSpan(), varMixinName, moduleMixin.MixinName);
943 var trueVar = mixin.ClassReferences.VariablesReferences.FirstOrDefault(x => x.Key.Name.Text == variable.Key.Name.Text).Key;
947 log.Error(ParadoxMessageCode.ErrorStageMixinVariableNotFound,
new SourceSpan(), varMixinName, sourceShader, moduleMixin.MixinName);
951 foreach (var varRef
in variable.Value)
953 varRef.Expression.TypeInference.Declaration = trueVar;
954 varRef.Expression.TypeInference.TargetType = trueVar.Type.ResolveType();
957 mainModuleMixin.ClassReferences.VariablesReferences[trueVar].UnionWith(variable.Value);
959 foreach (var method
in moduleMixin.StageInitReferences.MethodsReferences)
962 var mixin = MixinInheritance.FirstOrDefault(x => x.MixinName == varMixinName);
965 log.Error(ParadoxMessageCode.ErrorStageMixinNotFound,
new SourceSpan(), varMixinName, moduleMixin.MixinName);
969 var trueVar = GetTopMixin(mixin).GetMethodFromDeclaration(method.Key);
972 log.Error(ParadoxMessageCode.ErrorStageMixinMethodNotFound,
new SourceSpan(), varMixinName, method, moduleMixin.MixinName);
976 foreach (var varRef
in method.Value)
978 varRef.Target.TypeInference.Declaration = trueVar;
979 varRef.Target.SetTag(ParadoxTags.VirtualTableReference, trueVar.GetTag(ParadoxTags.VirtualTableReference));
982 mainModuleMixin.ClassReferences.MethodsReferences[trueVar].UnionWith(method.Value);
989 private void ProcessExterns()
991 ProcessExternReferences(mainModuleMixin);
993 AddStageVariables(mainModuleMixin);
994 foreach (var externMix
in CompositionsPerVariable.SelectMany(externMixes => externMixes.Value))
995 InferStageVariables(externMix);
997 ProcessStageInitReferences(mainModuleMixin);
998 CompositionsPerVariable.SelectMany(externMixes => externMixes.Value).ToList().ForEach(ProcessStageInitReferences);
1000 foreach (var externMix
in CompositionsPerVariable.SelectMany(externMixes => externMixes.Value))
1002 foreach (var variable
in externMix.StaticReferences.VariablesReferences)
1004 var varMixinName = (variable.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinName;
1005 var staticVars = mainModuleMixin.StaticReferences.VariablesReferences.Where(x => (x.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinName == varMixinName && x.Key.Name.Text == variable.Key.Name.Text).ToDictionary(x => x.Key, x => x.Value);
1008 if (staticVars.Count > 0)
1010 var staticVar = staticVars.FirstOrDefault();
1011 foreach (var varRef
in variable.Value)
1013 varRef.Expression.TypeInference.Declaration = staticVar.Key;
1014 varRef.Expression.TypeInference.TargetType = staticVar.Key.Type.ResolveType();
1016 staticVar.Value.UnionWith(variable.Value);
1019 mainModuleMixin.StaticReferences.VariablesReferences.Add(variable.Key, variable.Value);
1021 foreach (var method
in externMix.StaticReferences.MethodsReferences)
1023 var methodMixinName = (method.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinName;
1024 var staticMethods = mainModuleMixin.StaticReferences.MethodsReferences.Where(x => (x.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinName == methodMixinName && x.Key.IsSameSignature(method.Key)).ToDictionary(x => x.Key, x => x.Value);
1027 if (staticMethods.Count > 0)
1029 var staticMethod = staticMethods.FirstOrDefault();
1030 foreach (var methodRef
in method.Value)
1031 methodRef.Target.TypeInference.Declaration = staticMethod.Key;
1033 staticMethod.Value.UnionWith(method.Value);
1036 mainModuleMixin.StaticReferences.MethodsReferences.Add(method.Key, method.Value);
1044 private void RenameAllVariables()
1047 RenameAllVariables(mainModuleMixin.ClassReferences, ref
id);
1055 private void RenameAllVariables(ReferencesPool references, ref
int id)
1057 foreach (var variable
in references.VariablesReferences)
1059 if (variable.Key.Name.Text == FlipRendertargetVariableName)
1062 foreach (var varRef
in variable.Value)
1068 (varRef.Expression as MemberReferenceExpression).Member = variable.Key.Name;
1070 var type = (varRef.Expression as MemberReferenceExpression).Target.TypeInference.TargetType;
1076 (varRef.Expression as MemberReferenceExpression).Member = variable.Key.Name;
1081 vre.TypeInference.Declaration = variable.Key;
1082 vre.TypeInference.TargetType = variable.Key.Type.ResolveType();
1083 ReplaceMemberReferenceExpressionByVariableReferenceExpression(varRef.Expression as MemberReferenceExpression, vre, varRef.Node);
1084 varRef.Expression = vre;
1091 variable.Key.Name.Text +=
"_id" + id;
1101 private void RenameAllMethods(ReferencesPool references, HashSet<MethodDefinition> renameFreeMethods, ref
int id)
1103 foreach (var method
in references.MethodsReferences)
1105 if (renameFreeMethods.Contains(method.Key) || !(method.Key is
MethodDefinition))
1108 foreach (var methodRef
in method.Value)
1111 if (targetMre != null)
1114 methodRef.Target = vre;
1115 vre.TypeInference.Declaration = targetMre.TypeInference.Declaration;
1116 vre.TypeInference.TargetType = targetMre.TypeInference.TargetType;
1120 targetVre.Name = method.Key.Name;
1123 method.Key.Name.Text +=
"_id" + id;
1126 references.RegenKeys();
1132 private void RenameAllMethods()
1135 var vertexShaderMethod = FindEntryPoint(
"VSMain");
1136 var hullShaderMethod = FindEntryPoint(
"HSMain");
1137 var hullConstantShaderMethod = FindEntryPoint(
"HSConstantMain");
1138 var domainShaderMethod = FindEntryPoint(
"DSMain");
1139 var geometryShaderMethod = FindEntryPoint(
"GSMain");
1140 var pixelShaderMethod = FindEntryPoint(
"PSMain");
1141 var computeShaderMethod = FindEntryPoint(
"CSMain");
1143 if (pixelShaderMethod != null && pixelShaderMethod.Body.Count == 0)
1144 pixelShaderMethod = null;
1146 var renameFreeMethods =
new HashSet<MethodDefinition>();
1149 if (vertexShaderMethod != null)
1150 renameFreeMethods.Add(vertexShaderMethod);
1151 if (hullShaderMethod != null)
1152 renameFreeMethods.Add(hullShaderMethod);
1153 if (hullConstantShaderMethod != null)
1154 renameFreeMethods.Add(hullConstantShaderMethod);
1155 if (domainShaderMethod != null)
1156 renameFreeMethods.Add(domainShaderMethod);
1157 if (geometryShaderMethod != null)
1158 renameFreeMethods.Add(geometryShaderMethod);
1159 if (pixelShaderMethod != null)
1160 renameFreeMethods.Add(pixelShaderMethod);
1161 if (computeShaderMethod != null)
1162 renameFreeMethods.Add(computeShaderMethod);
1166 RenameAllMethods(mainModuleMixin.ClassReferences, renameFreeMethods, ref
id);
1176 for (
int i = MixinInheritance.Count - 1; i >= 0; --i)
1178 var mixin = MixinInheritance[i];
1180 for (
int j = 0; j < i; ++j)
1182 count += mixin.MixinName == MixinInheritance[j].MixinName ? 1 : 0;
1185 var method = mixin.LocalVirtualTable.Methods.FirstOrDefault(x => x.Method.Name.Text == name && x.Method is
MethodDefinition);
1195 private void GenerateShader()
1200 foreach (var mixin
in MixinInheritance.Where(x => x.OccurenceId == 1))
1201 MixedShader.Members.AddRange(mixin.ParsingInfo.Typedefs);
1202 foreach (var mixin
in MixinInheritance.Where(x => x.OccurenceId == 1))
1203 MixedShader.Members.AddRange(mixin.ParsingInfo.StructureDefinitions);
1206 GroupByConstantBuffer();
1209 MixedShader.Members.AddRange(mainModuleMixin.ClassReferences.MethodsReferences.Select(x => x.Key).Where(x => x is
MethodDefinition));
1212 MixedShader.Members = MixedShader.Members.Distinct().ToList();
1215 ParadoxStreamCreator.Run(MixedShader, mainModuleMixin, MixinInheritance, log);
1221 ExpandForEachStatements(mainModuleMixin);
1222 foreach (var externMix
in CompositionsPerVariable.SelectMany(x => x.Value))
1223 ExpandForEachStatements(externMix);
1226 RemoveUselessVariables();
1232 private void RemoveUselessVariables()
1234 var variablesUsages = MixedShader.Members.OfType<
Variable>().ToDictionary(variable => variable, variable =>
false);
1236 foreach (var constantBuffer
in MixedShader.Members.OfType<
ConstantBuffer>())
1238 foreach (var variable
in constantBuffer.Members.OfType<
Variable>().ToList())
1239 variablesUsages.Add(variable,
false);
1244 var variableUsageVisitor =
new ParadoxVariableUsageVisitor(variablesUsages);
1245 variableUsageVisitor.Run(MixedShader);
1247 foreach (var variable
in MixedShader.Members.OfType<
Variable>().ToList())
1250 if (variablesUsages.TryGetValue(variable, out used))
1252 if (!used && variable.Name.Text != FlipRendertargetVariableName)
1253 MixedShader.Members.Remove(variable);
1257 foreach (var constantBuffer
in MixedShader.Members.OfType<
ConstantBuffer>())
1259 foreach (var variable
in constantBuffer.Members.OfType<
Variable>().ToList())
1262 if (variablesUsages.TryGetValue(variable, out used))
1264 if (!used && variable.Name.Text != FlipRendertargetVariableName)
1265 constantBuffer.Members.Remove(variable);
1276 private bool IsOutOfCBufferVariable(
Variable variable)
1286 private bool KeepVariableInCBuffer(
Variable variable)
1288 return !(variable.Qualifiers.Contains(ParadoxStorageQualifier.Extern) || variable.
Qualifiers.
Contains(
ParadoxStorageQualifier.
Stream) || variable.Qualifiers.Contains(ParadoxStorageQualifier.PatchStream) || IsOutOfCBufferVariable(variable));
1292 private void GroupByConstantBuffer()
1294 MergeSameSemanticVariables(mainModuleMixin.ClassReferences.VariablesReferences.Select(x => x.Key).ToList());
1295 MergeReferenceVariables(mainModuleMixin.ClassReferences.VariablesReferences.Select(x => x.Key).ToList());
1296 var usefulVars = mainModuleMixin.ClassReferences.VariablesReferences.Select(x => x.Key).Where(KeepVariableInCBuffer);
1300 foreach (var group
in groupedVarList)
1303 var cbuffer =
new ConstantBuffer { Type = SiliconStudio.Shaders.Ast.Hlsl.ConstantBufferType.Constant, Name = cbufferName };
1304 cbuffer.Members.AddRange(group);
1306 MixedShader.Members.Add(cbuffer);
1310 var globalBuffer =
new ConstantBuffer { Type = SiliconStudio.Shaders.Ast.Hlsl.ConstantBufferType.Constant, Name =
"Globals" };
1311 if (remainingVars.Count > 0)
1313 globalBuffer.Members.AddRange(remainingVars);
1314 MixedShader.Members.Add(globalBuffer);
1317 MixedShader.Members.AddRange(mainModuleMixin.ClassReferences.VariablesReferences.Select(x => x.Key).Where(IsOutOfCBufferVariable));
1324 private void MergeSameSemanticVariables(List<Variable> variables)
1326 var duplicateVariables =
new List<Variable>();
1327 var allVariablesWithSemantic = variables.Where(x => x.Qualifiers.Values.Any(
y => y is
Semantic)).ToList();
1328 foreach (var variable
in allVariablesWithSemantic)
1330 if (!duplicateVariables.Contains(variable))
1332 var semantic = variable.Qualifiers.OfType<
Semantic>().First();
1334 var sameSemanticVariables = allVariablesWithSemantic.Where(x => x != variable && x.Qualifiers.Values.OfType<Semantic>().Any(
y => AreSameSemantics(
y.Name.Text, semantic.Name.Text))).ToList();
1336 foreach (var sameSemVar
in sameSemanticVariables)
1340 if (cbufferName != null ^ newcbufferName != null)
1342 else if (cbufferName != null && cbufferName != newcbufferName)
1344 var sourceMixinName = (variable.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinName;
1345 var newMixinName = (sameSemVar.GetTag(ParadoxTags.ShaderScope) as ModuleMixin).MixinName;
1346 log.Error(ParadoxMessageCode.ErrorSemanticCbufferConflict, variable.Span, variable, sourceMixinName, sameSemVar, newMixinName, semantic, cbufferName, newcbufferName);
1349 foreach (var exp
in mainModuleMixin.ClassReferences.VariablesReferences[sameSemVar])
1352 (exp.Expression as VariableReferenceExpression).Name = variable.Name;
1354 (exp.Expression as MemberReferenceExpression).Member = variable.Name;
1356 exp.Expression.TypeInference.Declaration = variable;
1358 mainModuleMixin.ClassReferences.VariablesReferences[variable].UnionWith(mainModuleMixin.ClassReferences.VariablesReferences[sameSemVar]);
1359 sameSemVar.Name = variable.Name;
1362 duplicateVariables.AddRange(sameSemanticVariables);
1366 mainModuleMixin.ClassReferences.RegenKeys();
1367 duplicateVariables.ForEach(variable => mainModuleMixin.ClassReferences.VariablesReferences.Remove(variable));
1374 private void MergeReferenceVariables(List<Variable> variables)
1376 var duplicateVariables =
new List<Variable>();
1380 var target = variable.InitialValue.TypeInference.Declaration as
Variable;
1383 foreach (var exp
in mainModuleMixin.ClassReferences.VariablesReferences[variable])
1385 if (exp.Expression is VariableReferenceExpression)
1386 (exp.Expression as VariableReferenceExpression).Name = target.
Name;
1388 (exp.Expression as MemberReferenceExpression).Member = target.Name;
1390 exp.Expression.TypeInference.Declaration = target;
1392 mainModuleMixin.ClassReferences.VariablesReferences[target].UnionWith(mainModuleMixin.ClassReferences.VariablesReferences[variable]);
1393 variable.Name = target.Name;
1394 duplicateVariables.Add(variable);
1398 mainModuleMixin.ClassReferences.RegenKeys();
1399 duplicateVariables.ForEach(variable => mainModuleMixin.ClassReferences.VariablesReferences.Remove(variable));
1404 #region Static helpers
1410 private static void ExpandForEachStatements(ModuleMixin mixin)
1414 var newStatement = ExpandForEachStatement(statementNodeCouple.Statement as ForEachStatement);
1415 if (newStatement != null)
1417 var replace =
new ParadoxReplaceVisitor(statementNodeCouple.Statement, newStatement);
1418 replace.Run(statementNodeCouple.Node);
1422 mixin.InheritanceList.ForEach(ExpandForEachStatements);
1432 if (forEachStatement != null)
1434 var collec = forEachStatement.Collection.TypeInference.Declaration as
Variable;
1438 if ((collec.Type as ArrayType).Dimensions.Count == 1)
1453 var variable = forEachStatement.Variable;
1458 body.Statements.AddRange((forEachStatement.Body as BlockStatement).Statements);
1460 body.Statements.Add(forEachStatement.Body);
1462 forStatement.Body = body;
1464 return forStatement;
1482 var replacor =
new ParadoxReplaceVisitor(memberReferenceExpression, variableReferenceExpression);
1483 replacor.Run(parentNode);
1492 private static bool AreSameSemantics(
string sem0,
string sem1)
1494 var upperSem0 = sem0.ToUpperInvariant();
1495 var upperSem1 = sem1.ToUpperInvariant();
1497 if (upperSem0 == upperSem1)
1500 var i = upperSem0.Length - 1;
1501 while (i > 0 &&
char.IsDigit(upperSem0[i]))
1503 string trimSem0 = upperSem0.Substring(0, i + 1);
1504 int sem0Index = i == upperSem0.Length - 1 ? 0 : Int32.Parse(upperSem0.Substring(i + 1, upperSem0.Length - i - 1));
1506 i = upperSem1.Length - 1;
1507 while (i > 0 &&
char.IsDigit(upperSem1[i]))
1509 string trimSem1 = upperSem1.Substring(0, i + 1);
1510 int sem1Index = i == upperSem1.Length - 1 ? 0 : Int32.Parse(upperSem1.Substring(i + 1, upperSem1.Length - i - 1));
1512 return trimSem0 == trimSem1 && sem0Index == sem1Index;
SiliconStudio.Shaders.Ast.Hlsl.ConstantBuffer ConstantBuffer
TypeBase TargetType
Gets or sets the type.
Identifier Name
Gets or sets the name.
static readonly SiliconStudio.Shaders.Ast.StorageQualifier Abstract
Override keyword (override).
Describes a binary expression.
static readonly ScalarType Int
Scalar int.
UnaryOperator
Unary operator used in all binary expressions (except assignment expression).
TypeInference TypeInference
Gets or sets the resolved reference.
static readonly SiliconStudio.Shaders.Ast.StorageQualifier Stream
Stream keyword (stream).
string Text
Gets or sets the name.
static readonly SiliconStudio.Shaders.Ast.StorageQualifier PatchStream
Patch stream keyword (patchstream).
Qualifier Qualifiers
Gets or sets the qualifiers.
static readonly ParadoxType Input2
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Expression Collection
Gets or sets the condition.
BinaryOperator
Binary operator used in all binary expressions (except assignment expression).
A class to collect parsing/expression messages.
static readonly StorageQualifier Const
Const qualifier.
A method definition with a body of statements.
A declaration inside a statement.
bool HasErrors
Gets or sets a value indicating whether this instance has errors.
static readonly ParadoxType Input
object Value
Gets or sets the value.
Variable Variable
Gets or sets the initializer.
A member reference in the form {this}.{Name}
SiliconStudio.Shaders.Ast.StorageQualifier StorageQualifier
Statement Body
Gets or sets the condition.
static readonly SiliconStudio.Shaders.Ast.StorageQualifier Stage
Stage keyword (stage).
SiliconStudio.Shaders.Ast.SourceSpan SourceSpan
static readonly ParadoxType Output
Provides a dictionary of cloned values, where the [key] is the original object and [value] the new ob...
Declaration of a constant buffer.
Toplevel container of a shader parsing result.
bool Contains(CompositeEnum enumValue)
Determines whether [contains] [the specified enum value].
A reference to a variable.
static readonly Ast.StorageQualifier Extern
Extern modifier.
static readonly SiliconStudio.Shaders.Ast.StorageQualifier Clone
Clone keyword (clone).