예제 #1
0
        public override unsafe void Prepare(RenderDrawContext context)
        {
            var previousTransformationInfoData     = rootRenderFeature.RenderData.GetData(previousTransformationInfoKey);
            var previousTransformationViewInfoData = rootRenderFeature.RenderData.GetData(previousTransformationViewInfoKey);
            var renderModelObjectInfoData          = rootRenderFeature.RenderData.GetData(renderModelObjectInfoKey);

            // Calculate previous WVP matrix per view and object
            usageCounter++;
            for (int index = 0; index < RenderSystem.Views.Count; index++)
            {
                var view        = RenderSystem.Views[index];
                var viewFeature = view.Features[rootRenderFeature.Index];

                bool useView = false;
                foreach (var stage in RenderSystem.RenderStages)
                {
                    foreach (var renderViewStage in view.RenderStages)
                    {
                        if (renderViewStage.Index == stage.Index && stage.OutputValidator?.Find <VelocityTargetSemantic>() >= 0)
                        {
                            useView = true;
                            break;
                        }
                    }
                }
                if (!useView)
                {
                    continue;
                }

                // Cache per-view data locally
                RenderViewData viewData;
                if (!renderViewDatas.TryGetValue(view, out viewData))
                {
                    viewData = new RenderViewData();
                    renderViewDatas.Add(view, viewData);
                }

                Dispatcher.ForEach(viewFeature.ViewObjectNodes, renderPerViewNodeReference =>
                {
                    var renderPerViewNode    = rootRenderFeature.GetViewObjectNode(renderPerViewNodeReference);
                    var renderModelFrameInfo = renderModelObjectInfoData[renderPerViewNode.ObjectNode];

                    Matrix previousViewProjection = viewData.PreviousViewProjection;

                    Matrix previousWorldViewProjection;
                    Matrix.Multiply(ref renderModelFrameInfo.World, ref previousViewProjection, out previousWorldViewProjection);

                    previousTransformationViewInfoData[renderPerViewNodeReference] = new PreviousObjectViewInfo
                    {
                        WorldViewProjection = previousWorldViewProjection,
                    };
                });

                // Shift current view projection transform into previous
                viewData.PreviousViewProjection = view.ViewProjection;
                viewData.UsageCounter           = usageCounter;
                updatedViews.Add(view);
            }

            foreach (var view in renderViewDatas.Keys.ToArray())
            {
                if (!updatedViews.Contains(view))
                {
                    renderViewDatas.Remove(view);
                }
            }
            updatedViews.Clear();

            // Update cbuffer for previous WVP matrix
            Dispatcher.ForEach(((RootEffectRenderFeature)rootRenderFeature).RenderNodes, (ref RenderNode renderNode) =>
            {
                var perDrawLayout = renderNode.RenderEffect.Reflection.PerDrawLayout;
                if (perDrawLayout == null)
                {
                    return;
                }

                var previousWvpOffset = perDrawLayout.GetConstantBufferOffset(previousWorldViewProjection);
                if (previousWvpOffset == -1)
                {
                    return;
                }

                var mappedCB        = renderNode.Resources.ConstantBuffer.Data;
                var previousPerDraw = (PreviousPerDraw *)((byte *)mappedCB + previousWvpOffset);

                var renderModelFrameInfo         = renderModelObjectInfoData[renderNode.RenderObject.ObjectNode];
                var renderModelPreviousFrameInfo = previousTransformationViewInfoData[renderNode.ViewObjectNode];

                // Shift current world transform into previous transform
                previousTransformationInfoData[renderNode.RenderObject.StaticObjectNode] = new StaticObjectInfo
                {
                    World = renderModelFrameInfo.World,
                };

                previousPerDraw->PreviousWorldViewProjection = renderModelPreviousFrameInfo.WorldViewProjection;
            });
        }
예제 #2
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();
        }
예제 #3
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);
            }
        }
예제 #4
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));
 }