Exemplo n.º 1
0
        /// <summary>
        /// Compiles using a given shader compiler.
        /// </summary>
        /// <param name="compiler">The compiler.</param>
        /// <param name="parameters">Shader parameters.</param>
        public IShader Compile(ShaderCompiler compiler, FixedShaderParameters parameters)
        {
            if (immutable == false || parameters == null || parameters.ShaderCode != this)
            {
                throw new ArgumentNullException("Argument is invalid (null) or is not part of this ShaderCode.");
            }

            lock (cacheSyncRoot)
            {
                ICacheable shader = cache.FindAndTouch(parameters);
                if (shader != null)
                {
                    return(shader as IShader);
                }
            }

            // We make validation of parameters and layouts.
            parameters.IsDefinedThrow();

            // ShaderCode must be immutable here if parameters were sucessfully created, operations must be cached.
            List <KeyValuePair <Pin, ShaderCompiler.Operand> > operands = new List <KeyValuePair <Pin, ShaderCompiler.Operand> >();

            cachedOps = (cachedOps == null) ? GraphHelper.GetSortedOperations(output) : cachedOps;

            List <DualShareContext> shareData = new List <DualShareContext>();

            // Begin compilation process.
            compiler.Begin(stage);

            // We go through all operations in right order
            for (int i = cachedOps.Count - 1; i >= 0; i--)
            {
                IOperation operation = cachedOps[i];

                // First prepare all inputs.
                Pin[] pins = operation.Inputs;
                ShaderCompiler.Operand[] inputs = new ShaderCompiler.Operand[pins.Length];
                for (uint j = 0; j < pins.Length; j++)
                {
                    // We extract it.
                    for (int z = 0; z < operands.Count; z++)
                    {
                        if (object.ReferenceEquals(operands[z].Key, pins[j]))
                        {
                            inputs[j] = operands[z].Value;
                            continue;
                        }
                    }
                }

                // Find if sharing context exists.
                int idx = shareData.FindIndex(delegate(DualShareContext c) { return(c.DestinationOperation == operation); });
                DualShareContext shareContext = null;
                if (idx >= 0)
                {
                    shareContext = shareData[idx];
                    shareData.RemoveAt(idx);
                }

                // Compile the operation.
                ShaderCompiler.Operand[] outputs = operation.Compile(compiler, inputs,
                                                                     parameters, ref shareContext);

                // We add it if it is not the same as "this" and notn-null.
                if (shareContext != null && shareContext.DestinationOperation != operation)
                {
                    shareData.Add(shareContext);
                }

                // Add all outputs.
                for (uint z = 0; z < outputs.Length; z++)
                {
                    operands.Add(new KeyValuePair <Pin, ShaderCompiler.Operand>(operation.Outputs[z], outputs[z]));
                }
            }

            // We do the compile process.
            IShader shader1 = compiler.End(parameters);

            // We add it to cache.
            lock (cacheSyncRoot)
            {
                try
                {
                    cache.Add(parameters, shader1);
                } catch (Exception)
                {
                    // This is the case when cache probably re-inserted shader.
                    IShader shader2 = cache.FindAndTouch(parameters) as IShader;
                    if (shader2 != null)
                    {
                        Common.Warning(typeof(ShaderCode), "Recompiled the same shader two times in a row.");

                        shader1.Dispose();
                        return(shader2);
                    }

                    // If not, we rethrow.
                    throw;
                }
            }

            return(shader1);
        }