4 using System.Collections.Generic;
 
    8 using SiliconStudio.Core.Extensions;
 
    9 using SiliconStudio.Core.Storage;
 
   10 using SiliconStudio.Paradox.Shaders.Parser.Ast;
 
   11 using SiliconStudio.Paradox.Shaders.Parser.Utility;
 
   12 using SiliconStudio.Shaders.Ast;
 
   13 using SiliconStudio.Shaders.Ast.Hlsl;
 
   14 using SiliconStudio.Shaders.Utility;
 
   16 namespace SiliconStudio.
Paradox.Shaders.Parser.Mixins
 
   18     internal class ParadoxShaderLibrary
 
   22         public delegate 
ShaderClassType LoadClassSourceDelegate(ShaderClassSource shaderClassSource, SiliconStudio.Shaders.Parser.ShaderMacro[] shaderMacros, out 
ObjectId hash, out 
ObjectId hashPreprocessSource);
 
   26         #region Public members 
   31         public HashSet<ModuleMixinInfo> MixinInfos = 
new HashSet<ModuleMixinInfo>();
 
   36         public ShaderLoader ShaderLoader { 
get; 
private set; }
 
   46         public HashSourceCollection SourceHashes = 
new HashSourceCollection();
 
   51         public HashSet<string> ModifiedShaders = 
new HashSet<string>();
 
   55         #region Private members 
   57         private int lastMixIndex = 0;
 
   62         private readonly Dictionary<string, List<ModuleMixinInfo>> mapMacrosToMixins = 
new Dictionary<string, List<ModuleMixinInfo>>();
 
   68         public ParadoxShaderLibrary(ShaderLoader loader)
 
   70             ShaderLoader = loader;
 
   75         #region Public methods 
   83         public HashSet<ModuleMixinInfo> LoadShaderSource(ShaderSource shaderSource, SiliconStudio.Shaders.Parser.ShaderMacro[] macros)
 
   85             var mixinsToAnalyze = 
new HashSet<ModuleMixinInfo>();
 
   86             ExtendLibrary(shaderSource, macros, mixinsToAnalyze);
 
   87             ReplaceMixins(mixinsToAnalyze); 
 
   88             return mixinsToAnalyze;
 
   95         public void DeleteObsoleteCache(HashSet<string> modifiedShaders)
 
   97             var mixinsToDelete = 
new HashSet<ModuleMixinInfo>();
 
   99             foreach (var shaderName 
in modifiedShaders)
 
  102                 foreach (var mixin 
in MixinInfos)
 
  104                     if (mixin.MixinName == shaderName)
 
  105                         mixinsToDelete.Add(mixin);
 
  108                         foreach (var dep 
in mixin.MinimalContext)
 
  110                             if (dep.MixinName == shaderName)
 
  111                                 mixinsToDelete.Add(mixin);
 
  117                 SourceHashes.Remove(shaderName);
 
  121             foreach (var mixin 
in mixinsToDelete)
 
  123                 MixinInfos.Remove(mixin);
 
  126                 foreach (var macroMap 
in mapMacrosToMixins)
 
  127                     macroMap.Value.Remove(mixin);
 
  130             mixinsToDelete.Clear();
 
  132             ShaderLoader.DeleteObsoleteCache(modifiedShaders);
 
  137         #region Private methods 
  144         private void ExtendLibrary(ShaderSource shaderSource, SiliconStudio.Shaders.Parser.ShaderMacro[] macros, HashSet<ModuleMixinInfo> mixinToAnalyze)
 
  146             if (shaderSource is ShaderMixinSource)
 
  148                 var newMacros = MergeMacroSets((ShaderMixinSource)shaderSource, macros);
 
  149                 mixinToAnalyze.Add(GetModuleMixinInfo(shaderSource, newMacros));
 
  150                 foreach (var composition 
in ((ShaderMixinSource)shaderSource).Compositions)
 
  151                     ExtendLibrary(composition.Value, newMacros, mixinToAnalyze);
 
  153             else if (shaderSource is ShaderClassSource)
 
  154                 mixinToAnalyze.Add(GetModuleMixinInfo(shaderSource, macros));
 
  155             else if (shaderSource is ShaderArraySource)
 
  157                 foreach (var shader 
in ((ShaderArraySource)shaderSource).Values)
 
  158                     ExtendLibrary(shader, macros, mixinToAnalyze);
 
  169         private ModuleMixinInfo GetModuleMixinInfo(ShaderSource shaderSource, SiliconStudio.Shaders.Parser.ShaderMacro[] macros, 
string macrosString = null)
 
  174             if (macrosString == null)
 
  176                 macrosString =  string.Join(
",", macros.OrderBy(x => x.Name));
 
  179             List<ModuleMixinInfo> context;
 
  180             if (!mapMacrosToMixins.TryGetValue(macrosString, out context))
 
  182                 context = 
