Пример #1
0
        public unsafe void TestClearRenderTargetWithWindow()
        {
            Window renderTargetWindow = new Window("Test window");

            RenderTargetViewHandle outRTV;
            DepthStencilViewHandle outDSV;

            renderTargetWindow.GetWindowRTVAndDSV(out outRTV, out outDSV);

            RenderCommand testCommand = RenderCommand.ClearRenderTarget(renderTargetWindow);

            Assert.AreEqual(RenderCommandInstruction.ClearRenderTarget, testCommand.Instruction);
            Assert.AreEqual(
                outRTV,
                UnsafeUtils.Reinterpret <IntPtr, RenderTargetViewHandle>(new IntPtr(UnsafeUtils.Reinterpret <RenderCommandArgument, long>(testCommand.Arg1, sizeof(long))), sizeof(RenderTargetViewHandle))
                );

            renderTargetWindow.Close();

            LosgapSystem.InvokeOnMaster(() => { });             // Wait for the window to be closed

            testCommand = RenderCommand.ClearRenderTarget(renderTargetWindow);
            Assert.AreEqual(RenderCommandInstruction.NoOperation, testCommand.Instruction);

#if !DEVELOPMENT && !RELEASE
            try {
                RenderCommand.ClearRenderTarget(null as Window);
                Assert.Fail();
            }
            catch (AssuranceFailedException) { }
#endif
        }
Пример #2
0
        public void TestClearRenderTarget()
        {
            Texture2D <TexelFormat.RenderTarget> renderTarget = TextureFactory.NewTexture2D <TexelFormat.RenderTarget>()
                                                                .WithWidth(800U)
                                                                .WithHeight(600U)
                                                                .WithDynamicDetail(false)
                                                                .WithMipAllocation(false)
                                                                .WithMipGenerationTarget(false)
                                                                .WithMultisampling(false)
                                                                .WithPermittedBindings(GPUBindings.RenderTarget)
                                                                .WithUsage(ResourceUsage.Write);

            RenderTargetView rtv = renderTarget.CreateRenderTargetView(0U);

            RenderCommand testCommand = RenderCommand.ClearRenderTarget(rtv);

            Assert.AreEqual(RenderCommandInstruction.ClearRenderTarget, testCommand.Instruction);
            Assert.AreEqual((RenderCommandArgument)(IntPtr)(ResourceViewHandle)rtv.ResourceViewHandle, testCommand.Arg1);

#if !DEVELOPMENT && !RELEASE
            try {
                RenderCommand.ClearRenderTarget(null as RenderTargetView);
                Assert.Fail();
            }
            catch (AssuranceFailedException) { }
#endif

            rtv.Dispose();
            renderTarget.Dispose();

#if !DEVELOPMENT && !RELEASE
            try {
                RenderCommand.ClearRenderTarget(rtv);
                Assert.Fail();
            }
            catch (AssuranceFailedException) { }
#endif
        }
