public unsafe void TestDepthStencilTargetWithWindow()
        {
            Window depthStencilWindow = new Window("Test window");

            RenderTargetViewHandle outRTV;
            DepthStencilViewHandle outDSV;

            depthStencilWindow.GetWindowRTVAndDSV(out outRTV, out outDSV);

            RenderCommand testCommand = RenderCommand.ClearDepthStencil(depthStencilWindow);

            Assert.AreEqual(RenderCommandInstruction.ClearDepthStencil, testCommand.Instruction);
            Assert.AreEqual(
                outDSV,
                UnsafeUtils.Reinterpret <IntPtr, DepthStencilViewHandle>(new IntPtr(UnsafeUtils.Reinterpret <RenderCommandArgument, long>(testCommand.Arg1, sizeof(long))), sizeof(DepthStencilViewHandle))
                );

            depthStencilWindow.Close();

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

            testCommand = RenderCommand.ClearDepthStencil(depthStencilWindow);
            Assert.AreEqual(RenderCommandInstruction.NoOperation, testCommand.Instruction);

#if !DEVELOPMENT && !RELEASE
            try {
                RenderCommand.ClearDepthStencil(null as Window);
                Assert.Fail();
            }
            catch (AssuranceFailedException) { }
#endif
        }
        public void TestClearDepthStencil()
        {
            Texture2D <TexelFormat.DepthStencil> depthStencilBuffer = TextureFactory.NewTexture2D <TexelFormat.DepthStencil>()
                                                                      .WithWidth(800U)
                                                                      .WithHeight(600U)
                                                                      .WithDynamicDetail(false)
                                                                      .WithMipAllocation(false)
                                                                      .WithMipGenerationTarget(false)
                                                                      .WithMultisampling(false)
                                                                      .WithPermittedBindings(GPUBindings.DepthStencilTarget)
                                                                      .WithUsage(ResourceUsage.Write);

            DepthStencilView dsv = depthStencilBuffer.CreateDepthStencilView(0U);

            RenderCommand testCommand = RenderCommand.ClearDepthStencil(dsv);

            Assert.AreEqual(RenderCommandInstruction.ClearDepthStencil, testCommand.Instruction);
            Assert.AreEqual((RenderCommandArgument)(IntPtr)(ResourceViewHandle)dsv.ResourceViewHandle, testCommand.Arg1);

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

            dsv.Dispose();
            depthStencilBuffer.Dispose();

#if !DEVELOPMENT && !RELEASE
            try {
                RenderCommand.ClearDepthStencil(dsv);
                Assert.Fail();
            }
            catch (AssuranceFailedException) { }
#endif
        }
Example #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);
            }
        }
Example #5
0
        protected internal unsafe override void Execute(ParallelizationProvider pp)
        {
            // See if we need to resize the depth buffer
            Vector2 viewportDimensions = output.SizePixels;

            if (viewportDimensions.X < 1f || viewportDimensions.Y < 1f)
            {
                return;
            }
            uint viewportX = (uint)viewportDimensions.X;
            uint viewportY = (uint)viewportDimensions.Y;

            if (shadowBuffer == null || shadowBufferDSV == null || shadowBufferDSV.ResourceOrViewDisposed ||
                shadowBufferSRV == null || shadowBufferSRV.ResourceOrViewDisposed ||
                shadowBuffer.Width != viewportX || shadowBuffer.Height != viewportY)
            {
                if (shadowBufferDSV != null && !shadowBufferDSV.IsDisposed)
                {
                    shadowBufferDSV.Dispose();
                }
                if (shadowBuffer != null && !shadowBuffer.IsDisposed)
                {
                    shadowBuffer.Dispose();
                }
                shadowBuffer    = shadowBufferBuilder.WithWidth(viewportX).WithHeight(viewportY);
                shadowBufferDSV = shadowBuffer.CreateDepthStencilView <TexelFormat.DepthStencil>(0U);
                shadowBufferSRV = shadowBuffer.CreateView <TexelFormat.R24UnormX8Typeless>(0U, 1U);
            }

            // Clear the depth buffer
            QueueRenderCommand(RenderCommand.ClearDepthStencil(shadowBufferDSV));

            List <GeometryCache> activeCaches = GeometryCache.ActiveCaches;

            foreach (GeometryCache c in activeCaches)
            {
                // Set view/proj matrix
                Matrix vpMat    = (*((Matrix *)lightCam.GetRecalculatedViewMatrix()) * *((Matrix *)Output.GetRecalculatedProjectionMatrix(lightCam))).Transpose;
                byte * vpMapPtr = (byte *)&vpMat;
                shadowVS.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
                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)

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