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.Parser;
13 using SiliconStudio.Shaders.Utility;
15 namespace SiliconStudio.
Paradox.Shaders.Parser.Mixins
17 internal class ShaderCompilationContext
19 #region Private static members
24 private static readonly
Object AnalysisLock =
new Object();
28 #region Public members
33 public HashSet<ModuleMixinInfo> MixinInfos =
new HashSet<ModuleMixinInfo>();
49 if (log == null)
throw new ArgumentNullException(
"log");
51 ErrorWarningLog = log;
56 #region Public methods
64 public void Preprocess(HashSet<ModuleMixinInfo> mixinInfos)
66 MixinInfos = mixinInfos;
68 BuildModuleMixins(MixinInfos);
75 public void Analyze(ModuleMixinInfo mixinInfo)
77 ModuleSemanticAnalysisPerMixin(mixinInfo);
85 public ModuleMixin GetModuleMixinFromShaderSource(ShaderSource shaderSource)
87 var found = MixinInfos.FirstOrDefault(x => x.ShaderSource.Equals(shaderSource));
88 return found == null ? null : found.Mixin;
93 #region Private methods
99 private void BuildModuleMixins(HashSet<ModuleMixinInfo> mixinInfos)
102 foreach (var mixinInfo
in mixinInfos)
103 PerformTypeAnalysis(mixinInfo);
104 foreach (var mixinInfo
in mixinInfos)
105 BuildModuleMixin(mixinInfo);
109 foreach (var mixinInfo
in mixinInfos)
110 BuildMixinDependencies(mixinInfo);
113 foreach (var mixinInfo
in mixinInfos)
114 BuildVirtualTables(mixinInfo);
122 private void BuildModuleMixin(ModuleMixinInfo mixinInfo)
126 if (mixinInfo.Mixin.ModuleMixinBuildStatus ==
AnalysisStatus.Complete)
129 if (mixinInfo.Mixin.ModuleMixinBuildStatus !=
AnalysisStatus.None)
130 throw new Exception(
"BuildModuleMixin failed for mixin " + mixinInfo.MixinName);
132 mixinInfo.Mixin.ModuleMixinBuildStatus = AnalysisStatus.InProgress;
134 var mixinAst = mixinInfo.MixinAst;
136 var moduleMixin = mixinInfo.Mixin;
137 moduleMixin.SetShaderAst(mixinAst);
138 moduleMixin.MixinGenericName = mixinInfo.MixinGenericName;
140 if (mixinAst != null && mixinInfo.Instanciated)
143 foreach (var member
in mixinAst.Members)
147 moduleMixin.LocalVirtualTable.Methods.Add(
new MethodDeclarationShaderCouple(member as MethodDeclaration, mixinAst));
148 member.SetTag(ParadoxTags.VirtualTableReference,
new VTableReference {
Shader = mixinInfo.MixinName, Slot = vtindex++ });
152 var variable = member as Variable;
153 moduleMixin.LocalVirtualTable.Variables.Add(
new VariableShaderCouple(variable, mixinAst));
156 if (initValue != null && initValue.Name.Text ==
"null")
157 variable.InitialValue = null;
161 moduleMixin.LocalVirtualTable.Typedefs.Add(member as Typedef);
163 moduleMixin.LocalVirtualTable.StructureTypes.Add(member as StructType);
165 moduleMixin.RemainingNodes.Add(member);
168 member.SetTag(ParadoxTags.ShaderScope, moduleMixin);
169 member.SetTag(ParadoxTags.BaseDeclarationMixin, mixinInfo.MixinName);
173 foreach (var method
in moduleMixin.LocalVirtualTable.Methods)
175 if (moduleMixin.LocalVirtualTable.Methods.Count(x => x.Method.IsSameSignature(method.Method)) > 1)
176 ErrorWarningLog.Error(ParadoxMessageCode.ErrorFunctionRedefined, method.Method.Span, method.Method, mixinInfo.MixinName);
178 if (moduleMixin.LocalVirtualTable.Variables.Any(x => x.Variable.Name.Text == method.Method.Name.Text))
181 foreach (var variable
in moduleMixin.LocalVirtualTable.Variables)
183 if (moduleMixin.LocalVirtualTable.Variables.Count(x => x.Variable.Name.Text == variable.Variable.Name.Text) > 1)
186 if (moduleMixin.LocalVirtualTable.Methods.Any(x => x.Method.Name.Text == variable.Variable.Name.Text))
191 moduleMixin.MinimalContext =
new HashSet<ModuleMixin>(mixinInfo.MinimalContext.Select(x => x.Mixin));
193 mixinInfo.Mixin.ModuleMixinBuildStatus = AnalysisStatus.Complete;
202 private void BuildMixinDependencies(ModuleMixinInfo mixinInfo)
204 var mixin = mixinInfo.Mixin;
210 ErrorWarningLog.Error(ParadoxMessageCode.ErrorCyclicDependency, mixin.Shader.Span, mixin.Shader);
211 mixin.DependenciesStatus = AnalysisStatus.Cyclic;
216 mixin.DependenciesStatus = AnalysisStatus.InProgress;
218 foreach (var baseClass
in mixin.Shader.BaseClasses)
221 var bcInfo = MixinInfos.FirstOrDefault(x => x.MixinName == baseClass.Name.Text && AreMacrosEqual(x.Macros, mixinInfo.Macros));
225 ErrorWarningLog.Error(ParadoxMessageCode.ErrorDependencyNotInModule, baseClass.Span, baseClass, mixin.MixinName);
226 mixin.DependenciesStatus = AnalysisStatus.Error;
230 var bc = bcInfo.Mixin;
232 BuildMixinDependencies(bcInfo);
235 mixin.DependenciesStatus = AnalysisStatus.Error;
239 foreach (var dependency
in bc.InheritanceList)
241 if (!mixin.InheritanceList.Contains(dependency))
242 mixin.InheritanceList.Add(dependency);
245 if (!mixin.InheritanceList.Contains(bc))
246 mixin.InheritanceList.Add(bc);
248 mixin.BaseMixins.Add(bc);
250 if (!bcInfo.Instanciated)
251 mixinInfo.Instanciated =
false;
255 foreach (var variable
in mixin.LocalVirtualTable.Variables)
257 var variableTypeName = variable.Variable.Type.Name.Text;
259 variableTypeName = (variable.Variable.Type as ArrayType).
Type.Name.Text;
261 var baseClassInfo = MixinInfos.FirstOrDefault(x => x.MixinName == variableTypeName);
262 if (baseClassInfo != null)
264 variable.Variable.Qualifiers |= SiliconStudio.Shaders.Ast.Hlsl.StorageQualifier.Extern;
265 if (variable.Variable.InitialValue is VariableReferenceExpression && (variable.Variable.InitialValue as VariableReferenceExpression).Name.Text ==
"stage")
266 mixin.StageInitVariableDependencies.Add(variable.Variable, baseClassInfo.Mixin);
268 mixin.VariableDependencies.Add(variable.Variable, baseClassInfo.Mixin);
270 if (variable.Variable.Type is ArrayType)
272 var typeArray = variable.Variable.Type as ArrayType;
273 typeArray.Type.TypeInference.Declaration = baseClassInfo.MixinAst;
277 variable.Variable.Type.TypeInference.Declaration = baseClassInfo.MixinAst;
282 mixin.DependenciesStatus = AnalysisStatus.Complete;
290 private void PerformTypeAnalysis(ModuleMixinInfo mixinInfo)
296 mixinInfo.Mixin.TypeAnalysisStatus = AnalysisStatus.InProgress;
299 var typeAnalyzer =
new ParadoxTypeAnalysis(
new ParsingResult());
300 typeAnalyzer.Run(mixinInfo.MixinAst);
301 mixinInfo.Mixin.TypeAnalysisStatus = AnalysisStatus.Complete;
303 else if (mixinInfo.Mixin.TypeAnalysisStatus !=
AnalysisStatus.Complete)
305 throw new Exception(
"Type analysis failed for mixin " + mixinInfo.MixinName);
314 private void BuildVirtualTables(ModuleMixinInfo mixinInfo)
316 var mixin = mixinInfo.Mixin;
321 if (!mixinInfo.Instanciated)
324 foreach (var dep
in mixin.InheritanceList)
326 var depInfo = MixinInfos.FirstOrDefault(x => x.Mixin == dep);
327 BuildVirtualTables(depInfo);
331 foreach (var dep
in mixin.InheritanceList)
332 mixin.VirtualTable.MergeWithLocalVirtualTable(dep.LocalVirtualTable, mixin.MixinName, ErrorWarningLog);
334 mixin.VirtualTable.MergeWithLocalVirtualTable(mixin.LocalVirtualTable, mixin.MixinName, ErrorWarningLog);
336 foreach (var dep
in mixin.InheritanceList)
337 mixin.VirtualTable.AddVirtualTable(dep.VirtualTable, dep.MixinName, ErrorWarningLog);
338 mixin.VirtualTable.AddFinalDeclarations(mixin.LocalVirtualTable.Methods.Select(x => x.Method).ToList(), mixin.MixinName, ErrorWarningLog);
340 foreach (var variable
in mixin.VirtualTable.Variables.Select(x => x.Variable))
342 if (mixin.VirtualTable.Variables.Any(x => x.Variable != variable && x.Variable.Name.Text == variable.Name.Text))
343 mixin.PotentialConflictingVariables.Add(variable);
345 foreach (var method
in mixin.VirtualTable.Methods.Select(x => x.Method))
347 if (mixin.VirtualTable.Methods.Any(x => x.Method != method && x.Method.IsSameSignature(method)))
348 mixin.PotentialConflictingMethods.Add(method);
351 CheckStageClass(mixin);
353 mixin.VirtualTableStatus = AnalysisStatus.Complete;
360 private void CheckStageClass(ModuleMixin mixin)
362 mixin.StageOnlyClass = mixin.VirtualTable.Variables.All(x => x.Variable.Qualifiers.Contains(ParadoxStorageQualifier.Stage)) && mixin.VirtualTable.Methods.All(x => x.Method.Qualifiers.Contains(ParadoxStorageQualifier.Stage) && !x.Method.Qualifiers.Contains(
ParadoxStorageQualifier.
Clone));
369 private void ModuleSemanticAnalysisPerMixin(ModuleMixinInfo mixinInfo)
371 if (mixinInfo == null)
374 var mixin = mixinInfo.Mixin;
383 ErrorWarningLog.Error(ParadoxMessageCode.ErrorCyclicDependency, mixin.Shader.Span, mixin.Shader);
386 if (!mixinInfo.Instanciated)
389 mixin.SemanticAnalysisStatus = AnalysisStatus.InProgress;
392 foreach (var baseClass
in mixin.BaseMixins)
394 var baseClassInfo = MixinInfos.FirstOrDefault(x => x.Mixin == baseClass);
395 ModuleSemanticAnalysisPerMixin(baseClassInfo);
397 if (baseClassInfo.Mixin.SemanticAnalysisStatus ==
AnalysisStatus.Error || baseClassInfo.Mixin.SemanticAnalysisStatus ==
AnalysisStatus.Cyclic)
399 mixin.SemanticAnalysisStatus = AnalysisStatus.Error;
403 if (!baseClassInfo.Instanciated)
405 mixinInfo.Instanciated =
false;
406 mixin.SemanticAnalysisStatus = AnalysisStatus.None;
410 if (mixin.LocalVirtualTable.CheckNameConflict(baseClass.VirtualTable, ErrorWarningLog))
412 mixin.SemanticAnalysisStatus = AnalysisStatus.Error;
418 foreach (var externMixin
in mixin.VariableDependencies)
420 var externMixinInfo = MixinInfos.FirstOrDefault(x => x.Mixin == externMixin.Value);
421 ModuleSemanticAnalysisPerMixin(externMixinInfo);
422 if (externMixinInfo.Mixin.SemanticAnalysisStatus ==
AnalysisStatus.Error || externMixinInfo.Mixin.SemanticAnalysisStatus ==
AnalysisStatus.Cyclic)
424 mixin.SemanticAnalysisStatus = AnalysisStatus.Error;
429 var compilationContext = MixinInfos.Select(x => x.Mixin).ToList();
431 mixin.ParsingInfo = ParadoxSemanticAnalysis.RunAnalysis(mixin, compilationContext);
433 var staticStageMixins =
new List<ModuleMixin>();
434 staticStageMixins.AddRange(mixin.ParsingInfo.StaticReferences.VariablesReferences.Select(x => x.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin));
435 staticStageMixins.AddRange(mixin.ParsingInfo.StaticReferences.MethodsReferences.Select(x => x.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin));
436 staticStageMixins.AddRange(mixin.ParsingInfo.StageInitReferences.VariablesReferences.Select(x => x.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin));
437 staticStageMixins.AddRange(mixin.ParsingInfo.StageInitReferences.MethodsReferences.Select(x => x.Key.GetTag(ParadoxTags.ShaderScope) as ModuleMixin));
438 staticStageMixins.RemoveAll(x => x == mixin);
440 foreach (var dep
in staticStageMixins)
442 var depInfo = MixinInfos.FirstOrDefault(x => x.Mixin == dep);
443 ModuleSemanticAnalysisPerMixin(depInfo);
446 mixin.SemanticAnalysisStatus = AnalysisStatus.Error;
452 var externList =
new List<ModuleMixin>();
456 mixin.InheritanceList.ForEach(dep => externList.AddRange(dep.VariableDependencies.Select(x => x.Value)));
457 externList.AddRange(mixin.VariableDependencies.Select(x => x.Value));
458 externList.ForEach(ext => CheckReferencesFromExternMixin(ext, mixin));
460 mixin.ParsingInfo.ErrorsWarnings.CopyTo(ErrorWarningLog);
462 mixin.SemanticAnalysisStatus = AnalysisStatus.Complete;
470 private void CheckReferencesFromExternMixin(ModuleMixin externMixin, ModuleMixin contextMixin)
473 foreach (var variable
in externMixin.ParsingInfo.StageInitializedVariables)
475 if (variable.Type.Name.Text != contextMixin.MixinName && contextMixin.InheritanceList.All(x => x.MixinName == variable.Type.Name.Text))
479 foreach (var stageCall
in externMixin.ParsingInfo.StageMethodCalls)
481 var decl = contextMixin.FindTopThisFunction(stageCall).FirstOrDefault();
483 ErrorWarningLog.Error(ParadoxMessageCode.ErrorExternStageFunctionNotFound, stageCall.Span, stageCall, externMixin.MixinName, contextMixin.MixinName);
487 foreach (var mixin
in externMixin.InheritanceList)
489 CheckReferencesFromExternMixin(mixin, contextMixin);
491 foreach (var externModule
in mixin.VariableDependencies)
492 CheckReferencesFromExternMixin(externModule.Value, contextMixin);
495 foreach (var externModule
in externMixin.VariableDependencies)
496 CheckReferencesFromExternMixin(externModule.Value, contextMixin);
501 #region Private static methods
509 private static bool AreMacrosEqual(SiliconStudio.Shaders.Parser.ShaderMacro[] macros0, SiliconStudio.Shaders.Parser.ShaderMacro[] macros1)
511 return macros0.All(macro => macros1.Any(x => x.Name == macro.Name && x.Definition == macro.Definition)) && macros1.All(macro => macros0.Any(x => x.Name == macro.Name && x.Definition == macro.Definition));
521 public int Slot = -1;
529 return Slot == vtr.Slot &&
Shader == vtr.Shader;
static readonly MessageCode ErrorVariableNameConflict
A class to collect parsing/expression messages.
The type of the serialized type will be passed as a generic arguments of the serializer. Example: serializer of A becomes instantiated as Serializer{A}.
static readonly MessageCode ErrorExternStageVariableNotFound
Toplevel container of a shader parsing result.
A reference to a variable.
static readonly MessageCode ErrorFunctionVariableNameConflict
override bool Equals(object obj)
static readonly SiliconStudio.Shaders.Ast.StorageQualifier Clone
Clone keyword (clone).
AnalysisStatus
A status needed to analyze the mixin in the correct order within a compilation module ...
override int GetHashCode()