Loading... ## 动机 如果Compute Shader是异步执行的,那么ALT+F12抓帧将无法捕获到该Compute Shader的调用。使用GPUReadback又要多写依托答辩代码,还要依靠Debugger调试。 ## 解决方案 在RDG中插入开始捕获和结束捕获的Pass,IRenderCaptureProvider::Get()会通过UE的ModularFeature,去查找实现了IRenderCaptureProvider类的功能模块,并返回其引用。这里如果配置好了RenderDoc,就会正确返回RenderDocPlugin中的实现。 ```cpp ENQUEUE_RENDER_COMMAND(QwQVoxel)([this] (FRHICommandListImmediate& CmdList) { FRDGBuilder GraphBuilder(CmdList); FGlobalShaderMap* ShaderMap = GetGlobalShaderMap(GMaxRHIFeatureLevel); check(ShaderMap); // RenderDoc Capture FRDGPassRef BeginCapturePass = GraphBuilder.AddPass( RDG_EVENT_NAME("BeginCapture"), ERDGPassFlags::None, [] (FRHICommandListImmediate& RHICommandListLocal) { IRenderCaptureProvider::Get().BeginCapture(&RHICommandListLocal, IRenderCaptureProvider::ECaptureFlags_Launch); }); FRDGPassRef EndCapturePass = GraphBuilder.AddPass(RDG_EVENT_NAME("End Capture"), ERDGPassFlags::None, [] (FRHICommandListImmediate& RHICmdList) { IRenderCaptureProvider::Get().EndCapture(&RHICmdList); }); GraphBuilder.AddPassDependency(BeginCapturePass, EndCapturePass); const auto EnsureCaptured = [BeginCapturePass, EndCapturePass, &GraphBuilder](FRDGPassRef& NewPass) { if (NewPass) { GraphBuilder.AddPassDependency(BeginCapturePass, NewPass); GraphBuilder.AddPassDependency(NewPass, EndCapturePass); } }; // Atomic counter buffer static constexpr uint32 DEFAULT_COUNTER_VALUES[] { 0, 0, 0, 0 }; FRDGBufferDesc Desc = FRDGBufferDesc::CreateUploadDesc(sizeof(uint32), 4); Desc.Usage |= EBufferUsageFlags::UnorderedAccess; FRDGBufferRef CounterBuffer = GraphBuilder.CreateBuffer(Desc, TEXT("Voxel Atomic Counter")); GraphBuilder.QueueBufferUpload(CounterBuffer, DEFAULT_COUNTER_VALUES, std::size(DEFAULT_COUNTER_VALUES)); FRDGBufferUAVRef CounterBufferUAV = GraphBuilder.CreateUAV(CounterBuffer, EPixelFormat::PF_R32_UINT); // Uniform buffer FVoxelMarchingCubeUniformParameters* UniformParameters =GraphBuilder.AllocParameters<FVoxelMarchingCubeUniformParameters>(); UniformParameters->VoxelSize = DimensionX; UniformParameters->SurfaceIsoValue = 0.f; UniformParameters->TotalCubes = (DimensionX + 1) * (DimensionY + 1) * (DimensionZ + 1); TRDGUniformBufferRef<FVoxelMarchingCubeUniformParameters> UniformParametersBuffer = GraphBuilder.CreateUniformBuffer(UniformParameters); // Nanovdb data buffer nanovdb::NanoGrid<float>* GridData = HostVdbBuffer.grid<float>(); FRDGBufferDesc GridBufferDesc = FRDGBufferDesc::CreateUploadDesc(sizeof(float), HostVdbBuffer.size()); FRDGBufferRef GridBuffer = GraphBuilder.CreateBuffer(GridBufferDesc, TEXT("Voxel Data Buffer")); GraphBuilder.QueueBufferUpload(GridBuffer, GridData, HostVdbBuffer.size()); FRDGBufferSRVRef GridBufferSRV = GraphBuilder.CreateSRV(GridBuffer, EPixelFormat::PF_R32_UINT); // Cube index offset buffer FRDGBufferDesc CubeIndexOffsetBufferDesc = FRDGBufferDesc::CreateBufferDesc(sizeof(uint32), DimensionX * DimensionY * DimensionZ); FRDGBufferRef CubeIndexOffsetBuffer = GraphBuilder.CreateBuffer(CubeIndexOffsetBufferDesc, TEXT("Cube Index Offset")); FRDGBufferUAVRef CubeIndexOffsetBufferUAV = GraphBuilder.CreateUAV(CubeIndexOffsetBuffer, EPixelFormat::PF_R32_UINT); FRDGBufferSRVRef CubeIndexOffsetBufferSRV = GraphBuilder.CreateSRV(CubeIndexOffsetBuffer, EPixelFormat::PF_R32_UINT); { auto CSRef = ShaderMap->GetShader<FVoxelMarchingCubesCalcCubeIndexCS>(); auto* Parameters = GraphBuilder.AllocParameters<FVoxelMarchingCubesCalcCubeIndexCS::FParameters>(); Parameters->Counter = CounterBufferUAV; Parameters->MarchingCubeParameters = UniformParametersBuffer; Parameters->SrcVoxelData = GridBufferSRV; Parameters->OutCubeIndexOffsets = CubeIndexOffsetBufferUAV; FRDGPassRef CalcPass = FComputeShaderUtils::AddPass(GraphBuilder, RDG_EVENT_NAME("Voxel Marching Cubes Calc CubeIndex"), CSRef, Parameters, GetDispatchSize(DimensionX * DimensionY * DimensionZ)); EnsureCaptured(CalcPass); } GraphBuilder.Execute(); }); ``` EnsureCaptured函数被调用时会显式声明对应Pass的依赖,以便执行的顺序是正确的。 最后修改:2024 年 11 月 18 日 © 允许规范转载 打赏 赞赏作者 赞 如果觉得我的文章对你有用,请随意赞赏