Пример #3
0
        protected internal override void Execute(ParallelizationProvider pp)
        {
            // See if we need to resize the light plane and get the new GBuffer
            Camera        input;
            SceneViewport output;

            Texture2D <TexelFormat.RGBA32Float>[] currentGBuffer;
            geometryPass.GetLightPassParameters(out currentGBuffer, out input, out output);
            Vector2 outputSizePixels = output.SizePixels;

            if (outputSizePixels.X <= 0f || outputSizePixels.Y <= 0f)
            {
                return;
            }
            RenderTargetViewHandle windowRTV; DepthStencilViewHandle windowDSV;
            bool windowStillOpen = output.TargetWindow.GetWindowRTVAndDSV(out windowRTV, out windowDSV);

            if (!windowStillOpen)
            {
                return;
            }
            CheckGeometryPassParameters(currentGBuffer, outputSizePixels);

            // Clear the bloom textures
            QueueRenderCommand(RenderCommand.ClearRenderTarget(preBloomBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(reducedBloomBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(bloomTargetBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(nonDepthOfFieldBackBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(reducedNonDepthOfFieldBackBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(depthOfFieldBackBufferRTV));
            QueueRenderCommand(RenderCommand.ClearDepthStencil(bloomResizeCopyDSDSV));
            QueueRenderCommand(RenderCommand.ClearDepthStencil(dsThrowawayBufferDSV));

            // Set topology
            QueueRenderCommand(RenderCommand.SetPrimitiveTopology(RenderCommand.DEFAULT_PRIMITIVE_TOPOLOGY));

            // Set input layout
            QueueRenderCommand(RenderCommand.SetInputLayout(lightPlaneInputLayout));

            // Enqueue VS commands
            QueueShaderSwitch(dlLightVS);
            QueueShaderResourceUpdate(dlLightVS, vsResPackage);

            /* =======================================
             * STAGE: DYNAMIC LIGHTING APPLICATION
             * ======================================= */

            // Enqueue FS commands
            Vector4 cameraPos = input.Position;

            ((ConstantBufferBinding)dlLightFS.GetBindingByIdentifier("CameraProperties")).SetValue((byte *)(&cameraPos));
            QueueShaderSwitch(dlLightFS);

            // Set rasterizer state
            QueueRenderCommand(RenderCommand.SetRasterizerState(rsState));
            QueueRenderCommand(RenderCommand.SetViewport(output));

            // Set depth stencil state
            QueueRenderCommand(RenderCommand.SetDepthStencilState(dsState));

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(blendState));

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(dsThrowawayBufferDSV.ResourceViewHandle, nonDepthOfFieldBackBufferRTV.ResourceViewHandle, preBloomBufferRTV.ResourceViewHandle));

            // Draw lights
            //input = new Camera();
            //input.Position = Vector3.ZERO;
            //input.Orient(Vector3.FORWARD, Vector3.UP);

            var frustum            = input.GetFrustum(output);
            int numLights          = addedLights.Count;
            int numLightsInFrustum = 0;

            for (int i = 0; i < numLights; ++i)
            {
                if (!frustum.IsWithinFrustum(new Sphere(addedLights[i].Position, addedLights[i].Radius)))
                {
                    continue;
                }
                lightPropsWorkspace[numLightsInFrustum++] = addedLights[i].Properties;
            }
            if (numLightsInFrustum > dynamicLightCap)
            {
                dynamicLightComparer.CameraPosition = input.Position;
                Array.Sort(lightPropsWorkspace, 0, numLightsInFrustum, dynamicLightComparer);
                numLightsInFrustum = dynamicLightCap;
            }

            Buffer <LightProperties> lightBuffer = (Buffer <LightProperties>)(((ResourceViewBinding)dlLightFS.GetBindingByIdentifier("LightBuffer")).GetBoundResource().Resource);
            var lightMetaCBuffer = (ConstantBufferBinding)dlLightFS.GetBindingByIdentifier("LightMeta");

            QueueShaderResourceUpdate(dlLightFS, fsResPackage);

            Array.Clear(perTileLightPropCounts, 0, perTileLightPropCounts.Length);



            Vector3 upDir          = input.UpDirection;
            Vector3 downDir        = -input.UpDirection;
            Vector3 rightDir       = upDir.Cross(input.Orientation);
            Vector3 leftDir        = -rightDir;
            var     worldToProjMat = (*((Matrix *)input.GetRecalculatedViewMatrix()) * *((Matrix *)output.GetRecalculatedProjectionMatrix(input)));

            for (int i = 0; i < numLightsInFrustum; ++i)
            {
                var lightProps = lightPropsWorkspace[i];
                //lightProps = new LightProperties(
                //	Vector3.LEFT + Vector3.BACKWARD, 3f, Vector3.ONE
                //);
                var lightCentre    = lightProps.Position;
                var lightTop       = new Vector4(lightCentre + upDir * lightProps.Radius, w: 1f);
                var lightBottom    = new Vector4(lightCentre + downDir * lightProps.Radius, w: 1f);
                var lightLeftmost  = new Vector4(lightCentre + leftDir * lightProps.Radius, w: 1f);
                var lightRightmost = new Vector4(lightCentre + rightDir * lightProps.Radius, w: 1f);

                var lightTopProjspace       = lightTop * worldToProjMat;
                var lightBottomProjspace    = lightBottom * worldToProjMat;
                var lightLeftmostProjspace  = lightLeftmost * worldToProjMat;
                var lightRightmostProjspace = lightRightmost * worldToProjMat;

                var lightTopScreenSpace       = lightTopProjspace / Math.Abs(lightTopProjspace.W);
                var lightBottomScreenSpace    = lightBottomProjspace / Math.Abs(lightBottomProjspace.W);
                var lightLeftmostScreenSpace  = lightLeftmostProjspace / Math.Abs(lightLeftmostProjspace.W);
                var lightRightmostScreenSpace = lightRightmostProjspace / Math.Abs(lightRightmostProjspace.W);

                var xMin = ((float)MathUtils.Clamp(lightLeftmostScreenSpace.X, -1f, 1f) + 1f) * 0.5f;
                var xMax = ((float)MathUtils.Clamp(lightRightmostScreenSpace.X, -1f, 1f) + 1f) * 0.5f;
                var yMin = ((float)MathUtils.Clamp(lightBottomScreenSpace.Y, -1f, 1f) + 1f) * 0.5f;
                var yMax = ((float)MathUtils.Clamp(lightTopScreenSpace.Y, -1f, 1f) + 1f) * 0.5f;

                for (int x = 0; x < LIGHTING_TILE_GRANULARITY; ++x)
                {
                    for (int y = 0; y < LIGHTING_TILE_GRANULARITY; ++y)
                    {
                        var tileXMin = tileOffsetsX[x];
                        var tileXMax = tileOffsetsX[x + 1];
                        var tileYMin = tileOffsetsY[y];
                        var tileYMax = tileOffsetsY[y + 1];

                        if (xMax < tileXMin ||
                            xMin > tileXMax ||
                            yMax < tileYMin ||
                            yMin > tileYMax)
                        {
                            continue;
                        }

                        var bucketIndex = x * LIGHTING_TILE_GRANULARITY + y;
                        perTileLightPropsWorkspace[bucketIndex][perTileLightPropCounts[bucketIndex]++] = lightProps;
                    }
                }
            }

            for (int x = 0; x < LIGHTING_TILE_GRANULARITY; ++x)
            {
                for (int y = 0; y < LIGHTING_TILE_GRANULARITY; ++y)
                {
                    var bucketIndex         = x * LIGHTING_TILE_GRANULARITY + y;
                    var numLightsOnThisTile = perTileLightPropCounts[bucketIndex];

                    if (numLightsOnThisTile == 0)
                    {
                        continue;
                    }

                    var scalars = new Vector4(tileOffsetsX[x], tileOffsetsX[x + 1], tileOffsetsY[y], tileOffsetsY[y + 1]);                     // 0f to 1f, from bottom left corner
                    QueueRenderCommand(RenderCommand.DiscardWriteShaderConstantBuffer(
                                           lightBuffer,
                                           new ArraySlice <LightProperties>(perTileLightPropsWorkspace[bucketIndex], 0U, (uint)numLightsOnThisTile),
                                           (uint)sizeof(LightProperties)
                                           ));
                    int *numLightsWithPadding = stackalloc int[4];
                    numLightsWithPadding[0] = numLightsOnThisTile;

                    QueueRenderCommand(RenderCommand.DiscardWriteShaderConstantBuffer(lightMetaCBuffer, (IntPtr)(numLightsWithPadding)));

                    QueueRenderCommand(RenderCommand.DiscardWriteShaderConstantBuffer(lightVSScalarsBufferBinding, (IntPtr)(&scalars)));
                    QueueRenderCommand(RenderCommand.Draw(0, 3U));
                    QueueRenderCommand(RenderCommand.Draw(3, 3U));
                }
            }



            // Unbind gbuffer
            QueueShaderResourceUpdate(dlLightFS, fsUnbindResPackage);

            /* =======================================
             * STAGE: ADD AMBIENT LIGHT (DL FINAL)
             * ======================================= */

            // Switch to finalization shader
            var scalarsFinal = new Vector4(0f, 1f, 0f, 1f);

            QueueRenderCommand(RenderCommand.DiscardWriteShaderConstantBuffer(lightVSScalarsBufferBinding, (IntPtr)(&scalarsFinal)));
            QueueShaderSwitch(dlFinalFS);
            QueueShaderResourceUpdate(dlFinalFS, finalizationShaderResPackage);

            // Draw finalization triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(dlFinalFS, finalizationShaderUnbindResPackage);

            /* =======================================
             * STAGE: OUTLINING
             * ======================================= */

            // Switch to outlining shader
            QueueShaderSwitch(outliningShader);
            QueueShaderResourceUpdate(outliningShader, outliningShaderResPackage);

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(outliningBlendState));

            // Draw outlining triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(outliningShader, outliningShaderUnbindResPackage);

            /* =======================================
             * STAGE: DOWNSCALE PRE-BLOOM BUFFER TEX
             * ======================================= */

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(bloomResizeCopyDSDSV, reducedBloomBufferRTV));

            // Switch to copy shader
            QueueShaderSwitch(copyShader);
            QueueShaderResourceUpdate(copyShader, copyShaderResPackage);

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(blendState));

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(copyShader, copyShaderUnbindResPackage);

            /* =======================================
             * STAGE: BLOOM RENDER TO BLOOM TARGET
             * ======================================= */

            // Clear DSV
            QueueRenderCommand(RenderCommand.ClearDepthStencil(bloomResizeCopyDSDSV));

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(bloomResizeCopyDSDSV, bloomTargetBufferRTV));

            // Switch to bloom H shader
            QueueShaderSwitch(bloomHShader);
            QueueShaderResourceUpdate(bloomHShader, bloomHShaderResPackage);

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(bloomHShader, bloomHShaderUnbindResPackage);

            // Switch to bloom V shader
            QueueShaderSwitch(bloomVShader);
            QueueShaderResourceUpdate(bloomVShader, bloomVShaderResPackage);

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(bloomVShader, bloomVShaderUnbindResPackage);

            /* =======================================
             * STAGE: COPY BLOOM RESULT ON TO NON-DoF BUFFER
             * ======================================= */

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(dsThrowawayBufferDSV.ResourceViewHandle, nonDepthOfFieldBackBufferRTV));

            // Switch to reverse copy shader
            QueueShaderSwitch(copyReverseShader);
            QueueShaderResourceUpdate(copyReverseShader, copyReverseShaderResPackage);

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(copyReverseShader, copyReverseShaderUnbindResPackage);

            /* =======================================
             * STAGE: DOWNSCALE NON-DoF SCENE
             * ======================================= */

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(bloomResizeCopyDSDSV, reducedNonDepthOfFieldBackBufferRTV));

            // Switch to copy shader
            QueueShaderSwitch(copyShader);
            QueueShaderResourceUpdate(copyShader, copyDoFShaderResPackage);

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(blendState));

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(copyShader, copyDoFShaderUnbindResPackage);

            /* =======================================
             * STAGE: BLUR NON-DoF SCENE
             * ======================================= */

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(bloomResizeCopyDSDSV, depthOfFieldBackBufferRTV));

            // Switch to copy shader
            QueueShaderSwitch(blurShader);
            QueueShaderResourceUpdate(blurShader, blurShaderResPackage);

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(blendState));

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(blurShader, blurShaderUnbindResPackage);

            /* =======================================
             * STAGE: RENDER TO BACK BUFFER WITH DoF SELECTION
             * ======================================= */

            // Set up output merger
            QueueRenderCommand(RenderCommand.SetRenderTargets(windowDSV, windowRTV));

            // Switch to copy shader
            QueueShaderSwitch(dofShader);
            QueueShaderResourceUpdate(dofShader, dofShaderResPackage);

            // Set blend state
            QueueRenderCommand(RenderCommand.SetBlendState(blendState));

            // Draw fullscreen triangles
            QueueRenderCommand(RenderCommand.Draw(0, 3U));
            QueueRenderCommand(RenderCommand.Draw(3, 3U));

            // Unbind resources
            QueueShaderResourceUpdate(dofShader, dofShaderUnbindResPackage);



            // Flush + present
            FlushRenderCommands();
            if (presentAfterPass)
            {
                PresentBackBuffer(output.TargetWindow);
            }
        }
        protected internal override void Execute(ParallelizationProvider pp)
        {
            for (int i = 0; i < NUM_GBUFFER_TEXTURES; ++i)
            {
                if (gBufferViews[i] != null)
                {
                    QueueRenderCommand(RenderCommand.ClearRenderTarget(gBufferViews[i]));
                }
            }
            if (clearOutputBeforePass)
            {
                QueueRenderCommand(RenderCommand.ClearRenderTarget(output.TargetWindow));
                QueueRenderCommand(RenderCommand.ClearDepthStencil(output.TargetWindow));
            }

            Vector2 outputSizePixels = output.SizePixels;

            if (gBuffer[0] == null || gBuffer[0].Width != (uint)outputSizePixels.X || gBuffer[0].Height != (uint)outputSizePixels.Y)
            {
                for (int i = 0; i < NUM_GBUFFER_TEXTURES; ++i)
                {
                    if (gBufferViews[i] != null)
                    {
                        gBufferViews[i].Dispose();
                    }
                    if (gBuffer[i] != null)
                    {
                        gBuffer[i].Dispose();
                    }
                    gBuffer[i]      = gBufferBuilder.WithWidth((uint)outputSizePixels.X).WithHeight((uint)outputSizePixels.Y);
                    gBufferViews[i] = gBuffer[i].CreateRenderTargetView(0U);
                }
            }
            if (primaryDSBuffer == null || primaryDSBuffer.Width != outputSizePixels.X || primaryDSBuffer.Height != outputSizePixels.Y)
            {
                if (primaryDSBuffer != null)
                {
                    primaryDSBuffer.Dispose();
                }
                if (primaryDSBufferDSV != null)
                {
                    primaryDSBufferDSV.Dispose();
                }
                if (primaryDSBufferSRV != null)
                {
                    primaryDSBufferSRV.Dispose();
                }

                primaryDSBuffer    = dsBufferBuilder.WithWidth((uint)outputSizePixels.X).WithHeight((uint)outputSizePixels.Y);
                primaryDSBufferDSV = primaryDSBuffer.CreateDepthStencilView <TexelFormat.DepthStencil>(0U);
                primaryDSBufferSRV = primaryDSBuffer.CreateView <TexelFormat.R24UnormX8Typeless>(0U, 1U);
            }
            previousShadowBufferSRV = shadowPass.ShadowBufferSRV;

            // Clear main DSV
            QueueRenderCommand(RenderCommand.ClearDepthStencil(primaryDSBufferDSV));

            List <GeometryCache> activeCaches = GeometryCache.ActiveCaches;

            foreach (GeometryCache c in activeCaches)
            {
                if (!deferredGeometryVertexShaders.ContainsKey(c))
                {
                    continue;
                }
                currentVS = deferredGeometryVertexShaders[c];

                // Set view/proj matrices
                var vpMatrices = new GeomPassProjViewMatrices {
                    MainCameraVPMat   = (*((Matrix *)Input.GetRecalculatedViewMatrix()) * *((Matrix *)Output.GetRecalculatedProjectionMatrix(Input))).Transpose,
                    ShadowCameraVPMat = (*((Matrix *)shadowPass.LightCam.GetRecalculatedViewMatrix()) * *((Matrix *)Output.GetRecalculatedProjectionMatrix(shadowPass.LightCam))).Transpose
                };
                byte *vpMatPtr = (byte *)&vpMatrices;
                currentVS.ViewProjMatBinding.SetValue(vpMatPtr);

                // Set state for current cache
                cpuInstanceBufferCurIndex = 0;
                List <SceneLayer> allEnabledLayers = Scene.EnabledLayers;
                uint maxLayer = 0U;
                for (int i = 0; i < allEnabledLayers.Count; ++i)
                {
                    if (allEnabledLayers[i].Index > maxLayer)
                    {
                        maxLayer = allEnabledLayers[i].Index;
                    }
                }
                if (allEnabledLayers.Count > 0 && currentSceneLayers.Length <= maxLayer)
                {
                    currentSceneLayers = new SceneLayer[maxLayer + 1U];
                }
                Array.Clear(currentSceneLayers, 0, currentSceneLayers.Length);
                foreach (SceneLayer layer in allEnabledLayers)
                {
                    currentSceneLayers[layer.Index] = layer;
                }
                currentCache = c;
                ++frameNum;
                Thread.MemoryBarrier();
                currentInstanceData = currentCache.GetModelInstanceData();

                // Set up each thread
                pp.InvokeOnAll(setUpCacheForLocalThreadAct, true);                 // membar here

                // Iterate all model instances (ordered by material)
                pp.Execute((int)currentInstanceData.Length, (int)(currentInstanceData.Length / (pp.NumThreads << 3)) + 1, renderCacheIterateMatAct);

                // Set instance buffer and write to it
                if (gpuInstanceBuffer == null || gpuInstanceBuffer.Length < cpuInstanceBuffer.Length)
                {
                    if (gpuInstanceBuffer != null)
                    {
                        gpuInstanceBuffer.Dispose();
                    }
                    gpuInstanceBuffer = gpuInstanceBufferBuilder.WithLength((uint)cpuInstanceBuffer.Length).Create();
                }
                gpuInstanceBuffer.DiscardWrite(cpuInstanceBuffer);                 // Happens immediately (required)

                // Unbind shadow buffer
                QueueShaderSwitch(geomFSWithShadowSupport);
                QueueShaderResourceUpdate(geomFSWithShadowSupport, geomFSShadowUnbindPackage);

                // Set instance buffer and flush all commands, first on immediate context, then on each deferred
                SetInstanceBufferAndFlushCommands();
                pp.InvokeOnAll(setInstanceBufferAndFlushCommandsAct, false);
            }
        }
        protected internal override void Execute(ParallelizationProvider pp)
        {
            // Set up buffers
            if (!output.TargetWindow.GetWindowRTVAndDSV(out windowRTVH, out windowDSVH))
            {
                return;
            }
            Vector2 viewportSizePixels = output.TargetWindow.AddedViewports.First().SizePixels;

            if (viewportSizePixels.X <= 0f || viewportSizePixels.Y <= 0f)
            {
                return;
            }
            SetUpBuffers(viewportSizePixels);

            // Clear pre-glow buffer
            QueueRenderCommand(RenderCommand.ClearRenderTarget(preGlowTargetBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(glowSrcBufferRTV));
            QueueRenderCommand(RenderCommand.ClearRenderTarget(glowDstBufferRTV));

            List <GeometryCache> activeCaches = GeometryCache.ActiveCaches;

            foreach (GeometryCache c in activeCaches)
            {
                // Set view/proj matrix
                Matrix vpMat    = (*((Matrix *)Input.GetRecalculatedViewMatrix()) * *((Matrix *)Output.GetRecalculatedProjectionMatrix(Input))).Transpose;
                byte * vpMapPtr = (byte *)&vpMat;
                VertexShader.ViewProjMatBinding.SetValue(vpMapPtr);

                // Set state for current cache
                cpuInstanceBufferCurIndex = 0;
                List <SceneLayer> allEnabledLayers = Scene.EnabledLayers;
                uint maxLayer = 0U;
                for (int i = 0; i < allEnabledLayers.Count; ++i)
                {
                    if (allEnabledLayers[i].Index > maxLayer)
                    {
                        maxLayer = allEnabledLayers[i].Index;
                    }
                }
                if (allEnabledLayers.Count > 0 && currentSceneLayers.Length <= maxLayer)
                {
                    currentSceneLayers = new SceneLayer[maxLayer + 1U];
                }
                Array.Clear(currentSceneLayers, 0, currentSceneLayers.Length);
                foreach (SceneLayer layer in allEnabledLayers)
                {
                    currentSceneLayers[layer.Index] = layer;
                }
                currentCache = c;
                ++frameNum;
                Thread.MemoryBarrier();
                currentInstanceData = currentCache.GetModelInstanceData();

                // Set up each thread
                SetUpCacheForLocalThread();

                // Iterate all model instances (ordered by material && ZIndex)
                //if (instanceDataSortSpace.Length < currentInstanceData.Length) instanceDataSortSpace = new KeyValuePair<Material, ModelInstanceManager.MIDArray>[currentInstanceData.Length * 2];
                //for (int i = 0; i < currentInstanceData.Length; i += 2) {
                //	var a = currentInstanceData[i];
                //	if (currentInstanceData.Length == i + 1) {
                //		if (currentInstanceData.Length >= 3) {
                //			if (a.Key.ZIndex < instanceDataSortSpace[i - 2].Key.ZIndex) {
                //				instanceDataSortSpace[i] = instanceDataSortSpace[i - 1];
                //				instanceDataSortSpace[i - 1] = instanceDataSortSpace[i - 2];
                //				instanceDataSortSpace[i - 2] = a;
                //			}
                //			else if (a.Key.ZIndex < instanceDataSortSpace[i - 1].Key.ZIndex) {
                //				instanceDataSortSpace[i] = instanceDataSortSpace[i - 1];
                //				instanceDataSortSpace[i - 1] = a;
                //			}
                //			else instanceDataSortSpace[i] = a;
                //		}
                //		else instanceDataSortSpace[i] = a;
                //	}
                //	else {
                //		var b = currentInstanceData[i + 1];
                //		if (a.Key.ZIndex <= b.Key.ZIndex) {
                //			instanceDataSortSpace[i] = a;
                //			instanceDataSortSpace[i + 1] = b;
                //		}
                //		else {
                //			instanceDataSortSpace[i] = b;
                //			instanceDataSortSpace[i + 1] = a;
                //		}
                //	}
                //}
                Array.Sort(currentInstanceData.ContainingArray, 0, (int)currentInstanceData.Length, zIndexComparer);
                foreach (KeyValuePair <Material, ModelInstanceManager.MIDArray> material in currentInstanceData)
                {
                    for (int i = 0; i < currentInstanceData.Length; ++i)
                    {
                        if (currentInstanceData[i].Value == material.Value && currentInstanceData[i].Key == material.Key)
                        {
                            RenderCache_IterateMaterial(i);
                            break;
                        }
                    }
                }

                // Set instance buffer and write to it
                if (gpuInstanceBuffer == null || gpuInstanceBuffer.Length < cpuInstanceBuffer.Length)
                {
                    if (gpuInstanceBuffer != null)
                    {
                        gpuInstanceBuffer.Dispose();
                    }
                    gpuInstanceBuffer = gpuInstanceBufferBuilder.WithLength((uint)cpuInstanceBuffer.Length).Create();
                }
                gpuInstanceBuffer.DiscardWrite(cpuInstanceBuffer);                 // Happens immediately (required)

                // Set instance buffer and flush all commands, first on immediate context, then on each deferred
                SetInstanceBufferAndFlushCommands();
            }

            ///* =============================================
            // * PREPARE FOR GLOW
            // * ============================================= */

            //// Clear glow buffers
            //QueueRenderCommand(RenderCommand.ClearRenderTarget(glowSrcBufferRTV));

            //// Set blend state
            //QueueRenderCommand(RenderCommand.SetBlendState(glowBlendState));

            //// Set topology
            //QueueRenderCommand(RenderCommand.SetPrimitiveTopology(RenderCommand.DEFAULT_PRIMITIVE_TOPOLOGY));

            //// Set input layout
            //QueueRenderCommand(RenderCommand.SetInputLayout(glowPlaneInputLayout));

            //// Enqueue VS commands
            //QueueShaderSwitch(glowVS);
            //QueueShaderResourceUpdate(glowVS);

            ///* =============================================
            // * DOWNSCALE TO GLOW SRC BUFFER
            // * ============================================= */

            //// Set up output merger
            //QueueRenderCommand(RenderCommand.SetRenderTargets(glowDSBufferDSV, glowSrcBufferRTV));

            //// Switch to copy shader
            //QueueShaderSwitch(scaleDownShader);
            //QueueShaderResourceUpdate(scaleDownShader, scaleDownShaderResPkg);

            //// Draw fullscreen triangles
            //QueueRenderCommand(RenderCommand.Draw(0, 3U));
            //QueueRenderCommand(RenderCommand.Draw(3, 3U));

            //// Unbind resources
            //QueueShaderResourceUpdate(scaleDownShader, scaleDownShaderResUnbindPkg);

            ///* =============================================
            // * RENDER GLOW
            // * ============================================= */

            //// Set up output merger
            //QueueRenderCommand(RenderCommand.SetRenderTargets(glowDSBufferDSV, glowDstBufferRTV));

            //// Switch to glow shader
            //QueueShaderSwitch(glowShader);
            //QueueShaderResourceUpdate(glowShader, glowShaderVResPkg);

            //// Set blend state
            //QueueRenderCommand(RenderCommand.SetBlendState(dstMergeBlend));

            //// Draw fullscreen triangles
            //QueueRenderCommand(RenderCommand.Draw(0, 3U));
            //QueueRenderCommand(RenderCommand.Draw(3, 3U));

            //// Unbind resources
            //QueueShaderResourceUpdate(glowShader, glowShaderVResUnbindPkg);

            ///* =============================================
            // * UPSCALE TO BACK BUFFER
            // * ============================================= */

            //// Set up output merger
            //QueueRenderCommand(RenderCommand.SetRenderTargets(output.TargetWindow));

            //// Switch to copy shader
            //QueueShaderSwitch(scaleUpShader);
            //QueueShaderResourceUpdate(scaleUpShader, scaleUpShaderResPkg);

            //// Draw fullscreen triangles
            //QueueRenderCommand(RenderCommand.Draw(0, 3U));
            //QueueRenderCommand(RenderCommand.Draw(3, 3U));

            //// Unbind resources
            //QueueShaderResourceUpdate(scaleUpShader, scaleUpShaderResUnbindPkg);

            // Present
            FlushRenderCommands();
            if (presentAfterPass)
            {
                PresentBackBuffer(Output.TargetWindow);
            }
        }