4 using System.Collections.Generic;
7 using SiliconStudio.Core;
8 using SiliconStudio.Core.Diagnostics;
9 using SiliconStudio.Core.IO;
10 using SiliconStudio.Core.Serialization;
11 using SiliconStudio.Core.Serialization.Assets;
12 using SiliconStudio.Core.Serialization.Serializers;
13 using SiliconStudio.Core.Storage;
14 using SiliconStudio.Paradox.Effects;
16 namespace SiliconStudio.
Paradox.Shaders.Compiler
21 [DataSerializerGlobal(null, typeof(KeyValuePair<HashSourceCollection, EffectBytecode>))]
24 private static readonly
Logger Log = GlobalLogger.GetLogger(
"EffectCompilerCache");
25 private readonly Dictionary<ObjectId, EffectBytecode> storedResults =
new Dictionary<ObjectId, EffectBytecode>();
26 private const string CompiledShadersKey =
"__shaders_bytecode__";
34 var database = AssetManager.FileProvider;
37 throw new NotSupportedException(
"Using the cache requires to AssetManager.FileProvider to be valid.");
41 if (recentlyModifiedShaders != null && recentlyModifiedShaders.Count != 0)
42 RemoveObsoleteStoredResults(recentlyModifiedShaders);
44 var ids = ShaderMixinObjectId.Compute(mixin, compilerParameters);
49 if (storedResults.TryGetValue(ids.FullParametersId, out bytecode))
55 var compiledUrl = string.Format(
"{0}/{1}", CompiledShadersKey, ids.CompileParametersId);
61 if (database.AssetIndexMap.TryGetValue(compiledUrl, out bytecodeId))
63 using (var stream = database.ObjectDatabase.OpenStream(bytecodeId))
65 var localBytecode = BinarySerialization.Read<
EffectBytecode>(stream);
70 bytecode = localBytecode;
73 if (modifiedShaders != null && modifiedShaders.Count != 0 && IsBytecodeObsolete(bytecode, modifiedShaders))
82 Log.Error(
"Unable to find compiled shaders [{0}] for mixin [{1}] with parameters [{2}]", compiledUrl, mixin, compilerParameters.ToStringDetailed());
83 throw new InvalidOperationException(
"Unable to find compiled shaders [{0}]".ToFormat(compiledUrl));
92 var isObjectInDatabase = database.ObjectDatabase.Exists(ids.CompileParametersId);
95 if ((modifiedShaders == null || modifiedShaders.Count == 0) && isObjectInDatabase)
97 var stream = database.ObjectDatabase.OpenStream(ids.CompileParametersId, VirtualFileMode.Open, VirtualFileAccess.Read, VirtualFileShare.Read);
98 using (var resultsStore =
new ShaderBytecodeStore(stream))
101 resultsStore.LoadNewValues();
103 var storedValues = resultsStore.GetValues();
105 foreach (KeyValuePair<HashSourceCollection, EffectBytecode> hashResults
in storedValues)
107 if (CheckBytecodeInSyncAgainstSources(hashResults.Value, database))
109 bytecode = hashResults.Value;
119 if (bytecode == null)
122 var stream = database.ObjectDatabase.OpenStream(ids.CompileParametersId, VirtualFileMode.OpenOrCreate, VirtualFileAccess.ReadWrite, VirtualFileShare.ReadWrite);
123 using (var resultsStore =
new ShaderBytecodeStore(stream))
128 bytecode = base.Compile(mixin, fullEffectName, compilerParameters, modifiedShaders, recentlyModifiedShaders, localLogger);
129 log.Info(
"New effect compiled [{0}]\r\n{1}", ids.CompileParametersId, compilerParameters.ToStringDetailed());
130 localLogger.CopyTo(log);
133 if (localLogger.HasErrors)
139 resultsStore[bytecode.HashSources] = bytecode;
144 using (var stream = database.OpenStream(compiledUrl, VirtualFileMode.Create, VirtualFileAccess.Write, VirtualFileShare.Write))
146 BinarySerialization.Write(stream, bytecode);
152 bytecode = bytecode.Clone();
156 storedResults[ids.FullParametersId] = bytecode;
162 private void RemoveObsoleteStoredResults(HashSet<string> modifiedShaders)
166 var keysToRemove =
new List<ObjectId>();
167 foreach (var bytecodePair
in storedResults)
169 if (IsBytecodeObsolete(bytecodePair.Value, modifiedShaders))
170 keysToRemove.Add(bytecodePair.Key);
173 foreach (var key
in keysToRemove)
174 storedResults.Remove(key);
178 private bool IsBytecodeObsolete(EffectBytecode bytecode, HashSet<string> modifiedShaders)
180 return bytecode.HashSources.Any(x => modifiedShaders.Contains(x.Key));
189 private static bool CheckBytecodeInSyncAgainstSources(EffectBytecode byteCode,
DatabaseFileProvider database)
191 var usedSources = byteCode.HashSources;
194 foreach (var usedSource
in usedSources)
205 private class ShaderBytecodeStore : DictionaryStore<HashSourceCollection, EffectBytecode>
207 public ShaderBytecodeStore(
Stream stream) : base(stream)
Parameters used for mixin.
Checks if an effect has already been compiled in its cache before deferring to a real IEffectCompiler...
A mixin performing a combination of ShaderClassSource and other mixins.
SiliconStudio.Core.Diagnostics.LoggerResult LoggerResult
A logger that stores messages locally useful for internal log scenarios.
EffectCompilerCache(EffectCompilerBase compiler)
Base class for implementations of IEffectCompiler, providing some helper functions.
Base implementation for ILogger.
Helper class that delegates actual compilation to another IEffectCompiler.
IAssetIndexMap AssetIndexMap
A hash to uniquely identify data.
override EffectBytecode Compile(ShaderMixinSource mixin, string fullEffectName, ShaderMixinParameters compilerParameters, HashSet< string > modifiedShaders, HashSet< string > recentlyModifiedShaders, LoggerResult log)
Compiles the ShaderMixinSource into a platform bytecode.
Contains a compiled shader with bytecode for each stage.
bool TryGetValue(string url, out ObjectId objectId)
Output message to log right away.