new List<ModuleMixinInfo>();
 
  183                 mapMacrosToMixins.Add(macrosString, context);
 
  186             var mixinInfo = context.FirstOrDefault(x => x.AreEqual(shaderSource, macros));
 
  187             if (mixinInfo == null)
 
  189                 mixinInfo = BuildMixinInfo(shaderSource, macros);
 
  191                 if (mixinInfo.Instanciated)
 
  193                     MixinInfos.Add(mixinInfo);
 
  194                     mapMacrosToMixins[macrosString].Add(mixinInfo);
 
  196                     mixinInfo.MinimalContext.Add(mixinInfo);
 
  198                     if (!mixinInfo.Log.HasErrors)
 
  200                         LoadNecessaryShaders(mixinInfo, macros, macrosString);
 
  202                     mixinInfo.MinimalContext = 
new HashSet<ModuleMixinInfo>(mixinInfo.MinimalContext.Distinct());
 
  213         private void ReplaceMixins(HashSet<ModuleMixinInfo> mixinInfos)
 
  215             foreach (var mixinInfo 
in mixinInfos)
 
  216                 CheckMixinForReplacement(mixinInfo);
 
  223         private void CheckMixinForReplacement(ModuleMixinInfo mixinInfo)
 
  227             if (mixinInfo.ReplacementChecked)
 
  231             mixinInfo.MinimalContext.Where(x => x != mixinInfo).ForEach(CheckMixinForReplacement);
 
  233             foreach (var replaceCandidateMixinInfo 
in MixinInfos.Where(x => x != mixinInfo && x.ShaderSource.Equals(mixinInfo.ShaderSource) && x.HashPreprocessSource == mixinInfo.HashPreprocessSource))
 
  235                 if (replaceCandidateMixinInfo != null && replaceCandidateMixinInfo.Mixin.DependenciesStatus != 
AnalysisStatus.None)
 
  237                     if (replaceCandidateMixinInfo.Mixin.MinimalContext != null)
 
  239                         var noNeedToReplaced = replaceCandidateMixinInfo.Mixin.MinimalContext
 
  240                             .Where(dep => dep != replaceCandidateMixinInfo.Mixin)
 
  241                             .
All(dep => mixinInfo.MinimalContext.FirstOrDefault(x => x.Mixin == dep) != null);
 
  242                         if (noNeedToReplaced)
 
  244                             mixinInfo.Mixin = replaceCandidateMixinInfo.Mixin;
 
  245                             mixinInfo.MixinAst = replaceCandidateMixinInfo.MixinAst;
 
  246                             mixinInfo.MixinGenericName = replaceCandidateMixinInfo.MixinGenericName;
 
  253             mixinInfo.ReplacementChecked = 
true;
 
  262         private ModuleMixinInfo BuildMixinInfo(ShaderSource shaderSource, SiliconStudio.Shaders.Parser.ShaderMacro[] macros)
 
  264             ModuleMixinInfo mixinInfo = null;
 
  266             if (shaderSource is ShaderClassSource)
 
  268                 var shaderClassSource = shaderSource as ShaderClassSource;
 
  269                 mixinInfo = 
new ModuleMixinInfo { ShaderSource = shaderClassSource, Macros = macros };
 
  270                 LoadMixinFromClassSource(mixinInfo);
 
  272             else if (shaderSource is ShaderMixinSource)
 
  274                 var shaderMixinSource = shaderSource as ShaderMixinSource;
 
  276                 var shaderName = 
"Mix" + lastMixIndex;
 
  279                 foreach (var classSource 
in shaderMixinSource.Mixins)
 
  282                     if (classSource.GenericArguments != null && classSource.GenericArguments.Length > 0)
 
  283                         name = 
new IdentifierGeneric(classSource.ClassName, classSource.GenericArguments.Select(x => 
new Identifier(x.ToString())).ToArray());
 
  287                     fakeAst.BaseClasses.Add(
new TypeName(name));
 
  290                 mixinInfo = 
new ModuleMixinInfo
 
  292                         MixinGenericName = shaderName,
 
  295                         ShaderSource =  shaderSource,
 
  296                         SourceHash = ObjectId.FromBytes(Encoding.UTF8.GetBytes(shaderName)), 
 
  308         private void LoadMixinFromClassSource(ModuleMixinInfo mixinInfo)
 
  310             var classSource = (ShaderClassSource)mixinInfo.ShaderSource;
 
  312             var shaderClass = ShaderLoader.LoadClassSource(classSource, mixinInfo.Macros, mixinInfo.Log, ModifiedShaders);
 
  315             if (shaderClass == null)
 
  318             shaderClass = shaderClass.DeepClone();
 
  320             if (shaderClass.ShaderGenerics != null && shaderClass.ShaderGenerics.Count != 0)
 
  321                 mixinInfo.Instanciated = 
