public static void Write(string name, CompilerParameters parameters, EffectBytecode effectData, TextWriter writer)
        {
            const string codeTemplate         = @"//------------------------------------------------------------------------------
// <auto-generated>
//     Paradox Effect Compiler File Generated:
{0}//
//     Command Line: {7}
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace {1} 
{{
    {2} class {3}
    {{
        {4} static readonly byte[] {5} = new byte[] {{
{6}
        }};
    }}
}}
";
            var          effectToGenerateText = new StringBuilder();

            effectToGenerateText.AppendFormat("//     Effect [{0}]\r\n", name);

            var buffer = new MemoryStream();

            effectData.WriteTo(buffer);

            var bufferAsText = new StringBuilder();
            var bufferArray  = buffer.ToArray();

            for (int i = 0; i < bufferArray.Length; i++)
            {
                bufferAsText.Append(bufferArray[i]).Append(", ");
                if (i > 0 && (i % 64) == 0)
                {
                    bufferAsText.AppendLine();
                }
            }

            var classDeclaration = parameters.Get(EffectSourceCodeKeys.ClassDeclaration);
            var fieldDeclaration = parameters.Get(EffectSourceCodeKeys.FieldDeclaration);
            var nameSpace        = parameters.Get(EffectSourceCodeKeys.Namespace);
            var className        = parameters.Get(EffectSourceCodeKeys.ClassName) ?? name;
            var fieldName        = parameters.Get(EffectSourceCodeKeys.FieldName);

            var commandLine = string.Join(" ", Environment.GetCommandLineArgs());

            var    graphicsPlatform = parameters.Get(CompilerParameters.GraphicsPlatformKey);
            string paradoxDefine    = "undefined";

            switch (graphicsPlatform)
            {
            case GraphicsPlatform.Direct3D11:
                paradoxDefine = "SILICONSTUDIO_PARADOX_GRAPHICS_API_DIRECT3D11";
                break;

            case GraphicsPlatform.OpenGL:
                paradoxDefine = "SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLCORE";
                break;

            case GraphicsPlatform.OpenGLES:
                paradoxDefine = "SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES";
                break;
            }

            writer.WriteLine("#if {0}", paradoxDefine);
            writer.Write(codeTemplate,
                         effectToGenerateText, // {0}
                         nameSpace,            // {1}
                         classDeclaration,     // {2}
                         className,            // {3}
                         fieldDeclaration,     // {4}
                         fieldName,            // {5}
                         bufferAsText,         // {6}
                         commandLine);         // {7}

            writer.WriteLine("#endif");

            writer.Flush();
        }
        public override EffectBytecode Compile(ShaderMixinSourceTree mixinTree, CompilerParameters compilerParameters, LoggerResult log)
        {
            var database = AssetManager.FileProvider;

            if (database == null)
            {
                throw new NotSupportedException("Using the cache requires to AssetManager.FileProvider to be valid.");
            }

            var mixin          = mixinTree.Mixin;
            var usedParameters = mixinTree.UsedParameters;

            var mixinObjectId = ShaderMixinObjectId.Compute(mixin, usedParameters);

            // Final url of the compiled bytecode
            var compiledUrl = string.Format("{0}/{1}", CompiledShadersKey, mixinObjectId);

            EffectBytecode bytecode = null;

            lock (bytecodes)
            {
                // ------------------------------------------------------------------------------------------------------------
                // 1) Try to load latest bytecode
                // ------------------------------------------------------------------------------------------------------------
                ObjectId bytecodeId;
                if (database.AssetIndexMap.TryGetValue(compiledUrl, out bytecodeId))
                {
                    bytecode = LoadEffectBytecode(bytecodeId);
                }

                // On non Windows platform, we are expecting to have the bytecode stored directly
                if (!Platform.IsWindowsDesktop && bytecode == null)
                {
                    var stringBuilder = new StringBuilder();
                    stringBuilder.AppendFormat("Unable to find compiled shaders [{0}] for mixin [{1}] with parameters [{2}]", compiledUrl, mixin, usedParameters.ToStringDetailed());
                    Log.Error(stringBuilder.ToString());
                    throw new InvalidOperationException(stringBuilder.ToString());
                }

                // ------------------------------------------------------------------------------------------------------------
                // 2) Try to load from database cache
                // ------------------------------------------------------------------------------------------------------------
                if (bytecode == null && database.ObjectDatabase.Exists(mixinObjectId))
                {
                    using (var stream = database.ObjectDatabase.OpenStream(mixinObjectId))
                    {
                        // We have an existing stream, make sure the shader is compiled
                        var objectIdBuffer = new byte[ObjectId.HashSize];
                        if (stream.Read(objectIdBuffer, 0, ObjectId.HashSize) == ObjectId.HashSize)
                        {
                            var newBytecodeId = new ObjectId(objectIdBuffer);
                            bytecode = LoadEffectBytecode(newBytecodeId);

                            if (bytecode != null)
                            {
                                // If we successfully retrieved it from cache, add it to index map so that it won't be collected and available for faster lookup
                                database.AssetIndexMap[compiledUrl] = newBytecodeId;
                            }
                        }
                    }
                }
            }

            // ------------------------------------------------------------------------------------------------------------
            // 3) Compile the shader
            // ------------------------------------------------------------------------------------------------------------
            if (bytecode == null)
            {
                // Open the database for writing
                var localLogger = new LoggerResult();

                // Compile the mixin
                bytecode = base.Compile(mixinTree, compilerParameters, localLogger);
                localLogger.CopyTo(log);

                // If there are any errors, return immediately
                if (localLogger.HasErrors)
                {
                    return(null);
                }

                // Compute the bytecodeId
                var newBytecodeId = bytecode.ComputeId();

                // Check if we really need to store the bytecode
                lock (bytecodes)
                {
                    // Using custom serialization to the database to store an object with a custom id
                    // TODO: Check if we really need to write the bytecode everytime even if id is not changed
                    var memoryStream = new MemoryStream();
                    bytecode.WriteTo(memoryStream);
                    memoryStream.Position = 0;
                    database.ObjectDatabase.Write(memoryStream, newBytecodeId, true);
                    database.AssetIndexMap[compiledUrl] = newBytecodeId;

                    // Save bytecode Id to the database cache as well
                    memoryStream.SetLength(0);
                    memoryStream.Write((byte[])newBytecodeId, 0, ObjectId.HashSize);
                    memoryStream.Position = 0;
                    database.ObjectDatabase.Write(memoryStream, mixinObjectId);

                    if (!bytecodes.ContainsKey(newBytecodeId))
                    {
                        log.Info("New effect compiled #{0} [{1}] (db: {2})\r\n{3}", effectCompileCount, mixinObjectId, newBytecodeId, usedParameters.ToStringDetailed());
                        Interlocked.Increment(ref effectCompileCount);

                        // Replace or add new bytecode
                        bytecodes[newBytecodeId] = bytecode;
                    }
                }
            }

            return(bytecode);
        }