예제 #1
0
 /// <summary>
 /// Perform effect permutations, before <see cref="Prepare"/>.
 /// </summary>
 /// <param name="context"></param>
 public virtual void PrepareEffectPermutations(RenderDrawContext context)
 {
 }
예제 #2
0
 protected abstract void DrawCore(RenderDrawContext context, RenderFrame output);
예제 #3
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(RenderDrawContext context)
 {
 }
예제 #4
0
 /// <summary>
 /// Performs GPU updates and/or draw.
 /// </summary>
 /// <param name="context"></param>
 /// <param name="renderView"></param>
 /// <param name="renderViewStage"></param>
 /// <param name="startIndex"></param>
 /// <param name="endIndex"></param>
 public virtual void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex)
 {
 }
예제 #5
0
        /// <inheritdoc/>
        public override void Prepare(RenderDrawContext context)
        {
            EffectObjectNodes.Clear(false);

            // 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];

                Dispatcher.ForEach(viewFeature.RenderNodes, () => prepareThreadContext.Value, (renderNodeReference, batch) =>
                {
                    var threadContext = batch.Context;
                    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;
                        return;
                    }

                    var renderEffectReflection = renderEffect.Reflection;

                    // PerView resources/cbuffer
                    var viewLayout = renderEffectReflection.PerViewLayout;
                    if (viewLayout != null)
                    {
                        var viewCount = RenderSystem.Views.Count;
                        if (viewLayout.Entries?.Length < viewCount)
                        {
                            // TODO: Should this be a first loop?
                            lock (viewLayout)
                            {
                                if (viewLayout.Entries?.Length < viewCount)
                                {
                                    var newEntries = new ResourceGroupEntry[viewCount];

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

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

                                    viewLayout.Entries = newEntries;
                                }
                            }
                        }

                        if (viewLayout.Entries[view.Index].MarkAsUsed(RenderSystem))
                        {
                            threadContext.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))
                    {
                        threadContext.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 = threadContext.ResourceGroupAllocator.AllocateResourceGroup();
                    if (renderEffectReflection.PerDrawLayout != null)
                    {
                        threadContext.ResourceGroupAllocator.PrepareResourceGroup(renderEffectReflection.PerDrawLayout, BufferPoolAllocationType.UsedOnce, renderNode.Resources);
                    }

                    // Create EffectObjectNode
                    var effectObjectNodeIndex = EffectObjectNodes.Add(new EffectObjectNode(renderEffect, viewObjectNode.ObjectNode));

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

                    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, threadContext.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 mutablePipelineState = batch.MutablePipelineState;
                        var pipelineState        = mutablePipelineState.State;
                        pipelineState.SetDefaults();

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

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

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

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

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

                    RenderNodes[renderNodeReference.Index] = renderNode;
                });

                viewFeature.RenderNodes.Close();
                viewFeature.Layouts.Close();
            }

            EffectObjectNodes.Close();
            FrameLayouts.Close();
        }
예제 #6
0
 protected override void ActivateOutputCore(RenderDrawContext context, RenderFrame output, bool disableDepth)
 {
     base.ActivateOutputCore(context, output, disableDepth);
     context.CommandList.SetViewport(ComputedViewport);
 }
예제 #7
0
 public PrepareThreadContext(RenderContext renderContext)
 {
     MutablePipelineState = new MutablePipelineState(renderContext.GraphicsDevice);
     Context = renderContext.GetThreadContext();
 }
