Beispiel #1
0
 /// <summary>
 /// Performs pipeline initialization, enumerates views and populates visibility groups.
 /// </summary>
 /// <param name="context"></param>
 public void Collect(RenderThreadContext context)
 {
     foreach (var renderFeature in RenderFeatures)
     {
         renderFeature.Collect();
     }
 }
Beispiel #2
0
        /// <param name="context"></param>
        /// <inheritdoc/>
        public override void PrepareEffectPermutations(RenderThreadContext context)
        {
            var renderEffects   = RootRenderFeature.RenderData.GetData(renderEffectKey);
            int effectSlotCount = ((RootEffectRenderFeature)RootRenderFeature).EffectPermutationSlotCount;

            foreach (var renderObject in RootRenderFeature.RenderObjects)
            {
                var staticObjectNode = renderObject.StaticObjectNode;

                for (int i = 0; i < effectSlotCount; ++i)
                {
                    var staticEffectObjectNode = staticObjectNode * effectSlotCount + i;
                    var renderEffect           = renderEffects[staticEffectObjectNode];
                    var renderMesh             = (RenderMesh)renderObject;

                    // Skip effects not used during this frame
                    if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem))
                    {
                        continue;
                    }

                    if (renderMesh.Mesh.Skinning != null)
                    {
                        renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningPosition, renderMesh.Mesh.Parameters.Get(MaterialKeys.HasSkinningPosition));
                        renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningNormal, renderMesh.Mesh.Parameters.Get(MaterialKeys.HasSkinningNormal));
                        renderEffect.EffectValidator.ValidateParameter(MaterialKeys.HasSkinningTangent, renderMesh.Mesh.Parameters.Get(MaterialKeys.HasSkinningTangent));

                        var skinningBones = Math.Max(MaxBones, renderMesh.Mesh.Skinning.Bones.Length);
                        renderEffect.EffectValidator.ValidateParameter(MaterialKeys.SkinningMaxBones, skinningBones);
                    }
                }
            }
        }
Beispiel #3
0
        /// <inheritdoc/>
        public override unsafe void Prepare(RenderThreadContext context)
        {
            var renderModelObjectInfoData = RootRenderFeature.RenderData.GetData(renderModelObjectInfoKey);

            foreach (var renderNode in ((RootEffectRenderFeature)RootRenderFeature).RenderNodes)
            {
                var perDrawLayout = renderNode.RenderEffect.Reflection.PerDrawLayout;
                if (perDrawLayout == null)
                {
                    continue;
                }

                var blendMatricesOffset = perDrawLayout.GetConstantBufferOffset(blendMatrices);
                if (blendMatricesOffset == -1)
                {
                    continue;
                }

                var renderModelObjectInfo = renderModelObjectInfoData[renderNode.RenderObject.ObjectNode];

                var mappedCB    = renderNode.Resources.ConstantBuffer.Data + blendMatricesOffset;
                var blendMatrix = (Matrix *)mappedCB;

                for (int i = 0; i < renderModelObjectInfo.NodeInfoCount; i++)
                {
                    int boneInfoIndex = renderModelObjectInfo.NodeInfoOffset + i;
                    Matrix.Multiply(ref nodeInfos.Items[boneInfoIndex].LinkToMeshMatrix, ref nodeInfos.Items[boneInfoIndex].NodeTransformation, out *blendMatrix++);
                }
            }
        }
Beispiel #4
0
        /// <inheritdoc/>
        public override void Prepare(RenderThreadContext context)
        {
            base.Prepare(context);

            // Prepare each sub render feature
            foreach (var renderFeature in RenderFeatures)
            {
                renderFeature.Prepare(context);
            }
        }
