internal void GatherArray(RwTexId postprocessTarget, RwTexId cascadeArray, MyProjectionInfo[] cascadeInfo, ConstantsBufferId cascadeConstantBuffer)
        {
            if (!MyRenderProxy.Settings.EnableShadows)
                return;

            MarkCascadesInStencil(cascadeInfo);

            MyGpuProfiler.IC_BeginBlock("Cascades postprocess");

            MyRenderContext renderContext = MyRenderContext.Immediate;
            DeviceContext deviceContext = renderContext.DeviceContext;

            renderContext.SetCS(m_gatherCS);
            ComputeShaderId.TmpUav[0] = postprocessTarget.Uav;
            deviceContext.ComputeShader.SetUnorderedAccessViews(0, ComputeShaderId.TmpUav, ComputeShaderId.TmpCount);

            deviceContext.ComputeShader.SetShaderResource(0, MyRender11.MultisamplingEnabled ? MyScreenDependants.m_resolvedDepth.m_SRV_depth : MyGBuffer.Main.DepthStencil.m_SRV_depth);
            deviceContext.ComputeShader.SetShaderResource(1, MyGBuffer.Main.DepthStencil.m_SRV_stencil);
            deviceContext.ComputeShader.SetSampler(MyCommon.SHADOW_SAMPLER_SLOT, MyRender11.m_shadowmapSamplerState);
            deviceContext.ComputeShader.SetConstantBuffer(0, MyCommon.FrameConstants);
            deviceContext.ComputeShader.SetConstantBuffer(4, cascadeConstantBuffer);
            deviceContext.ComputeShader.SetShaderResource(MyCommon.CASCADES_SM_SLOT, cascadeArray.ShaderView);

            deviceContext.Dispatch(m_threadGroupCountX, m_threadGroupCountY, 1);

            ComputeShaderId.TmpUav[0] = null;
            renderContext.DeviceContext.ComputeShader.SetUnorderedAccessViews(0, ComputeShaderId.TmpUav, ComputeShaderId.TmpCount);
            deviceContext.ComputeShader.SetShaderResource(0, null);

            if(MyRender11.Settings.EnableShadowBlur)
                MyBlur.Run(postprocessTarget.Rtv, MyRender11.CascadesHelper.Rtv, MyRender11.CascadesHelper.ShaderView, postprocessTarget.ShaderView, depthDiscardThreshold: 0.2f);

            MyGpuProfiler.IC_EndBlock();
        }
        private unsafe void MarkCascadesInStencil(MyProjectionInfo[] cascadeInfo)
        {
            MyGpuProfiler.IC_BeginBlock("MarkCascadesInStencil");

            //RC.SetRS(MyRasterizerState.CullCW);

            MyRenderContext renderContext = MyRenderContext.Immediate;

            renderContext.DeviceContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
            renderContext.SetVB(0, m_cascadesBoundingsVertices.Buffer, m_cascadesBoundingsVertices.Stride);
            renderContext.SetIB(m_cubeIB.Buffer, m_cubeIB.Format);
            renderContext.SetIL(m_inputLayout);
            renderContext.DeviceContext.Rasterizer.SetViewport(0, 0, MyRender11.ViewportResolution.X, MyRender11.ViewportResolution.Y);
            renderContext.SetCB(MyCommon.FRAME_SLOT, MyCommon.FrameConstants);
            renderContext.BindDepthRT(MyGBuffer.Main.DepthStencil, DepthStencilAccess.DepthReadOnly, null);
            renderContext.SetVS(m_markVS);
            renderContext.SetPS(m_markPS);

            const int vertexCount = 8;

            Vector3D* frustumVerticesSS = stackalloc Vector3D[vertexCount];
            frustumVerticesSS[0] = new Vector3D(-1, -1, 0);
            frustumVerticesSS[1] = new Vector3D(-1, 1, 0);
            frustumVerticesSS[2] = new Vector3D(1, 1, 0);
            frustumVerticesSS[3] = new Vector3D(1, -1, 0);
            frustumVerticesSS[4] = new Vector3D(-1, -1, 1);
            frustumVerticesSS[5] = new Vector3D(-1, 1, 1);
            frustumVerticesSS[6] = new Vector3D(1, 1, 1);
            frustumVerticesSS[7] = new Vector3D(1, -1, 1);

            Vector3D* lightVertices = stackalloc Vector3D[vertexCount];
            Vector3* tmpFloatVertices = stackalloc Vector3[vertexCount];

            var mapping = MyMapping.MapDiscard(m_cascadesBoundingsVertices.Buffer);
            for (int cascadeIndex = 0; cascadeIndex < MyRender11.Settings.ShadowCascadeCount; ++cascadeIndex)
            {
                var inverseViewProj = MatrixD.Invert(cascadeInfo[cascadeIndex].CurrentLocalToProjection);
                for (int arrayIndex = 0; arrayIndex < vertexCount; ++arrayIndex)
                {
                    Vector3D.Transform(ref frustumVerticesSS[arrayIndex], ref inverseViewProj, out lightVertices[arrayIndex]);
                    tmpFloatVertices[arrayIndex] = lightVertices[arrayIndex];
                }

                for (int arrayIndex = 0; arrayIndex < vertexCount; ++arrayIndex )
                    mapping.WriteAndPosition(ref tmpFloatVertices[arrayIndex]);
            }
            mapping.Unmap();

            for (int cascadeIndex = 0; cascadeIndex < MyRender11.Settings.ShadowCascadeCount; ++cascadeIndex)
            {
                renderContext.SetDS(MyDepthStencilState.MarkIfInsideCascade[cascadeIndex], 1 << cascadeIndex);
                // mark ith bit on depth near
                renderContext.DeviceContext.DrawIndexed(36, 0, 8 * cascadeIndex);
            }

            renderContext.BindDepthRT(null, DepthStencilAccess.DepthReadOnly, null);

            renderContext.SetDS(null);
            renderContext.SetRS(null);

            MyGpuProfiler.IC_EndBlock();
        }
        internal void GatherArray(RwTexId postprocessTarget, RwTexId cascadeArray, MyProjectionInfo[] cascadeInfo, ConstantsBufferId cascadeConstantBuffer)
        {
            if (!MyRenderProxy.Settings.EnableShadows || !MyRender11.DebugOverrides.Shadows)
                return;

            MarkCascadesInStencil(cascadeInfo);

            MyGpuProfiler.IC_BeginBlock("Cascades postprocess");

            MyRenderContext renderContext = MyRenderContext.Immediate;
            DeviceContext deviceContext = renderContext.DeviceContext;

            MyShadowsQuality shadowsQuality = MyRender11.RenderSettings.ShadowQuality.GetShadowsQuality();
            if (shadowsQuality == MyShadowsQuality.LOW)
                renderContext.SetCS(m_gatherCS_LD);
            else if (shadowsQuality == MyShadowsQuality.MEDIUM)
                renderContext.SetCS(m_gatherCS_MD);
            else if (shadowsQuality == MyShadowsQuality.HIGH)
                renderContext.SetCS(m_gatherCS_HD);

            ComputeShaderId.TmpUav[0] = postprocessTarget.Uav;
            deviceContext.ComputeShader.SetUnorderedAccessViews(0, ComputeShaderId.TmpUav, ComputeShaderId.TmpCount);

            deviceContext.ComputeShader.SetShaderResource(0, MyRender11.MultisamplingEnabled ? MyScreenDependants.m_resolvedDepth.m_SRV_depth : MyGBuffer.Main.DepthStencil.m_SRV_depth);
            deviceContext.ComputeShader.SetShaderResource(1, MyGBuffer.Main.DepthStencil.m_SRV_stencil);
            deviceContext.ComputeShader.SetSampler(MyCommon.SHADOW_SAMPLER_SLOT, SamplerStates.m_shadowmap);
            if (!MyStereoRender.Enable)
                deviceContext.ComputeShader.SetConstantBuffer(0, MyCommon.FrameConstants);
            else
                MyStereoRender.CSBindRawCB_FrameConstants(renderContext);
            deviceContext.ComputeShader.SetConstantBuffer(4, cascadeConstantBuffer);
            deviceContext.ComputeShader.SetShaderResource(MyCommon.CASCADES_SM_SLOT, cascadeArray.SRV);

            Vector2I threadGroups = GetThreadGroupCount();
            deviceContext.Dispatch(threadGroups.X, threadGroups.Y, 1);

            ComputeShaderId.TmpUav[0] = null;
            renderContext.DeviceContext.ComputeShader.SetUnorderedAccessViews(0, ComputeShaderId.TmpUav, ComputeShaderId.TmpCount);
            deviceContext.ComputeShader.SetShaderResource(0, null);
            deviceContext.ComputeShader.SetShaderResource(1, null);

            if (shadowsQuality == MyShadowsQuality.HIGH && MyRender11.Settings.EnableShadowBlur)
                MyBlur.Run(postprocessTarget.Rtv, MyRender11.CascadesHelper.Rtv, MyRender11.CascadesHelper.SRV, postprocessTarget.SRV, depthDiscardThreshold: 0.2f);

            MyGpuProfiler.IC_EndBlock();
        }