Ejemplo n.º 1
0
        /// <summary>
        /// Merges an existing <see cref="EffectData" /> into this instance.
        /// </summary>
        /// <param name="source">The EffectData to merge.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
        /// <remarks>This method is useful to build an archive of several effects.</remarks>
        private EffectData.Effect RegisterInternal(EffectData source)
        {
            var effect = source.Description;

            var effectRuntime = new EffectData.Effect()
            {
                Name                 = effect.Name,
                Arguments            = effect.Arguments,
                ShareConstantBuffers = effect.ShareConstantBuffers,
                Techniques           = new List <EffectData.Technique>(effect.Techniques.Count)
            };

            Logger logger = null;

            foreach (var techniqueOriginal in effect.Techniques)
            {
                var technique = techniqueOriginal.Clone();
                effectRuntime.Techniques.Add(technique);

                foreach (var pass in technique.Passes)
                {
                    foreach (var shaderLink in pass.Pipeline)
                    {
                        // No shader set for this stage
                        if (shaderLink == null)
                        {
                            continue;
                        }

                        // If the shader is an import, we try first to resolve it directly
                        if (shaderLink.IsImport)
                        {
                            var index = FindShaderByName(shaderLink.ImportName);
                            if (index >= 0)
                            {
                                shaderLink.ImportName = null;
                                shaderLink.Index      = index;
                            }
                            else
                            {
                                if (logger == null)
                                {
                                    logger = new Logger();
                                }

                                logger.Error("Cannot find shader import by name [{0}]", shaderLink.ImportName);
                            }
                        }
                        else if (!shaderLink.IsNullShader)
                        {
                            var shader = source.Shaders[shaderLink.Index];

                            // Find a similar shader
                            var shaderIndex = FindSimilarShader(shader);

                            if (shaderIndex >= 0)
                            {
                                var previousShader = RegisteredShaders[shaderIndex];

                                // If the previous shader is
                                if (shader.Name != null)
                                {
                                    // if shader from this instance is local and shader from source is global => transform current shader to global
                                    if (previousShader.Name == null)
                                    {
                                        previousShader.Name = shader.Name;
                                    }
                                    else if (shader.Name != previousShader.Name)
                                    {
                                        if (logger == null)
                                        {
                                            logger = new Logger();
                                        }
                                        // If shader from this instance is global and shader from source is global => check names. If exported names are different, this is an error
                                        logger.Error("Cannot merge shader [{0}] into this instance, as there is already a global shader with a different name [{1}]", shader.Name, previousShader.Name);
                                    }
                                }

                                shaderLink.Index = shaderIndex;
                            }
                            else
                            {
                                shaderLink.Index = RegisteredShaders.Count;
                                RegisteredShaders.Add(shader);
                            }
                        }
                    }
                }
            }

            if (logger != null && logger.HasErrors)
            {
                throw new InvalidOperationException(Utilities.Join("\r\n", logger.Messages));
            }

            return(effectRuntime);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Merges an existing <see cref="EffectData" /> into this instance.
        /// </summary>
        /// <param name="source">The EffectData to merge.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
        /// <remarks>This method is useful to build an archive of several effects.</remarks>
        private EffectData.Effect RegisterInternal(EffectData source)
        {
            var effect = source.Description;

            var effectRuntime = new EffectData.Effect()
                                    {
                                        Name = effect.Name,
                                        Arguments = effect.Arguments,
                                        ShareConstantBuffers = effect.ShareConstantBuffers,
                                        Techniques = new List<EffectData.Technique>(effect.Techniques.Count)
                                    };

            Logger logger = null;

            foreach (var techniqueOriginal in effect.Techniques)
            {
                var technique = techniqueOriginal.Clone();
                effectRuntime.Techniques.Add(technique);

                foreach (var pass in technique.Passes)
                {
                    foreach (var shaderLink in pass.Pipeline)
                    {
                        // No shader set for this stage
                        if (shaderLink == null) continue;

                        // If the shader is an import, we try first to resolve it directly
                        if (shaderLink.IsImport)
                        {
                            var index = FindShaderByName(shaderLink.ImportName);
                            if (index >= 0)
                            {
                                shaderLink.ImportName = null;
                                shaderLink.Index = index;
                            }
                            else
                            {
                                if (logger == null)
                                {
                                    logger = new Logger();
                                }

                                logger.Error("Cannot find shader import by name [{0}]", shaderLink.ImportName);
                            }
                        }
                        else if (!shaderLink.IsNullShader)
                        {
                            var shader = source.Shaders[shaderLink.Index];

                            // Find a similar shader
                            var shaderIndex = FindSimilarShader(shader);

                            if (shaderIndex >= 0)
                            {
                                var previousShader = RegisteredShaders[shaderIndex];

                                // If the previous shader is 
                                if (shader.Name != null)
                                {
                                    // if shader from this instance is local and shader from source is global => transform current shader to global
                                    if (previousShader.Name == null)
                                    {
                                        previousShader.Name = shader.Name;
                                    }
                                    else if (shader.Name != previousShader.Name)
                                    {
                                        if (logger == null)
                                        {
                                            logger = new Logger();
                                        }
                                        // If shader from this instance is global and shader from source is global => check names. If exported names are different, this is an error
                                        logger.Error("Cannot merge shader [{0}] into this instance, as there is already a global shader with a different name [{1}]", shader.Name, previousShader.Name);
                                    }
                                }

                                shaderLink.Index = shaderIndex;
                            }
                            else
                            {
                                shaderLink.Index = RegisteredShaders.Count;
                                RegisteredShaders.Add(shader);
                            }
                        }
                    }
                }
            }

            if (logger != null && logger.HasErrors)
                throw new InvalidOperationException(Utilities.Join("\r\n", logger.Messages));

            return effectRuntime;
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Binds the specified effect data to this instance.
        /// </summary>
        /// <param name="effectDataArg">The effect data arg.</param>
        /// <param name="cloneFromEffect">The clone from effect.</param>
        /// <exception cref="System.InvalidOperationException">If no techniques found in this effect.</exception>
        /// <exception cref="System.ArgumentException">If unable to find effect [effectName] from the EffectPool.</exception>
        internal void InitializeFrom(EffectData.Effect effectDataArg, Effect cloneFromEffect)
        {
            RawEffectData = effectDataArg;

            // Clean any previously allocated resources
            if (DisposeCollector != null)
            {
                DisposeCollector.DisposeAndClear();
            }
            ConstantBuffers.Clear();
            Parameters.Clear();
            Techniques.Clear();
            ResourceLinker = ToDispose(new EffectResourceLinker());
            if (effectConstantBuffersCache != null)
            {
                effectConstantBuffersCache.Clear();
            }

            // Copy data
            IsSupportingDynamicCompilation = RawEffectData.Arguments != null;
            ShareConstantBuffers           = RawEffectData.ShareConstantBuffers;

            // Create the local effect constant buffers cache
            if (!ShareConstantBuffers)
            {
                effectConstantBuffersCache = new Dictionary <EffectConstantBufferKey, EffectConstantBuffer>();
            }

            var        logger         = new Logger();
            int        techniqueIndex = 0;
            int        totalPassCount = 0;
            EffectPass parentPass     = null;

            foreach (var techniqueRaw in RawEffectData.Techniques)
            {
                var name = techniqueRaw.Name;
                if (string.IsNullOrEmpty(name))
                {
                    name = string.Format("${0}", techniqueIndex++);
                }

                var technique = new EffectTechnique(this, name);
                Techniques.Add(technique);

                int passIndex = 0;
                foreach (var passRaw in techniqueRaw.Passes)
                {
                    name = passRaw.Name;
                    if (string.IsNullOrEmpty(name))
                    {
                        name = string.Format("${0}", passIndex++);
                    }

                    var pass = new EffectPass(logger, this, technique, passRaw, name);

                    pass.Initialize(logger);

                    // If this is a subpass, add it to the parent pass
                    if (passRaw.IsSubPass)
                    {
                        if (parentPass == null)
                        {
                            logger.Error("Pass [{0}] is declared as a subpass but has no parent.");
                        }
                        else
                        {
                            parentPass.SubPasses.Add(pass);
                        }
                    }
                    else
                    {
                        technique.Passes.Add(pass);
                        parentPass = pass;
                    }
                }

                // Count the number of passes
                totalPassCount += technique.Passes.Count;
            }

            if (totalPassCount == 0)
            {
                throw new InvalidOperationException("No passes found in this effect.");
            }

            // Log all the exception in a single throw
            if (logger.HasErrors)
            {
                throw new InvalidOperationException(Utilities.Join("\n", logger.Messages));
            }

            // Initialize the resource linker when we are done with all pass/parameters
            ResourceLinker.Initialize();

            //// Sort all parameters by their resource types
            //// in order to achieve better local cache coherency in resource linker
            Parameters.Items.Sort((left, right) =>
            {
                // First, order first all value types, then resource type
                var comparison = left.IsValueType != right.IsValueType ? left.IsValueType ? -1 : 1 : 0;

                // If same type
                if (comparison == 0)
                {
                    // Order by resource type
                    comparison = ((int)left.ResourceType).CompareTo((int)right.ResourceType);

                    // If same, order by resource index
                    if (comparison == 0)
                    {
                        comparison = left.Offset.CompareTo(right.Offset);
                    }
                }
                return(comparison);
            });

            // Prelink constant buffers
            int resourceIndex = 0;

            foreach (var parameter in Parameters)
            {
                // Recalculate parameter resource index
                if (!parameter.IsValueType)
                {
                    parameter.Offset = resourceIndex;
                    resourceIndex   += parameter.ElementCount;
                }

                // Set the default values
                parameter.SetDefaultValue();

                if (parameter.ResourceType == EffectResourceType.ConstantBuffer)
                {
                    parameter.SetResource(ConstantBuffers[parameter.Name]);
                }
            }

            // Compute slot links
            foreach (var technique in Techniques)
            {
                foreach (var pass in technique.Passes)
                {
                    foreach (var subPass in pass.SubPasses)
                    {
                        subPass.ComputeSlotLinks();
                    }
                    pass.ComputeSlotLinks();
                }
            }

            // Setup the first Current Technique.
            CurrentTechnique = this.Techniques[0];

            // Initialize predefined parameters used by Model.Draw (to speedup things internally)
            DefaultParameters = new EffectDefaultParameters(this);

            // If this is a clone, we need to
            if (cloneFromEffect != null)
            {
                // Copy the content of the constant buffers to the new instance.
                for (int i = 0; i < ConstantBuffers.Count; i++)
                {
                    cloneFromEffect.ConstantBuffers[i].CopyTo(ConstantBuffers[i]);
                }

                // Copy back all bound resources except constant buffers
                // that are already initialized with InitializeFrom method.
                for (int i = 0; i < cloneFromEffect.ResourceLinker.Count; i++)
                {
                    if (cloneFromEffect.ResourceLinker.BoundResources[i] is EffectConstantBuffer)
                    {
                        continue;
                    }

                    ResourceLinker.BoundResources[i] = cloneFromEffect.ResourceLinker.BoundResources[i];
                    unsafe
                    {
                        ResourceLinker.Pointers[i] = cloneFromEffect.ResourceLinker.Pointers[i];
                    }
                }

                // If everything was fine, then we can register it into the pool
                Pool.AddEffect(this);
            }

            // Allow subclasses to complete initialization.
            Initialize();

            OnInitialized();
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Initializes the specified effect bytecode.
        /// </summary>
        /// <param name="effectDataArg">The effect bytecode.</param>
        /// <exception cref="System.InvalidOperationException"></exception>
        private void Initialize(EffectData.Effect effectDataArg)
        {
            if (effectDataArg == null)
                throw new ArgumentException(string.Format("Unable to find effect [{0}] from the EffectPool", Name), "effectName");

            rawEffect = effectDataArg;

            ShareConstantBuffers = effectDataArg.ShareConstantBuffers;

            // Create the local effect constant buffers cache
            if (!ShareConstantBuffers)
                effectConstantBuffersCache = new Dictionary<EffectConstantBufferKey, EffectConstantBuffer>();

            if (effectDataArg.Techniques.Count == 0)
                throw new InvalidOperationException("No techniques found in this effect");

            var logger = new Logger();
            int techniqueIndex = 0;
            int totalPassCount = 0;
            EffectPass parentPass = null;
            foreach (var techniqueRaw in effectDataArg.Techniques)
            {
                var name = techniqueRaw.Name;
                if (string.IsNullOrEmpty(name))
                    name = string.Format("${0}", techniqueIndex++);

                var technique = new EffectTechnique(this, name);
                Techniques.Add(technique);

                int passIndex = 0;
                foreach (var passRaw in techniqueRaw.Passes)
                {
                    name = passRaw.Name;
                    if (string.IsNullOrEmpty(name))
                        name = string.Format("${0}", passIndex++);

                    var pass = new EffectPass(logger, this, technique, passRaw, name);

                    pass.Initialize(logger);

                    // If this is a subpass, add it to the parent pass
                    if (passRaw.IsSubPass)
                    {
                        if (parentPass == null)
                        {
                            logger.Error("Pass [{0}] is declared as a subpass but has no parent");
                        }
                        else
                        {
                            parentPass.SubPasses.Add(pass);
                        }
                    }
                    else
                    {
                        technique.Passes.Add(pass);
                        parentPass = pass;
                    }
                }

                // Count the number of passes
                totalPassCount += technique.Passes.Count;
            }

            if (totalPassCount == 0)
                throw new InvalidOperationException("No passes found in this effect");

            // Log all the exception in a single throw
            if (logger.HasErrors)
                throw new InvalidOperationException(Utilities.Join("\n", logger.Messages));

            // Initialize the resource linker when we are done with all pass/parameters
            ResourceLinker.Initialize();

            //// Sort all parameters by their resource types
            //// in order to achieve better local cache coherency in resource linker
            Parameters.Items.Sort((left, right) =>
                {
                    // First, order first all value types, then resource type
                    var comparison = left.IsValueType != right.IsValueType ? left.IsValueType ? -1 : 1 : 0;

                    // If same type
                    if (comparison == 0)
                    {
                        // Order by resource type
                        comparison = ((int)left.ResourceType).CompareTo((int)right.ResourceType);

                        // If same, order by resource index
                        if (comparison == 0)
                        {
                            comparison = left.Offset.CompareTo(right.Offset);
                        }
                    }
                    return comparison;
                });

            // Prelink constant buffers
            int resourceIndex = 0;
            foreach (var parameter in Parameters)
            {
                // Recalculate parameter resource index
                if (!parameter.IsValueType)
                {
                    parameter.Offset = resourceIndex++;
                }

                // Set the default values 
                parameter.SetDefaultValue();

                if (parameter.ResourceType == EffectResourceType.ConstantBuffer)
                    parameter.SetResource(0, ConstantBuffers[parameter.Name]);
            }

            // Compute slot links
            foreach (var technique in Techniques)
            {
                foreach (var pass in technique.Passes)
                {
                    foreach (var subPass in pass.SubPasses)
                    {
                        subPass.ComputeSlotLinks();
                    }
                    pass.ComputeSlotLinks();
                }
            }

            // Setup the first Current Technique.
            CurrentTechnique = this.Techniques[0];
        }