void LightingParser_ResolveGBuffer( Metal::DeviceContext& context, LightingParserContext& parserContext, MainTargetsBox& mainTargets, LightingResolveTextureBox& lightingResTargets) { Metal::GPUProfiler::DebugAnnotation anno(context, L"ResolveGBuffer"); const bool doSampleFrequencyOptimisation = Tweakable("SampleFrequencyOptimisation", true); LightingResolveContext lightingResolveContext(mainTargets); const unsigned samplingCount = lightingResolveContext.GetSamplingCount(); const bool useMsaaSamplers = lightingResolveContext.UseMsaaSamplers(); auto& resolveRes = Techniques::FindCachedBoxDep2<LightingResolveResources>(samplingCount); // // Our inputs is the prepared gbuffer // -- we resolve the lighting and write out a "lighting resolve texture" // if (doSampleFrequencyOptimisation && samplingCount>1) { context.Bind(resolveRes._alwaysWriteToStencil, 0xff); // todo -- instead of clearing the stencil every time, how // about doing a progressive walk through all of the bits! context.ClearStencil(mainTargets._secondaryDepthBuffer, 0); context.Bind(ResourceList<Metal::RenderTargetView, 0>(), &mainTargets._secondaryDepthBuffer); context.BindPS(MakeResourceList(mainTargets._msaaDepthBufferSRV, mainTargets._gbufferRTVsSRV[1])); SetupVertexGeneratorShader(context); CATCH_ASSETS_BEGIN context.Bind(*resolveRes._perSampleMask); context.Draw(4); CATCH_ASSETS_END(parserContext) }
static void DrawTriMeshMarker( Metal::DeviceContext& devContext, ParsingContext& parserContext, const VisGeoBox& visBox, const ResolvedShader& shader, const RetainedEntity& obj, EntityInterface::RetainedEntities& objs) { static auto IndexListHash = ParameterBox::MakeParameterNameHash("IndexList"); if (!obj._properties.GetParameter(Parameters::Visible, true) || !GetShowMarker(obj)) return; // we need an index list with at least 3 indices (to make at least one triangle) auto indexListType = obj._properties.GetParameterType(IndexListHash); if (indexListType._type == ImpliedTyping::TypeCat::Void || indexListType._arrayCount < 3) return; auto ibData = std::make_unique<unsigned[]>(indexListType._arrayCount); bool success = obj._properties.GetParameter( IndexListHash, ibData.get(), ImpliedTyping::TypeDesc(ImpliedTyping::TypeCat::UInt32, indexListType._arrayCount)); if (!success) return; const auto& chld = obj._children; if (!chld.size()) return; auto vbData = std::make_unique<Float3[]>(chld.size()); for (size_t c=0; c<chld.size(); ++c) { const auto* e = objs.GetEntity(obj._doc, chld[c]); if (e) { vbData[c] = ExtractTranslation(GetTransform(*e)); } else { vbData[c] = Zero<Float3>(); } } const auto& cbLayout = ::Assets::GetAssetDep<Techniques::PredefinedCBLayout>( "game/xleres/BasicMaterialConstants.txt"); shader.Apply(devContext, parserContext, { MakeLocalTransformPacket( GetTransform(obj), ExtractTranslation(parserContext.GetProjectionDesc()._cameraToWorld)), cbLayout.BuildCBDataAsPkt(ParameterBox()) }); devContext.Bind(Techniques::CommonResources()._blendAdditive); devContext.Bind(Techniques::CommonResources()._dssReadOnly); devContext.Bind(Techniques::CommonResources()._cullDisable); Metal::VertexBuffer vb(vbData.get(), sizeof(Float3)*chld.size()); Metal::IndexBuffer ib(ibData.get(), sizeof(unsigned)*indexListType._arrayCount); devContext.Bind(MakeResourceList(vb), sizeof(Float3), 0); devContext.Bind(ib, Metal::NativeFormat::R32_UINT); devContext.Bind(Metal::Topology::TriangleList); devContext.DrawIndexed(indexListType._arrayCount); }
static void AmbientOcclusion_DrawDebugging( Metal::DeviceContext& context, AmbientOcclusionResources& resources) { SetupVertexGeneratorShader(context); context.BindPS(MakeResourceList(resources._aoSRV)); context.Bind(::Assets::GetAssetDep<Metal::ShaderProgram>( "game/xleres/basic2D.vsh:fullscreen:vs_*", "game/xleres/postprocess/debugging.psh:AODebugging:ps_*")); context.Draw(4); }
static void DrawObject( Metal::DeviceContext& devContext, ParsingContext& parserContext, const VisGeoBox& visBox, const ResolvedShader& shader, const RetainedEntity& obj) { if (!obj._properties.GetParameter(Parameters::Visible, true) || !GetShowMarker(obj)) return; const auto& cbLayout = ::Assets::GetAssetDep<Techniques::PredefinedCBLayout>( "game/xleres/BasicMaterialConstants.txt"); shader.Apply(devContext, parserContext, { MakeLocalTransformPacket( GetTransform(obj), ExtractTranslation(parserContext.GetProjectionDesc()._cameraToWorld)), cbLayout.BuildCBDataAsPkt(ParameterBox()) }); devContext.Bind(MakeResourceList(visBox._cubeVB), visBox._cubeVBStride, 0); devContext.Draw(visBox._cubeVBCount); }
PreparedRTShadowFrustum PrepareRTShadows( IThreadContext& context, Metal::DeviceContext& metalContext, LightingParserContext& parserContext, PreparedScene& preparedScene, const ShadowProjectionDesc& frustum, unsigned shadowFrustumIndex) { SceneParseSettings sceneParseSettings( SceneParseSettings::BatchFilter::RayTracedShadows, ~SceneParseSettings::Toggles::BitField(0), shadowFrustumIndex); if (!parserContext.GetSceneParser()->HasContent(sceneParseSettings)) return PreparedRTShadowFrustum(); Metal::GPUProfiler::DebugAnnotation anno(metalContext, L"Prepare-RTShadows"); auto& box = Techniques::FindCachedBox2<RTShadowsBox>(256, 256, 1024*1024, 32, 64*1024); auto oldSO = Metal::GeometryShader::GetDefaultStreamOutputInitializers(); static const Metal::InputElementDesc soVertex[] = { Metal::InputElementDesc("A", 0, Metal::NativeFormat::R32G32B32A32_FLOAT), Metal::InputElementDesc("B", 0, Metal::NativeFormat::R32G32_FLOAT), Metal::InputElementDesc("C", 0, Metal::NativeFormat::R32G32B32A32_FLOAT), Metal::InputElementDesc("D", 0, Metal::NativeFormat::R32G32B32_FLOAT) }; static const Metal::InputElementDesc il[] = { Metal::InputElementDesc("A", 0, Metal::NativeFormat::R32G32B32A32_FLOAT), Metal::InputElementDesc("B", 0, Metal::NativeFormat::R32G32_FLOAT), Metal::InputElementDesc("C", 0, Metal::NativeFormat::R32G32B32A32_FLOAT), Metal::InputElementDesc("D", 0, Metal::NativeFormat::R32G32B32_FLOAT) }; metalContext.UnbindPS<Metal::ShaderResourceView>(5, 3); const unsigned bufferCount = 1; unsigned strides[] = { 52 }; unsigned offsets[] = { 0 }; Metal::GeometryShader::SetDefaultStreamOutputInitializers( Metal::GeometryShader::StreamOutputInitializers(soVertex, dimof(soVertex), strides, 1)); static_assert(bufferCount == dimof(strides), "Stream output buffer count mismatch"); static_assert(bufferCount == dimof(offsets), "Stream output buffer count mismatch"); metalContext.BindSO(MakeResourceList(box._triangleBufferVB)); // set up the render state for writing into the grid buffer SavedTargets savedTargets(metalContext); metalContext.Bind(box._gridBufferViewport); metalContext.Unbind<Metal::RenderTargetView>(); metalContext.Bind(Techniques::CommonResources()._blendOpaque); metalContext.Bind(Techniques::CommonResources()._defaultRasterizer); // for newer video cards, we need "conservative raster" enabled PreparedRTShadowFrustum preparedResult; preparedResult.InitialiseConstants(&metalContext, frustum._projections); using TC = Techniques::TechniqueContext; parserContext.SetGlobalCB(metalContext, TC::CB_ShadowProjection, &preparedResult._arbitraryCBSource, sizeof(preparedResult._arbitraryCBSource)); parserContext.SetGlobalCB(metalContext, TC::CB_OrthoShadowProjection, &preparedResult._orthoCBSource, sizeof(preparedResult._orthoCBSource)); parserContext.GetTechniqueContext()._runtimeState.SetParameter( StringShadowCascadeMode, (preparedResult._mode == ShadowProjectionDesc::Projections::Mode::Ortho)?2:1); // Now, we need to transform the object's triangle buffer into shadow // projection space during this step (also applying skinning, wind bending, and // any other animation effects. // // Each object that will be used with projected shadows must have a buffer // containing the triangle information. // // We can deal with this in a number of ways: // 1. rtwritetiles shader writes triangles out in a stream-output step // 2. transform triangles first, then pass that information through the rtwritetiles shader // 3. transform triangles completely separately from the rtwritetiles step // // Method 1 would avoid extra transformations of the input data, and actually // simplifies some of the shader work. We don't need any special input buffers // or extra input data. The shaders just take generic model information, and build // everything they need, as they need it. // // We can also choose to reject backfacing triangles at this point, as well as // removing triangles that are culled from the frustum. // Float4x4 savedWorldToProjection = parserContext.GetProjectionDesc()._worldToProjection; parserContext.GetProjectionDesc()._worldToProjection = frustum._worldToClip; auto cleanup = MakeAutoCleanup( [&parserContext, &savedWorldToProjection]() { parserContext.GetProjectionDesc()._worldToProjection = savedWorldToProjection; parserContext.GetTechniqueContext()._runtimeState.SetParameter(StringShadowCascadeMode, 0); }); CATCH_ASSETS_BEGIN parserContext.GetSceneParser()->ExecuteScene( context, parserContext, sceneParseSettings, preparedScene, TechniqueIndex_RTShadowGen); CATCH_ASSETS_END(parserContext) metalContext.UnbindSO(); Metal::GeometryShader::SetDefaultStreamOutputInitializers(oldSO); // We have the list of triangles. Let's render then into the final // grid buffer viewport. This should create a list of triangles for // each cell in the grid. The goal is to reduce the number of triangles // that the ray tracing shader needs to look at. // // We could attempt to do this in the same step above. But that creates // some problems with frustum cull and back face culling. This order // allows us reduce the total triangle count before we start assigning // primitive ids. // // todo -- also calculate min/max for each grid during this step CATCH_ASSETS_BEGIN auto& shader = ::Assets::GetAssetDep<Metal::ShaderProgram>( "game/xleres/shadowgen/rtwritetiles.sh:vs_passthrough:vs_*", "game/xleres/shadowgen/consraster.sh:gs_conservativeRasterization:gs_*", "game/xleres/shadowgen/rtwritetiles.sh:ps_main:ps_*", "OUTPUT_PRIM_ID=1;INPUT_RAYTEST_TRIS=1"); metalContext.Bind(shader); Metal::BoundInputLayout inputLayout(Metal::InputLayout(il, dimof(il)), shader); metalContext.Bind(inputLayout); // no shader constants/resources required unsigned clearValues[] = { 0, 0, 0, 0 }; metalContext.Clear(box._gridBufferUAV, clearValues); metalContext.Bind(Techniques::CommonResources()._blendOpaque); metalContext.Bind(Techniques::CommonResources()._dssDisable); metalContext.Bind(Techniques::CommonResources()._cullDisable); metalContext.Bind(Metal::Topology::PointList); metalContext.Bind(MakeResourceList(box._triangleBufferVB), strides[0], offsets[0]); metalContext.Bind( MakeResourceList(box._dummyRTV), nullptr, MakeResourceList(box._gridBufferUAV, box._listsBufferUAV)); metalContext.DrawAuto(); CATCH_ASSETS_END(parserContext) metalContext.Bind(Metal::Topology::TriangleList); savedTargets.ResetToOldTargets(metalContext); preparedResult._listHeadSRV = box._gridBufferSRV; preparedResult._linkedListsSRV = box._listsBufferSRV; preparedResult._trianglesSRV = box._triangleBufferSRV; return std::move(preparedResult); }