Beispiel #5
0
        /// <param name="context"></param>
        /// <inheritdoc/>
        public override void PrepareEffectPermutationsImpl(RenderThreadContext context)
        {
            // Setup ActiveMeshDraw
            foreach (var objectNodeReference in ObjectNodeReferences)
            {
                var objectNode = GetObjectNode(objectNodeReference);
                var renderMesh = (RenderMesh)objectNode.RenderObject;

                renderMesh.ActiveMeshDraw = renderMesh.Mesh.Draw;
            }

            base.PrepareEffectPermutationsImpl(context);

            foreach (var renderFeature in RenderFeatures)
            {
                renderFeature.PrepareEffectPermutations(context);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Performs most of the work (computation and resource preparation). Later game simulation might be running during that step.
        /// </summary>
        /// <param name="context"></param>
        public unsafe void Prepare(RenderThreadContext context)
        {
            // Sync point: after extract, before prepare (game simulation could resume now)

            // Generate and execute prepare effect jobs
            foreach (var renderFeature in RenderFeatures)
            // We might be able to parallelize too as long as we resepect render feature dependency graph (probably very few dependencies in practice)
            {
                // Divide into task chunks for parallelism
                renderFeature.PrepareEffectPermutations(context);
            }

            // Generate and execute prepare jobs
            foreach (var renderFeature in RenderFeatures)
            // We might be able to parallelize too as long as we resepect render feature dependency graph (probably very few dependencies in practice)
            {
                // Divide into task chunks for parallelism
                renderFeature.Prepare(context);
            }

            // Sort
            foreach (var view in Views)
            {
                foreach (var renderViewStage in view.RenderStages)
                {
                    var renderNodes = renderViewStage.RenderNodes;
                    if (renderNodes.Count == 0)
                    {
                        continue;
                    }

                    var renderStage = renderViewStage.RenderStage;

                    // Allocate sorted render nodes
                    if (renderViewStage.SortedRenderNodes == null || renderViewStage.SortedRenderNodes.Length < renderNodes.Count)
                    {
                        Array.Resize(ref renderViewStage.SortedRenderNodes, renderNodes.Count);
                    }
                    var sortedRenderNodes = renderViewStage.SortedRenderNodes;

                    if (renderStage.SortMode != null)
                    {
                        // Make sure sortKeys is big enough
                        if (sortKeys == null || sortKeys.Length < renderNodes.Count)
                            Array.Resize(ref sortKeys, renderNodes.Count);

                        // renderNodes[start..end] belongs to the same render feature
                        fixed(SortKey *sortKeysPtr = sortKeys)
                        renderStage.SortMode.GenerateSortKey(view, renderViewStage, sortKeysPtr);

                        Array.Sort(sortKeys, 0, renderNodes.Count);

                        // Reorder list
                        for (int i = 0; i < renderNodes.Count; ++i)
                        {
                            sortedRenderNodes[i] = renderNodes[sortKeys[i].Index];
                        }
                    }
                    else
                    {
                        // No sorting, copy as is
                        for (int i = 0; i < renderNodes.Count; ++i)
                        {
                            sortedRenderNodes[i] = renderNodes[i];
                        }
                    }
                }
            }
        }
Beispiel #7
0
        /// <summary>
        /// Extract data from entities, should be as fast as possible to not block simulation loop. It should be mostly copies, and the actual processing should be part of Prepare().
        /// </summary>
        public void Extract(RenderThreadContext context)
        {
            // Prepare views
            for (int index = 0; index < Views.Count; index++)
            {
                // Update indices
                var view = Views[index];
                view.Index = index;

                // Create missing RenderViewFeature
                while (view.Features.Count < RenderFeatures.Count)
                {
                    view.Features.Add(new RenderViewFeature());
                }

                for (int i = 0; i < RenderFeatures.Count; i++)
                {
                    var renderViewFeature = view.Features[i];
                    renderViewFeature.RootFeature = RenderFeatures[i];
                }
            }

            // Create nodes for objects to render
            foreach (var view in Views)
            {
                // Sort per render feature (used for later sorting)
                // We'll be able to process data more efficiently for the next steps
                view.RenderObjects.Sort(RenderObjectFeatureComparer.Default);

                foreach (var renderObject in view.RenderObjects)
                {
                    var renderFeature = renderObject.RenderFeature;
                    var viewFeature   = view.Features[renderFeature.Index];

                    // Create object node
                    renderFeature.GetOrCreateObjectNode(renderObject);

                    // Let's create the view object node
                    var renderViewNode = renderFeature.CreateViewObjectNode(view, renderObject);
                    viewFeature.ViewObjectNodes.Add(renderViewNode);

                    // Collect object
                    // TODO: Check which stage it belongs to (and skip everything if it doesn't belong to any stage)
                    // TODO: For now, we build list and then copy. Another way would be to count and then fill (might be worse, need to check)
                    var activeRenderStages = renderObject.ActiveRenderStages;
                    foreach (var renderViewStage in view.RenderStages)
                    {
                        // Check if this RenderObject wants to be rendered for this render stage
                        var renderStageIndex = renderViewStage.RenderStage.Index;
                        if (!activeRenderStages[renderStageIndex].Active)
                        {
                            continue;
                        }

                        var renderNode = renderFeature.CreateRenderNode(renderObject, view, renderViewNode, renderViewStage.RenderStage);

                        // Note: Used mostly during updating
                        viewFeature.RenderNodes.Add(renderNode);

                        // Note: Used mostly during rendering
                        renderViewStage.RenderNodes.Add(new RenderNodeFeatureReference(renderFeature, renderNode, renderObject));
                    }
                }

                // Also sort view|stage per render feature
                foreach (var renderViewStage in view.RenderStages)
                {
                    renderViewStage.RenderNodes.Sort(RenderNodeFeatureReferenceComparer.Default);
                }
            }

            // Ensure size of data arrays per objects
            PrepareDataArrays();

            // Generate and execute extract jobs
            foreach (var renderFeature in RenderFeatures)
            // We might be able to parallelize too as long as we resepect render feature dependency graph (probably very few dependencies in practice)
            {
                // Divide into task chunks for parallelism
                renderFeature.Extract();
            }

            // Ensure size of all other data arrays
            PrepareDataArrays();
        }
Beispiel #8
0
        /// <inheritdoc/>
        public override void Prepare(RenderThreadContext context)
        {
            EffectObjectNodes.Clear();

            // Make sure descriptor set pool is large enough
            var expectedDescriptorSetPoolSize = RenderNodes.Count * effectDescriptorSetSlots.Count;

            if (ResourceGroupPool.Length < expectedDescriptorSetPoolSize)
            {
                Array.Resize(ref ResourceGroupPool, expectedDescriptorSetPoolSize);
            }

            // Allocate PerFrame, PerView and PerDraw resource groups and constant buffers
            var renderEffects   = RenderData.GetData(RenderEffectKey);
            int effectSlotCount = EffectPermutationSlotCount;

            foreach (var view in RenderSystem.Views)
            {
                var viewFeature = view.Features[Index];
                foreach (var renderNodeReference in viewFeature.RenderNodes)
                {
                    var renderNode   = this.GetRenderNode(renderNodeReference);
                    var renderObject = renderNode.RenderObject;

                    // Get RenderEffect
                    var staticObjectNode       = renderObject.StaticObjectNode;
                    var staticEffectObjectNode = staticObjectNode * effectSlotCount + effectSlots[renderNode.RenderStage.Index].Index;
                    var renderEffect           = renderEffects[staticEffectObjectNode];

                    // Not compiled yet?
                    if (renderEffect.Effect == null)
                    {
                        renderNode.RenderEffect                = renderEffect;
                        renderNode.EffectObjectNode            = EffectObjectNodeReference.Invalid;
                        renderNode.Resources                   = null;
                        RenderNodes[renderNodeReference.Index] = renderNode;
                        continue;
                    }

                    var renderEffectReflection = renderEffect.Reflection;

                    // PerView resources/cbuffer
                    var viewLayout = renderEffectReflection.PerViewLayout;
                    if (viewLayout != null)
                    {
                        if (viewLayout.Entries?.Length <= view.Index)
                        {
                            var oldEntries = viewLayout.Entries;
                            viewLayout.Entries = new ResourceGroupEntry[RenderSystem.Views.Count];

                            for (int index = 0; index < oldEntries.Length; index++)
                            {
                                viewLayout.Entries[index] = oldEntries[index];
                            }

                            for (int index = oldEntries.Length; index < viewLayout.Entries.Length; index++)
                            {
                                viewLayout.Entries[index].Resources = new ResourceGroup();
                            }
                        }

                        if (viewLayout.Entries[view.Index].MarkAsUsed(RenderSystem))
                        {
                            context.ResourceGroupAllocator.PrepareResourceGroup(viewLayout, BufferPoolAllocationType.UsedMultipleTime, viewLayout.Entries[view.Index].Resources);

                            // Register it in list of view layouts to update for this frame
                            viewFeature.Layouts.Add(viewLayout);
                        }
                    }

                    // PerFrame resources/cbuffer
                    var frameLayout = renderEffect.Reflection.PerFrameLayout;
                    if (frameLayout != null && frameLayout.Entry.MarkAsUsed(RenderSystem))
                    {
                        context.ResourceGroupAllocator.PrepareResourceGroup(frameLayout, BufferPoolAllocationType.UsedMultipleTime, frameLayout.Entry.Resources);

                        // Register it in list of view layouts to update for this frame
                        FrameLayouts.Add(frameLayout);
                    }

                    // PerDraw resources/cbuffer
                    // Get nodes
                    var viewObjectNode = GetViewObjectNode(renderNode.ViewObjectNode);

                    // Allocate descriptor set
                    renderNode.Resources = context.ResourceGroupAllocator.AllocateResourceGroup();
                    if (renderEffectReflection.PerDrawLayout != null)
                    {
                        context.ResourceGroupAllocator.PrepareResourceGroup(renderEffectReflection.PerDrawLayout, BufferPoolAllocationType.UsedOnce, renderNode.Resources);
                    }

                    // Link to EffectObjectNode (created right after)
                    // TODO: rewrite this
                    renderNode.EffectObjectNode = new EffectObjectNodeReference(EffectObjectNodes.Count);

                    renderNode.RenderEffect = renderEffect;

                    // Bind well-known descriptor sets
                    var descriptorSetPoolOffset = ComputeResourceGroupOffset(renderNodeReference);
                    ResourceGroupPool[descriptorSetPoolOffset + perFrameDescriptorSetSlot.Index] = frameLayout?.Entry.Resources;
                    ResourceGroupPool[descriptorSetPoolOffset + perViewDescriptorSetSlot.Index]  = renderEffect.Reflection.PerViewLayout?.Entries[view.Index].Resources;
                    ResourceGroupPool[descriptorSetPoolOffset + perDrawDescriptorSetSlot.Index]  = renderNode.Resources;

                    // Create resource group for everything else in case of fallback effects
                    if (renderEffect.State != RenderEffectState.Normal && renderEffect.FallbackParameters != null)
                    {
                        if (renderEffect.FallbackParameterUpdater.ResourceGroups == null)
                        {
                            // First time
                            renderEffect.FallbackParameterUpdater = new EffectParameterUpdater(renderEffect.Reflection.FallbackUpdaterLayout, renderEffect.FallbackParameters);
                        }

                        renderEffect.FallbackParameterUpdater.Update(RenderSystem.GraphicsDevice, context.ResourceGroupAllocator, renderEffect.FallbackParameters);

                        var fallbackResourceGroupMapping = renderEffect.Reflection.FallbackResourceGroupMapping;
                        for (int i = 0; i < fallbackResourceGroupMapping.Length; ++i)
                        {
                            ResourceGroupPool[descriptorSetPoolOffset + fallbackResourceGroupMapping[i]] = renderEffect.FallbackParameterUpdater.ResourceGroups[i];
                        }
                    }

                    // Compile pipeline state object (if first time or need change)
                    // TODO GRAPHICS REFACTOR how to invalidate if we want to change some state? (setting to null should be fine)
                    if (renderEffect.PipelineState == null)
                    {
                        var pipelineState = MutablePipeline.State;
                        pipelineState.SetDefaults();

                        // Effect
                        pipelineState.EffectBytecode = renderEffect.Effect.Bytecode;
                        pipelineState.RootSignature  = renderEffect.Reflection.RootSignature;

                        // Extract outputs from render stage
                        pipelineState.Output = renderNode.RenderStage.Output;

                        // Bind VAO
                        ProcessPipelineState(Context, renderNodeReference, ref renderNode, renderObject, pipelineState);

                        PostProcessPipelineState?.Invoke(renderNodeReference, ref renderNode, renderObject, pipelineState);

                        MutablePipeline.Update();
                        renderEffect.PipelineState = MutablePipeline.CurrentState;
                    }

                    RenderNodes[renderNodeReference.Index] = renderNode;

                    // Create EffectObjectNode
                    EffectObjectNodes.Add(new EffectObjectNode(renderEffect, viewObjectNode.ObjectNode));
                }
            }
        }
Beispiel #9
0
        /// <param name="context"></param>
        /// <inheritdoc/>
        public override void PrepareEffectPermutations(RenderThreadContext context)
        {
            base.PrepareEffectPermutations(context);

            // TODO: Temporary until we have a better system for handling permutations
            var renderEffects   = RenderData.GetData(RenderEffectKey);
            int effectSlotCount = EffectPermutationSlotCount;

            foreach (var view in RenderSystem.Views)
            {
                var viewFeature = view.Features[Index];
                foreach (var renderNodeReference in viewFeature.RenderNodes)
                {
                    var renderNode   = this.GetRenderNode(renderNodeReference);
                    var renderObject = renderNode.RenderObject;

                    // Get RenderEffect
                    var staticObjectNode       = renderObject.StaticObjectNode;
                    var staticEffectObjectNode = staticObjectNode * effectSlotCount + effectSlots[renderNode.RenderStage.Index].Index;
                    var renderEffect           = renderEffects[staticEffectObjectNode];

                    var effectSelector = renderObject.ActiveRenderStages[renderNode.RenderStage.Index].EffectSelector;

                    // Create it (first time) or regenerate it if effect changed
                    if (renderEffect == null || effectSelector != renderEffect.EffectSelector)
                    {
                        renderEffect = new RenderEffect(renderObject.ActiveRenderStages[renderNode.RenderStage.Index].EffectSelector);
                        renderEffects[staticEffectObjectNode] = renderEffect;
                    }

                    // Is it the first time this frame that we check this RenderEffect?
                    if (renderEffect.MarkAsUsed(RenderSystem))
                    {
                        renderEffect.EffectValidator.BeginEffectValidation();
                    }
                }
            }

            // Step1: Perform permutations
            PrepareEffectPermutationsImpl(context);

            // CompilerParameters are ThreadStatic
            if (staticCompilerParameters == null)
            {
                staticCompilerParameters = new CompilerParameters();
            }

            // Step2: Compile effects and update reflection infos (offset, etc...)
            foreach (var renderObject in RenderObjects)
            {
                var staticObjectNode = renderObject.StaticObjectNode;

                for (int i = 0; i < effectSlotCount; ++i)
                {
                    var staticEffectObjectNode = staticObjectNode * effectSlotCount + i;
                    var renderEffect           = renderEffects[staticEffectObjectNode];

                    // Skip if not used
                    if (renderEffect == null || !renderEffect.IsUsedDuringThisFrame(RenderSystem))
                    {
                        continue;
                    }

                    // Skip if nothing changed
                    Effect effect;
                    if (renderEffect.EffectValidator.ShouldSkip)
                    {
                        // Reset pending effect, as it is now obsolete anyway
                        effect = null;
                        renderEffect.Effect = null;
                        renderEffect.State  = RenderEffectState.Skip;
                    }
                    else if (renderEffect.EffectValidator.EndEffectValidation())
                    {
                        InvalidateEffectPermutation(renderObject, renderEffect);

                        // Still, let's check if there is a pending effect compiling
                        var pendingEffect = renderEffect.PendingEffect;
                        if (pendingEffect == null || !pendingEffect.IsCompleted)
                        {
                            continue;
                        }

                        renderEffect.ClearFallbackParameters();
                        if (pendingEffect.IsFaulted)
                        {
                            renderEffect.State = RenderEffectState.Error;
                            effect             = ComputeFallbackEffect?.Invoke(renderObject, renderEffect, RenderEffectState.Error);
                        }
                        else
                        {
                            renderEffect.State = RenderEffectState.Normal;
                            effect             = pendingEffect.Result;
                        }
                        renderEffect.PendingEffect = null;
                    }
                    else
                    {
                        // Reset pending effect, as it is now obsolete anyway
                        renderEffect.PendingEffect = null;
                        renderEffect.State         = RenderEffectState.Normal;

                        foreach (var effectValue in renderEffect.EffectValidator.EffectValues)
                        {
                            staticCompilerParameters.SetObject(effectValue.Key, effectValue.Value);
                        }

                        var asyncEffect = RenderSystem.EffectSystem.LoadEffect(renderEffect.EffectSelector.EffectName, staticCompilerParameters);
                        staticCompilerParameters.Clear();

                        effect = asyncEffect.Result;
                        if (effect == null)
                        {
                            // Effect still compiling, let's find if there is a fallback
                            renderEffect.ClearFallbackParameters();
                            effect = ComputeFallbackEffect?.Invoke(renderObject, renderEffect, RenderEffectState.Compiling);
                            if (effect != null)
                            {
                                // Use the fallback for now
                                renderEffect.PendingEffect = asyncEffect.Task;
                                renderEffect.State         = RenderEffectState.Compiling;
                            }
                            else
                            {
                                // No fallback effect, let's block until effect is compiled
                                effect = asyncEffect.WaitForResult();
                            }
                        }
                    }

                    var effectHashCode = effect != null ? (uint)effect.GetHashCode() : 0;

                    // Effect is last 16 bits
                    renderObject.StateSortKey = (renderObject.StateSortKey & 0xFFFF0000) | (effectHashCode & 0x0000FFFF);

                    if (effect != null)
                    {
                        RenderEffectReflection renderEffectReflection;
                        if (!InstantiatedEffects.TryGetValue(effect, out renderEffectReflection))
                        {
                            renderEffectReflection = new RenderEffectReflection();

                            // Build root signature automatically from reflection
                            renderEffectReflection.DescriptorReflection      = EffectDescriptorSetReflection.New(RenderSystem.GraphicsDevice, effect.Bytecode, effectDescriptorSetSlots, "PerFrame");
                            renderEffectReflection.ResourceGroupDescriptions = new ResourceGroupDescription[renderEffectReflection.DescriptorReflection.Layouts.Count];

                            // Compute ResourceGroup hashes
                            for (int index = 0; index < renderEffectReflection.DescriptorReflection.Layouts.Count; index++)
                            {
                                var descriptorSet = renderEffectReflection.DescriptorReflection.Layouts[index];
                                if (descriptorSet.Layout == null)
                                {
                                    continue;
                                }

                                var constantBufferReflection = effect.Bytecode.Reflection.ConstantBuffers.FirstOrDefault(x => x.Name == descriptorSet.Name);

                                renderEffectReflection.ResourceGroupDescriptions[index] = new ResourceGroupDescription(descriptorSet.Layout, constantBufferReflection);
                            }

                            renderEffectReflection.RootSignature = RootSignature.New(RenderSystem.GraphicsDevice, renderEffectReflection.DescriptorReflection);
                            renderEffectReflection.BufferUploader.Compile(RenderSystem.GraphicsDevice, renderEffectReflection.DescriptorReflection, effect.Bytecode);

                            // Prepare well-known descriptor set layouts
                            renderEffectReflection.PerDrawLayout  = CreateDrawResourceGroupLayout(renderEffectReflection.ResourceGroupDescriptions[perDrawDescriptorSetSlot.Index], effect.Bytecode);
                            renderEffectReflection.PerFrameLayout = CreateFrameResourceGroupLayout(renderEffectReflection.ResourceGroupDescriptions[perFrameDescriptorSetSlot.Index], effect.Bytecode);
                            renderEffectReflection.PerViewLayout  = CreateViewResourceGroupLayout(renderEffectReflection.ResourceGroupDescriptions[perViewDescriptorSetSlot.Index], effect.Bytecode);

                            InstantiatedEffects.Add(effect, renderEffectReflection);

                            // Notify a new effect has been compiled
                            EffectCompiled?.Invoke(RenderSystem, effect, renderEffectReflection);
                        }

                        // Setup fallback parameters
                        if (renderEffect.State != RenderEffectState.Normal && renderEffectReflection.FallbackUpdaterLayout == null)
                        {
                            // Process all "non standard" layouts
                            var layoutMapping      = new int[renderEffectReflection.DescriptorReflection.Layouts.Count - 3];
                            var layouts            = new DescriptorSetLayoutBuilder[renderEffectReflection.DescriptorReflection.Layouts.Count - 3];
                            int layoutMappingIndex = 0;
                            for (int index = 0; index < renderEffectReflection.DescriptorReflection.Layouts.Count; index++)
                            {
                                var layout = renderEffectReflection.DescriptorReflection.Layouts[index];

                                // Skip well-known layouts (already handled)
                                if (layout.Name == "PerDraw" || layout.Name == "PerFrame" || layout.Name == "PerView")
                                {
                                    continue;
                                }

                                layouts[layoutMappingIndex]         = layout.Layout;
                                layoutMapping[layoutMappingIndex++] = index;
                            }

                            renderEffectReflection.FallbackUpdaterLayout        = new EffectParameterUpdaterLayout(RenderSystem.GraphicsDevice, effect, layouts);
                            renderEffectReflection.FallbackResourceGroupMapping = layoutMapping;
                        }

                        // Update effect
                        renderEffect.Effect     = effect;
                        renderEffect.Reflection = renderEffectReflection;

                        // Invalidate pipeline state (new effect)
                        renderEffect.PipelineState = null;

                        renderEffects[staticEffectObjectNode] = renderEffect;
                    }
                    else
                    {
                        renderEffect.Reflection    = RenderEffectReflection.Empty;
                        renderEffect.PipelineState = null;
                    }
                }
            }
        }
Beispiel #10
0
 /// <summary>
 /// Actual implementation of <see cref="PrepareEffectPermutations"/>.
 /// </summary>
 /// <param name="context"></param>
 public virtual void PrepareEffectPermutationsImpl(RenderThreadContext context)
 {
 }
Beispiel #11
0
 /// <summary>
 /// Performs most of the work (computation and resource preparation). Later game simulation might be running during that step.
 /// </summary>
 /// <param name="context"></param>
 public virtual void Prepare(RenderThreadContext context)
 {
 }
Beispiel #12
0
        /// <param name="context"></param>
        /// <inheritdoc/>
        public unsafe override void Prepare(RenderThreadContext context)
        {
            // Compute WorldView, WorldViewProj
            var renderModelObjectInfoData = RootRenderFeature.RenderData.GetData(renderModelObjectInfoKey);
            var renderModelViewInfoData   = RootRenderFeature.RenderData.GetData(renderModelViewInfoKey);

            // Update PerFrame (time)
            // TODO Move that to RootEffectRenderFeature?
            foreach (var frameLayout in ((RootEffectRenderFeature)RootRenderFeature).FrameLayouts)
            {
                var timeOffset = frameLayout.GetConstantBufferOffset(time);
                if (timeOffset == -1)
                {
                    continue;
                }

                var resourceGroup = frameLayout.Entry.Resources;
                var mappedCB      = resourceGroup.ConstantBuffer.Data;

                var perFrameTime = (PerFrameTime *)((byte *)mappedCB + timeOffset);
                perFrameTime->Time     = (float)Context.Time.Total.TotalSeconds;
                perFrameTime->TimeStep = (float)Context.Time.Elapsed.TotalSeconds;
            }

            // Update PerView (View, Proj, etc...)
            for (int index = 0; index < RenderSystem.Views.Count; index++)
            {
                var view        = RenderSystem.Views[index];
                var viewFeature = view.Features[RootRenderFeature.Index];

                // Compute WorldView and WorldViewProjection
                foreach (var renderPerViewNodeReference in viewFeature.ViewObjectNodes)
                {
                    var renderPerViewNode    = RootRenderFeature.GetViewObjectNode(renderPerViewNodeReference);
                    var renderModelFrameInfo = renderModelObjectInfoData[renderPerViewNode.ObjectNode];

                    var renderModelViewInfo = new RenderModelViewInfo();
                    Matrix.Multiply(ref renderModelFrameInfo.World, ref view.View, out renderModelViewInfo.WorldView);
                    Matrix.Multiply(ref renderModelFrameInfo.World, ref view.ViewProjection, out renderModelViewInfo.WorldViewProjection);

                    // TODO: Use ref locals or Utilities instead, to avoid double copy
                    renderModelViewInfoData[renderPerViewNodeReference] = renderModelViewInfo;
                }

                // Copy ViewProjection to PerView cbuffer
                foreach (var viewLayout in viewFeature.Layouts)
                {
                    var viewProjectionOffset = viewLayout.GetConstantBufferOffset(this.view);
                    if (viewProjectionOffset == -1)
                    {
                        continue;
                    }

                    var resourceGroup = viewLayout.Entries[view.Index].Resources;
                    var mappedCB      = resourceGroup.ConstantBuffer.Data;

                    var perView = (PerView *)((byte *)mappedCB + viewProjectionOffset);

                    // Fill PerView
                    perView->View = view.View;
                    Matrix.Invert(ref view.View, out perView->ViewInverse);
                    perView->Projection = view.Projection;
                    Matrix.Invert(ref view.Projection, out perView->ProjectionInverse);
                    perView->ViewProjection = view.ViewProjection;
                    perView->ProjScreenRay  = new Vector2(-1.0f / view.Projection.M11, 1.0f / view.Projection.M22);
                    // TODO GRAPHICS REFACTOR avoid cbuffer read
                    perView->Eye = new Vector4(perView->ViewInverse.M41, perView->ViewInverse.M42, perView->ViewInverse.M43, 1.0f);
                }

                // Copy Camera to PerView cbuffer
                var cameraComponent = view.Camera;
                if (cameraComponent != null)
                {
                    foreach (var viewLayout in viewFeature.Layouts)
                    {
                        var cameraOffset = viewLayout.GetConstantBufferOffset(camera);
                        if (cameraOffset == -1)
                        {
                            continue;
                        }

                        var resourceGroup = viewLayout.Entries[view.Index].Resources;
                        var mappedCB      = resourceGroup.ConstantBuffer.Data;

                        var perViewCamera = (PerViewCamera *)((byte *)mappedCB + cameraOffset);

                        perViewCamera->NearClipPlane = cameraComponent.NearClipPlane;
                        perViewCamera->FarClipPlane  = cameraComponent.FarClipPlane;
                        perViewCamera->ZProjection   = CameraKeys.ZProjectionACalculate(cameraComponent.NearClipPlane, cameraComponent.FarClipPlane);

                        if (view.SceneCameraRenderer != null)
                        {
                            perViewCamera->ViewSize = new Vector2(view.SceneCameraRenderer.ComputedViewport.Width, view.SceneCameraRenderer.ComputedViewport.Height);
                        }

                        perViewCamera->AspectRatio         = cameraComponent.AspectRatio;
                        perViewCamera->VerticalFieldOfView = cameraComponent.VerticalFieldOfView;
                        perViewCamera->OrthoSize           = cameraComponent.OrthographicSize;
                    }
                }
            }

            // Update PerDraw (World, WorldViewProj, etc...)
            // Copy Entity.World to PerDraw cbuffer
            // TODO: Have a PerObject cbuffer?
            foreach (var renderNode in ((RootEffectRenderFeature)RootRenderFeature).RenderNodes)
            {
                var perDrawLayout = renderNode.RenderEffect.Reflection.PerDrawLayout;
                if (perDrawLayout == null)
                {
                    continue;
                }

                var worldOffset = perDrawLayout.GetConstantBufferOffset(this.world);
                if (worldOffset == -1)
                {
                    continue;
                }

                var renderModelObjectInfo = renderModelObjectInfoData[renderNode.RenderObject.ObjectNode];
                var renderModelViewInfo   = renderModelViewInfoData[renderNode.ViewObjectNode];

                var mappedCB = renderNode.Resources.ConstantBuffer.Data;
                var perDraw  = (PerDraw *)((byte *)mappedCB + worldOffset);


                // Fill PerDraw
                perDraw->World = renderModelObjectInfo.World;
                Matrix.Invert(ref renderModelObjectInfo.World, out perDraw->WorldInverse);
                // TODO GRAPHICS REFACTOR avoid cbuffer read
                Matrix.Transpose(ref perDraw->WorldInverse, out perDraw->WorldInverseTranspose);
                perDraw->WorldView = renderModelViewInfo.WorldView;
                Matrix.Invert(ref renderModelViewInfo.WorldView, out perDraw->WorldViewInverse);
                perDraw->WorldViewProjection = renderModelViewInfo.WorldViewProjection;
                perDraw->WorldScale          = new Vector3(
                    ((Vector3)renderModelObjectInfo.World.Row1).Length(),
                    ((Vector3)renderModelObjectInfo.World.Row2).Length(),
                    ((Vector3)renderModelObjectInfo.World.Row3).Length());
                // TODO GRAPHICS REFACTOR avoid cbuffer read
                perDraw->EyeMS = new Vector4(perDraw->WorldViewInverse.M41, perDraw->WorldViewInverse.M42, perDraw->WorldViewInverse.M43, 1.0f);
            }
        }