예제 #8
0
        /// <param name="context"></param>
        /// <inheritdoc/>
        public override void PrepareEffectPermutations(RenderDrawContext context)
        {
            base.PrepareEffectPermutations(context);

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

            Dispatcher.ForEach(RenderSystem.Views, view =>
            {
                var viewFeature = view.Features[Index];
                Dispatcher.ForEach(viewFeature.RenderNodes, renderNodeReference =>
                {
                    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);

            // Step2: Compile effects
            Dispatcher.ForEach(RenderObjects, renderObject =>
            {
                //var renderObject = RenderObjects[index];
                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)
                    {
                        continue;
                    }

                    // Skip reflection update unless a state change requires it
                    renderEffect.IsReflectionUpdateRequired = false;

                    if (!renderEffect.IsUsedDuringThisFrame(RenderSystem))
                    {
                        continue;
                    }

                    // Skip if nothing changed
                    if (renderEffect.EffectValidator.ShouldSkip)
                    {
                        // Reset pending effect, as it is now obsolete anyway
                        renderEffect.Effect = null;
                        renderEffect.State  = RenderEffectState.Skip;
                    }
                    else if (renderEffect.EffectValidator.EndEffectValidation() && (renderEffect.Effect == null || !renderEffect.Effect.SourceChanged))
                    {
                        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;
                            renderEffect.Effect = ComputeFallbackEffect?.Invoke(renderObject, renderEffect, RenderEffectState.Error);
                        }
                        else
                        {
                            renderEffect.State  = RenderEffectState.Normal;
                            renderEffect.Effect = pendingEffect.Result;
                        }
                        renderEffect.PendingEffect = null;
                    }
                    else
                    {
                        // Reset pending effect, as it is now obsolete anyway
                        renderEffect.PendingEffect = null;
                        renderEffect.State         = RenderEffectState.Normal;

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

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

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

                        renderEffect.Effect = asyncEffect.Result;
                        if (renderEffect.Effect == null)
                        {
                            // Effect still compiling, let's find if there is a fallback
                            renderEffect.ClearFallbackParameters();
                            renderEffect.Effect        = ComputeFallbackEffect?.Invoke(renderObject, renderEffect, RenderEffectState.Compiling);
                            renderEffect.PendingEffect = asyncEffect.Task;
                            renderEffect.State         = RenderEffectState.Compiling;
                        }
                    }

                    renderEffect.IsReflectionUpdateRequired = true;
                }
            });

            // Step3: Uupdate 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.IsReflectionUpdateRequired)
                    {
                        continue;
                    }

                    var effect = renderEffect.Effect;
                    if (effect == null && renderEffect.State == RenderEffectState.Compiling)
                    {
                        // Need to wait for completion
                        renderEffect.Effect = effect = renderEffect.PendingEffect.Result;
                        renderEffect.State  = RenderEffectState.Normal;
                    }

                    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], renderEffect.State);
                            renderEffectReflection.PerFrameLayout = CreateFrameResourceGroupLayout(renderEffectReflection.ResourceGroupDescriptions[perFrameDescriptorSetSlot.Index], renderEffect.State);
                            renderEffectReflection.PerViewLayout  = CreateViewResourceGroupLayout(renderEffectReflection.ResourceGroupDescriptions[perViewDescriptorSetSlot.Index], renderEffect.State);

                            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;
                    }
                }
            }
        }
예제 #9
0
        public void Draw(RenderDrawContext renderDrawContext, RenderView renderView, RenderStage renderStage)
        {
            // Sync point: draw (from now, we should execute with a graphics device context to perform rendering)

            // Look for the RenderViewStage corresponding to this RenderView | RenderStage combination
            var renderViewStage = RenderViewStage.Invalid;

            foreach (var currentRenderViewStage in renderView.RenderStages)
            {
                if (currentRenderViewStage.Index == renderStage.Index)
                {
                    renderViewStage = currentRenderViewStage;
                    break;
                }
            }

            if (renderViewStage.Index == -1)
            {
                throw new InvalidOperationException("Requested RenderView|RenderStage combination doesn't exist. Please add it to RenderView.RenderStages.");
            }

            // Perform updates once per change of RenderView
            foreach (var renderFeature in RenderFeatures)
            {
                renderFeature.Draw(renderDrawContext, renderView, renderViewStage);
            }

            // Generate and execute draw jobs
            var renderNodes     = renderViewStage.SortedRenderNodes;
            var renderNodeCount = renderViewStage.RenderNodes.Count;

            if (renderNodeCount == 0)
            {
                return;
            }

            if (!GraphicsDevice.IsDeferred)
            {
                int currentStart, currentEnd;
                for (currentStart = 0; currentStart < renderNodeCount; currentStart = currentEnd)
                {
                    var currentRenderFeature = renderNodes[currentStart].RootRenderFeature;
                    currentEnd = currentStart + 1;
                    while (currentEnd < renderNodeCount && renderNodes[currentEnd].RootRenderFeature == currentRenderFeature)
                    {
                        currentEnd++;
                    }

                    // Divide into task chunks for parallelism
                    currentRenderFeature.Draw(renderDrawContext, renderView, renderViewStage, currentStart, currentEnd);
                }
            }
            else
            {
                // Create at most one batch per processor
                int batchCount = Math.Min(Environment.ProcessorCount, renderNodeCount);
                int batchSize  = (renderNodeCount + (batchCount - 1)) / batchCount;
                batchCount = (renderNodeCount + (batchSize - 1)) / batchSize;

                // Remember state
                var depthStencilBuffer = renderDrawContext.CommandList.DepthStencilBuffer;
                int renderTargetCount  = renderDrawContext.CommandList.RenderTargetCount;
                if (renderTargets == null)
                {
                    renderTargets = new Texture[renderDrawContext.CommandList.RenderTargets.Length];
                }
                for (int i = 0; i < renderTargetCount; ++i)
                {
                    renderTargets[i] = renderDrawContext.CommandList.RenderTargets[i];
                }
                var viewport = renderDrawContext.CommandList.Viewport;
                var scissor  = renderDrawContext.CommandList.Scissor;

                // Collect one command list per batch and the main one up to this point
                if (commandLists == null || commandLists.Length < batchCount + 1)
                {
                    Array.Resize(ref commandLists, batchCount + 1);
                }
                commandLists[0] = renderDrawContext.CommandList.Close();

                Dispatcher.For(0, batchCount, () => renderDrawContext.RenderContext.GetThreadContext(), (batchIndex, threadContext) =>
                {
                    threadContext.CommandList.Reset();
                    threadContext.CommandList.ClearState();

                    // Transfer state to all command lists
                    threadContext.CommandList.SetRenderTargets(depthStencilBuffer, renderTargetCount, renderTargets);
                    threadContext.CommandList.SetViewport(viewport);
                    threadContext.CommandList.SetScissorRectangle(scissor);

                    var currentStart = batchSize * batchIndex;
                    int currentEnd;

                    var endExclusive = Math.Min(renderNodeCount, currentStart + batchSize);

                    if (endExclusive <= currentStart)
                    {
                        return;
                    }

                    for (; currentStart < endExclusive; currentStart = currentEnd)
                    {
                        var currentRenderFeature = renderNodes[currentStart].RootRenderFeature;
                        currentEnd = currentStart + 1;
                        while (currentEnd < endExclusive && renderNodes[currentEnd].RootRenderFeature == currentRenderFeature)
                        {
                            currentEnd++;
                        }

                        // Divide into task chunks for parallelism
                        currentRenderFeature.Draw(threadContext, renderView, renderViewStage, currentStart, currentEnd);
                    }

                    commandLists[batchIndex + 1] = threadContext.CommandList.Close();
                });

                GraphicsDevice.ExecuteCommandLists(batchCount + 1, commandLists);

                renderDrawContext.CommandList.Reset();
                renderDrawContext.CommandList.ClearState();

                // Reapply previous state
                renderDrawContext.CommandList.SetRenderTargets(depthStencilBuffer, renderTargetCount, renderTargets);
                renderDrawContext.CommandList.SetViewport(viewport);
                renderDrawContext.CommandList.SetScissorRectangle(scissor);
            }
        }
