Beispiel #1
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();
        }