false;
 
  323             mixinInfo.HashPreprocessSource = shaderClass.PreprocessedSourceHash;
 
  324             mixinInfo.SourceHash = shaderClass.SourceHash;
 
  326             if (!SourceHashes.ContainsKey(classSource.ClassName))
 
  327                 SourceHashes.Add(classSource.ClassName, shaderClass.SourceHash);
 
  330             if (shaderClass.GenericParameters.Count > 0)
 
  332                 if (classSource.GenericArguments == null || classSource.GenericArguments.Length == 0 || shaderClass.GenericParameters.Count > classSource.GenericArguments.Length)
 
  334                     mixinInfo.Instanciated = 
false;
 
  335                     mixinInfo.Log.Error(ParadoxMessageCode.ErrorClassSourceNotInstantiated, shaderClass.Span, classSource.ClassName);
 
  339                     ModuleMixinInfo.CleanIdentifiers(shaderClass.GenericParameters.Select(x => x.Name).ToList());
 
  343             mixinInfo.MixinAst = shaderClass;
 
  344             mixinInfo.MixinGenericName = classSource.ClassName;
 
  353         private void LoadNecessaryShaders(ModuleMixinInfo mixinInfo, SiliconStudio.Shaders.Parser.ShaderMacro[] macros, 
string macrosString)
 
  355             if (!mixinInfo.Instanciated)
 
  359             var shaderDependencyVisitor = 
new ShaderDependencyVisitor(mixinInfo.Log, ShaderLoader.SourceManager);
 
  360             shaderDependencyVisitor.Run(mixinInfo.MixinAst);
 
  362             foreach (var foundClass 
in shaderDependencyVisitor.FoundClasses)
 
  364                 var classSource = 
new ShaderClassSource(foundClass, null);
 
  365                 var foundMixinInfo = GetModuleMixinInfo(classSource, macros, macrosString);
 
  366                 mixinInfo.MinimalContext.UnionWith(foundMixinInfo.MinimalContext);
 
  369             foreach (var 
id in shaderDependencyVisitor.FoundIdentifiers)
 
  371                 var genericClass = id.Item1;
 
  372                 ModuleMixinInfo.CleanIdentifiers(genericClass.Identifiers);
 
  373                 var genericParams = BuildShaderGenericParameters(genericClass);
 
  374                 var classSource = 
new ShaderClassSource(genericClass.Text, genericParams);
 
  376                 var instanciatedClassInfo = GetModuleMixinInfo(classSource, macros, macrosString);
 
  377                 mixinInfo.MinimalContext.UnionWith(instanciatedClassInfo.MinimalContext);
 
  379                 var newId = 
new Identifier(instanciatedClassInfo.MixinName);
 
  381                     (id.Item2 as TypeName).Name = newId;
 
  383                     (id.Item2 as VariableReferenceExpression).Name = newId;
 
  385                     (id.Item2 as MemberReferenceExpression).Member = newId;
 
  391         #region Private static methods 
  398         private static string[] BuildShaderGenericParameters(
IdentifierGeneric genericClass)
 
  400             var genericParameters = 
new List<string>();
 
  402             for (
int i = 0; i < genericClass.Identifiers.Count; ++i)
 
  404                 var genericName = GetIdentifierName(genericClass.
Identifiers[i]);
 
  405                 genericParameters.Add(genericName);
 
  408             return genericParameters.ToArray();
 
  416         private static string GetIdentifierName(
Identifier identifier)
 
  420                 genericName = (identifier as LiteralIdentifier).
Value.Value.ToString();
 
  423                 var idDot = identifier as IdentifierDot;
 
  424                 genericName = idDot.Identifiers.Aggregate(
"", (current, id) => current + (GetIdentifierName(
id) + idDot.Separator));
 
  425                 genericName = genericName.Substring(0, genericName.Length - idDot.Separator.Length);
 
  428                 genericName = identifier.Text;
 
  430             if (genericName == null)
 
  431                 throw new Exception(
string.Format(
"Unable to find the name of the generic [{0}]", identifier));
 
  448             foreach (var macro 
in macros)
 
  450                 newMacros.RemoveAll(x => x.Name == macro.Name);
 
  451                 newMacros.Add(macro);
 
  455             foreach (var macro 
in mixin.Macros)
 
  457                 newMacros.RemoveAll(x => x.Name == macro.Name);
 
  459                 newMacros.Add(tempMacro);
 
  462             mixin.Macros = newMacros.Select(x => 
new ShaderMacro(x.Name, x.Definition)).ToList();
 
  463             return newMacros.ToArray();
 
SiliconStudio.Paradox.Shaders.ShaderMacro ShaderMacro
 
Macro to be used with PreProcessor. 
 
Search recursively all in and out dependencies. 
 
SiliconStudio.Core.Diagnostics.LoggerResult LoggerResult
 
A class to collect parsing/expression messages. 
 
A member reference in the form {this}.{Name} 
 
A generic identifier in the form Typename 
 
A reference to a variable. 
 
A hash to uniquely identify data. 
 
List< Identifier > Identifiers
Gets or sets the path. 
 
AnalysisStatus
A status needed to analyze the mixin in the correct order within a compilation module ...