예제 #10
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(RenderDrawContext 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
            Dispatcher.ForEach(Views, view =>
            {
                Dispatcher.For(0, view.RenderStages.Count, () => prepareThreadLocals.Acquire(), (index, local) =>
                {
                    var renderViewStage = view.RenderStages[index];

                    var renderNodes = renderViewStage.RenderNodes;
                    if (renderNodes.Count == 0)
                    {
                        return;
                    }

                    var renderStage       = RenderStages[renderViewStage.Index];
                    var sortedRenderNodes = renderViewStage.SortedRenderNodes;

                    // Fast clear, since it's cleared properly in Reset()
                    sortedRenderNodes.Resize(renderViewStage.RenderNodes.Count, true);

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

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

                        Dispatcher.Sort(local.SortKeys, 0, renderNodes.Count, Comparer <SortKey> .Default);

                        // Reorder list
                        for (int i = 0; i < renderNodes.Count; ++i)
                        {
                            sortedRenderNodes[i] = renderNodes[local.SortKeys[i].Index];
                        }
                    }
                    else
                    {
                        // No sorting, copy as is
                        for (int i = 0; i < renderNodes.Count; ++i)
                        {
                            sortedRenderNodes[i] = renderNodes[i];
                        }
                    }
                }, state => prepareThreadLocals.Release(state));
            });

            // Flush the resources uploaded during Prepare
            context.ResourceGroupAllocator.Flush();
            context.RenderContext.Flush();
        }
예제 #11
0
 protected virtual void PostDrawCore(RenderDrawContext context)
 {
 }
예제 #12
0
 /// <summary>
 /// Draws a full screen quad using iterating on each pass of this effect.
 /// </summary>
 public void Draw(RenderDrawContext context, string nameFormat, params object[] args)
 {
     // TODO: this is alocating a string, we should try to not allocate here.
     Draw(context, name: string.Format(nameFormat, args));
 }
예제 #13
0
 /// <summary>
 /// Activates the output to the current <see cref="GraphicsDevice" />.
 /// </summary>
 /// <param name="context">The context.</param>
 /// <param name="output">The output.</param>
 /// <param name="disableDepth">if set to <c>true</c> [disable depth].</param>
 protected virtual void ActivateOutputCore(RenderDrawContext context, RenderFrame output, bool disableDepth)
 {
     // Setup the render target
     context.CommandList.SetRenderTargetsAndViewport(disableDepth ? null : output.DepthStencil, output.RenderTargets);
 }