3 #if PARADOX_EFFECT_COMPILER
5 using System.Collections.Generic;
8 using System.Text.RegularExpressions;
10 using SiliconStudio.Core.Extensions;
11 using SiliconStudio.Core.Storage;
12 using SiliconStudio.Paradox.Shaders.Parser.Ast;
13 using SiliconStudio.Paradox.Shaders.Parser.Grammar;
14 using SiliconStudio.Paradox.Shaders.Parser.Utility;
15 using SiliconStudio.Shaders;
16 using SiliconStudio.Shaders.Ast;
17 using SiliconStudio.Shaders.Ast.Hlsl;
18 using SiliconStudio.Shaders.Parser;
19 using SiliconStudio.Shaders.Utility;
21 namespace SiliconStudio.
Paradox.Shaders.Parser.Mixins
26 public class ShaderLoader
28 private readonly Dictionary<ShaderSourceKey, ShaderClassType> loadedShaders =
new Dictionary<ShaderSourceKey, ShaderClassType>();
34 public ShaderSourceManager SourceManager {
get;
private set; }
36 private readonly
static Regex MatchHeader =
new Regex(
@"\{.*}\s*;", RegexOptions.Singleline | RegexOptions.Compiled);
43 public ShaderLoader(ShaderSourceManager sourceManager)
45 if (sourceManager == null)
46 throw new ArgumentNullException(
"sourceManager");
48 SourceManager = sourceManager;
55 public void DeleteObsoleteCache(HashSet<string> modifiedShaders)
57 var keysToRemove =
new HashSet<ShaderSourceKey>();
58 foreach (var shaderName
in modifiedShaders)
60 foreach (var key
in loadedShaders.Keys)
62 if (key.TypeName == shaderName)
63 keysToRemove.Add(key);
67 foreach (var key
in keysToRemove)
68 loadedShaders.Remove(key);
72 SourceManager.DeleteObsoleteCache(modifiedShaders);
84 public ShaderClassType LoadClassSource(ShaderClassSource shaderClassSource, SiliconStudio.Shaders.Parser.ShaderMacro[] shaderMacros,
LoggerResult log, HashSet<string> modifiedShaders = null)
86 if (shaderClassSource == null)
throw new ArgumentNullException(
"shaderClassSource");
88 string generics = null;
89 if (shaderClassSource.GenericArguments != null)
92 foreach (var gen
in shaderClassSource.GenericArguments)
93 generics +=
"___" + gen.ToString();
95 var shaderClassType = LoadShaderClass(shaderClassSource.ClassName, generics, log, shaderMacros, modifiedShaders);
97 if (shaderClassType == null)
101 if (shaderClassSource.GenericArguments != null)
103 if (shaderClassType.IsInstanciated)
104 return shaderClassType;
106 if (shaderClassSource.GenericArguments.Length != shaderClassType.ShaderGenerics.Count)
108 log.Error(ParadoxMessageCode.WrongGenericNumber, shaderClassType.Span, shaderClassSource.ClassName);
113 foreach (var
generic in shaderClassType.ShaderGenerics)
115 foreach (var genericCompare
in shaderClassType.ShaderGenerics.Where(x => x !=
generic))
117 if (
generic.Name.Text == genericCompare.Name.Text)
118 log.Error(ParadoxMessageCode.SameNameGenerics, generic.Span,
generic, genericCompare, shaderClassSource.ClassName);
125 var className = GenerateGenericClassName(shaderClassSource);
126 shaderClassType.Name =
new Identifier(className);
127 var genericAssociation = CreateGenericAssociation(shaderClassType.ShaderGenerics, shaderClassSource.GenericArguments);
128 var identifierGenerics = GenerateIdentifierFromGenerics(genericAssociation);
129 var expressionGenerics = GenerateGenericsExpressionValues(shaderClassType.ShaderGenerics, shaderClassSource.GenericArguments);
130 ParadoxClassInstanciator.Instanciate(shaderClassType, expressionGenerics, identifierGenerics, log);
131 shaderClassType.ShaderGenerics.Clear();
132 shaderClassType.IsInstanciated =
true;
134 return shaderClassType;
137 Dictionary<string, object> CreateGenericAssociation(List<Variable> genericParameters,
object[] genericArguments)
139 var result =
new Dictionary<string, object>();
140 for (var i = 0; i < genericParameters.Count; ++i)
142 result.Add(genericParameters[i].Name.Text, genericArguments[i]);
147 Dictionary<string, Identifier> GenerateIdentifierFromGenerics(Dictionary<string, object> generics)
149 var result =
new Dictionary<string, Identifier>();
150 foreach (var genericPair
in generics)
152 var
generic = genericPair.Value;
153 if (
generic is Identifier)
154 result.Add(genericPair.Key, (Identifier)
generic);
157 var stringGeneric = generic.ToString();
158 var stringParts = stringGeneric.Split(
'.');
159 if (stringParts.Length == 1)
160 result.Add(genericPair.Key,
new Identifier(stringGeneric));
163 var dotIdentifier =
new IdentifierDot();
164 dotIdentifier.Identifiers = stringParts.Select(x =>
new Identifier(x)).ToList();
165 result.Add(genericPair.Key, dotIdentifier);
174 private Dictionary<string, Expression> GenerateGenericsExpressionValues(List<Variable> genericParameters,
object[] genericArguments)
176 var result =
new Dictionary<string, Expression>();
178 if (genericArguments.Length > 0)
180 string allGenerics =
"";
181 foreach (var
generic in genericArguments)
182 allGenerics +=
"," + generic.ToString();
183 allGenerics = allGenerics.Substring(1);
185 var node = CreateExpressionFromString(allGenerics);
187 if (node is ExpressionList)
189 var nodeList = (ExpressionList)node;
190 if (nodeList.Count != genericArguments.Length)
191 throw new Exception(
"mismatch generic length after parsing");
193 for (var i = 0; i < genericArguments.Length; ++i)
194 result.Add(genericParameters[i].Name.Text, nodeList[i]);
198 if (genericArguments.Length != 1)
199 throw new Exception(
"mismatch generic length after parsing");
200 result.Add(genericParameters[0].Name.Text, node);
206 Expression CreateExpressionFromString(
string name)
209 var result = ShaderParser.GetParser<ParadoxGrammar>(ShaderParser.GetGrammar<ParadoxGrammar>().ExpressionNonTerminal).Parser.Parse(name,
"");
210 return (Expression)result.Root.AstNode;
213 private ShaderClassType LoadShaderClass(
string type,
string generics,
LoggerResult log, SiliconStudio.Shaders.Parser.ShaderMacro[] macros = null, HashSet<string> modifiedShaders = null)
215 if (type == null)
throw new ArgumentNullException(
"type");
217 var shaderSourceKey =
new ShaderSourceKey(type, generics, macros);
222 ShaderClassType shaderClass;
224 if (loadedShaders.TryGetValue(shaderSourceKey, out shaderClass))
230 var shaderSource = SourceManager.LoadShaderSource(type, modifiedShaders);
233 var preprocessedSource = PreProcessor.Run(shaderSource.Source, shaderSource.Path, macros);
235 byte[] byteArray = Encoding.ASCII.GetBytes(preprocessedSource);
236 var hashPreprocessSource = ObjectId.FromBytes(byteArray);
239 var parsingResult = ParadoxShaderParser.TryParse(preprocessedSource, shaderSource.Path);
240 parsingResult.CopyTo(log);
242 if (parsingResult.HasErrors)
247 var shader = parsingResult.Shader;
250 var shaderClassTypes = GetShaderClassTypes(shader.Declarations).ToList();
251 if (shaderClassTypes.Count != 1)
253 throw new InvalidOperationException(
string.Format(
"Shader [{0}] must contain only a single Shader class type intead of [{1}]", type, shaderClassTypes.Count));
256 shaderClass = shaderClassTypes.First();
257 shaderClass.SourcePath = shaderSource.Path;
258 shaderClass.SourceHash = shaderSource.Hash;
259 shaderClass.PreprocessedSourceHash = hashPreprocessSource;
260 shaderClass.IsInstanciated =
false;
263 Console.WriteLine(
"Loading Shader {0}{1}", type, macros != null && macros.Length > 0 ? String.Format(
"<{0}>", string.Join(
", ", macros)) : string.
Empty);
265 if (shaderClass.Name.Text != type)
267 throw new InvalidOperationException(
string.Format(
"Unable to load shader [{0}] not maching class name [{1}]", type, shaderClass.Name.Text));
271 loadedShaders.Add(shaderSourceKey, shaderClass);
277 public ShaderClassType ParseSource(
string shaderSource,
LoggerResult log)
279 var parsingResult = ParadoxShaderParser.TryParse(shaderSource, null);
280 parsingResult.CopyTo(log);
282 if (parsingResult.HasErrors)
287 var shader = parsingResult.Shader;
288 var shaderClass = shader.Declarations.OfType<ShaderClassType>().
Single();
289 shaderClass.SourcePath = null;
290 shaderClass.SourceHash = ObjectId.Empty;
291 shaderClass.PreprocessedSourceHash = ObjectId.Empty;
292 shaderClass.IsInstanciated =
false;
297 public bool ClassExists(
string className)
299 return SourceManager.IsClassExists(className);
302 private static Dictionary<string, string> GenerateGenericMapping(ShaderClassType shaderClassType, IList<object> genericParameters)
304 var identifierGenericClass = shaderClassType.GenericParameters;
305 if (identifierGenericClass.Count != genericParameters.Count)
306 throw new InvalidOperationException(
"Number of parameters in this generic instantiation doesn't match.");
309 return identifierGenericClass
310 .Select((value, index) =>
new { value, index })
311 .ToDictionary(x => x.value.Name.Text, x => genericParameters[x.index].ToString());
314 private static string GenerateGenericClassName(ShaderClassType shaderClassType)
317 return shaderClassType.Name.Text + (shaderClassType.GenericParameters == null ? string.Empty :
"_" + string.Join(
"_", shaderClassType.GenericParameters.Select(x => x.ToString().
Replace(
'.',
'_'))));
320 private static string GenerateGenericClassName(ShaderClassSource source)
323 if (source.GenericArguments != null && source.GenericArguments.Length > 0)
325 var hash = source.GenericArguments[0].ToString().GetHashCode();
326 for (var i = 0; i < source.GenericArguments.Length; ++i)
328 hash = (hash * 397) ^ source.GenericArguments[i].ToString().GetHashCode();
334 return source.ClassName +
"_Min" + hash.ToString();
337 return source.ClassName +
"_" + hash.ToString();
339 return source.ClassName;
344 foreach (var node
in nodes)
346 var namespaceBlock = node as NamespaceBlock;
347 if (namespaceBlock != null)
349 foreach (var type
in GetShaderClassTypes(namespaceBlock.Body))
356 var shaderClass = node as ShaderClassType;
357 if (shaderClass != null)
359 yield
return shaderClass;
365 private class ShaderSourceKey : IEquatable<ShaderSourceKey>
367 public readonly
string TypeName;
368 private readonly
string generics;
370 private readonly
int hashCode;
372 public ShaderSourceKey(
string typeName,
string generics, SiliconStudio.Shaders.Parser.ShaderMacro[] shaderMacros)
374 this.TypeName = typeName;
375 this.generics = generics;
376 this.shaderMacros = shaderMacros;
379 hashCode = ((typeName != null ? typeName.GetHashCode() : 0) * 397) ^ (generics != null ? generics.GetHashCode() : 0);
380 hashCode = (hashCode * 397) ^ (this.shaderMacros != null ? this.shaderMacros.ComputeHash() : 0);
384 public bool Equals(ShaderSourceKey other)
386 return Equals(other.TypeName, TypeName) && Equals(other.generics, generics) && ArrayExtensions.ArraysEqual(other.shaderMacros, shaderMacros);
389 public override bool Equals(
object obj)
391 if (ReferenceEquals(null, obj))
return false;
392 if (obj.GetType() != typeof(ShaderSourceKey))
return false;
393 return Equals((ShaderSourceKey)obj);
396 public override int GetHashCode()
Gets a single texture view at the specified index in the mip hierarchy and in the array of textures T...
Macro to be used with PreProcessor.
SiliconStudio.Core.Diagnostics.LoggerResult LoggerResult