Capture: Handle Debug Markers. Bug: 451479048 Change-Id: I6a6a6964dd79fdc53d7dc6bbba8f3f0ba30e9e50 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/275395 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Shrek Shao <shrekshao@google.com> Commit-Queue: Gregg Tavares <gman@chromium.org>
diff --git a/src/dawn/native/webgpu/CommandBufferHelpers.cpp b/src/dawn/native/webgpu/CommandBufferHelpers.cpp index ad2bbd2..35403b1 100644 --- a/src/dawn/native/webgpu/CommandBufferHelpers.cpp +++ b/src/dawn/native/webgpu/CommandBufferHelpers.cpp
@@ -40,6 +40,43 @@ namespace dawn::native::webgpu { +// Returns true if command was handled +bool CaptureDebugCommand(CaptureContext& captureContext, CommandIterator& commands, Command type) { + switch (type) { + case Command::PushDebugGroup: { + const auto& cmd = *commands.NextCommand<PushDebugGroupCmd>(); + const char* label = commands.NextData<char>(cmd.length + 1); + schema::CommandBufferCommandPushDebugGroupCmd data{{ + .data = {{ + .groupLabel = label, + }}, + }}; + Serialize(captureContext, data); + break; + } + case Command::PopDebugGroup: { + commands.NextCommand<PopDebugGroupCmd>(); + Serialize(captureContext, schema::CommandBufferCommand::PopDebugGroup); + break; + } + case Command::InsertDebugMarker: { + const auto& cmd = *commands.NextCommand<InsertDebugMarkerCmd>(); + const char* label = commands.NextData<char>(cmd.length + 1); + schema::CommandBufferCommandInsertDebugMarkerCmd data{{ + .data = {{ + .markerLabel = label, + }}, + }}; + Serialize(captureContext, data); + break; + } + default: { + return false; + } + } + return true; +} + // Captures commands common to a render pass and a render bundle MaybeError CaptureRenderCommand(CaptureContext& captureContext, CommandIterator& commands, @@ -97,21 +134,17 @@ Serialize(captureContext, data); break; } - default: - return DAWN_UNIMPLEMENTED_ERROR("Unimplemented command"); + default: { + if (!CaptureDebugCommand(captureContext, commands, type)) { + return DAWN_UNIMPLEMENTED_ERROR("Unimplemented command"); + } + break; + } } return {}; } -// Commands are encoded with a command id followed by command-specific data. -// so we're required to read each command to skip over them. -#define DAWN_SKIP_COMMAND(cmdName) \ - case Command::cmdName: { \ - commands.NextCommand<cmdName##Cmd>(); \ - break; \ - } - // Gathers resources used by commands from both render passes and render bundles. MaybeError GatherReferencedResourcesFromRenderCommand(CaptureContext& captureContext, CommandIterator& commands, @@ -128,22 +161,23 @@ usedResources.bindGroups.push_back(cmd->group.Get()); break; } - DAWN_SKIP_COMMAND(BeginOcclusionQuery) - DAWN_SKIP_COMMAND(EndOcclusionQuery) - DAWN_SKIP_COMMAND(Draw) - DAWN_SKIP_COMMAND(DrawIndexed) - DAWN_SKIP_COMMAND(DrawIndirect) - DAWN_SKIP_COMMAND(DrawIndexedIndirect) - DAWN_SKIP_COMMAND(InsertDebugMarker) - DAWN_SKIP_COMMAND(PopDebugGroup) - DAWN_SKIP_COMMAND(PushDebugGroup) - DAWN_SKIP_COMMAND(WriteTimestamp) - DAWN_SKIP_COMMAND(SetImmediates) - DAWN_SKIP_COMMAND(SetIndexBuffer) - DAWN_SKIP_COMMAND(SetVertexBuffer) - default: { + case Command::BeginOcclusionQuery: + case Command::EndOcclusionQuery: + case Command::Draw: + case Command::DrawIndexed: + case Command::DrawIndirect: + case Command::DrawIndexedIndirect: + case Command::WriteTimestamp: + case Command::SetImmediates: + case Command::SetIndexBuffer: + case Command::SetVertexBuffer: + case Command::PushDebugGroup: + case Command::InsertDebugMarker: + case Command::PopDebugGroup: + SkipCommand(&commands, type); + break; + default: return DAWN_UNIMPLEMENTED_ERROR("Unimplemented command"); - } } return {}; }
diff --git a/src/dawn/native/webgpu/CommandBufferHelpers.h b/src/dawn/native/webgpu/CommandBufferHelpers.h index 691b018..88f9d19 100644 --- a/src/dawn/native/webgpu/CommandBufferHelpers.h +++ b/src/dawn/native/webgpu/CommandBufferHelpers.h
@@ -57,6 +57,9 @@ std::vector<RenderBundleBase*> renderBundles; }; +// Returns true if command was handled. +bool CaptureDebugCommand(CaptureContext& captureContext, CommandIterator& commands, Command type); + // Captures shared commands from both render passes and render bundles MaybeError CaptureRenderCommand(CaptureContext& captureContext, CommandIterator& commands,
diff --git a/src/dawn/native/webgpu/CommandBufferWGPU.cpp b/src/dawn/native/webgpu/CommandBufferWGPU.cpp index b3c44b5..f1bf8e4 100644 --- a/src/dawn/native/webgpu/CommandBufferWGPU.cpp +++ b/src/dawn/native/webgpu/CommandBufferWGPU.cpp
@@ -411,14 +411,6 @@ DAWN_UNREACHABLE(); } -// Commands are encoded with a command id followed by command-specific data. -// so we're required to read each command to skip over them. -#define DAWN_SKIP_COMMAND(cmdName) \ - case Command::cmdName: { \ - commands.NextCommand<cmdName##Cmd>(); \ - break; \ - } - MaybeError GatherReferencedResourcesFromComputePass(CaptureContext& captureContext, CommandIterator& commands, CommandBufferResourceUsages& usedResources) { @@ -439,16 +431,17 @@ usedResources.bindGroups.push_back(cmd->group.Get()); break; } - DAWN_SKIP_COMMAND(Dispatch) - DAWN_SKIP_COMMAND(DispatchIndirect) - DAWN_SKIP_COMMAND(InsertDebugMarker) - DAWN_SKIP_COMMAND(PopDebugGroup) - DAWN_SKIP_COMMAND(PushDebugGroup) - DAWN_SKIP_COMMAND(WriteTimestamp) - DAWN_SKIP_COMMAND(SetImmediates) - default: { - DAWN_CHECK(false); + case Command::Dispatch: + case Command::DispatchIndirect: + case Command::WriteTimestamp: + case Command::SetImmediates: + case Command::PushDebugGroup: + case Command::InsertDebugMarker: + case Command::PopDebugGroup: + SkipCommand(&commands, type); break; + default: { + return DAWN_UNIMPLEMENTED_ERROR("Unimplemented command"); } } } @@ -535,8 +528,12 @@ Serialize(captureContext, data); break; } - default: - DAWN_CHECK(false); + default: { + if (!CaptureDebugCommand(captureContext, commands, type)) { + return DAWN_UNIMPLEMENTED_ERROR("Unimplemented command"); + } + break; + } } } return {}; @@ -685,12 +682,18 @@ usedResources)); break; } - DAWN_SKIP_COMMAND(CopyBufferToBuffer) - DAWN_SKIP_COMMAND(CopyBufferToTexture) - DAWN_SKIP_COMMAND(CopyTextureToBuffer) - DAWN_SKIP_COMMAND(CopyTextureToTexture) - default: - DAWN_CHECK(false); + case Command::CopyBufferToBuffer: + case Command::CopyBufferToTexture: + case Command::CopyTextureToBuffer: + case Command::CopyTextureToTexture: + case Command::PushDebugGroup: + case Command::InsertDebugMarker: + case Command::PopDebugGroup: + SkipCommand(&commands, type); + break; + default: { + return DAWN_UNIMPLEMENTED_ERROR("Unimplemented command"); + } } } @@ -854,8 +857,12 @@ Serialize(captureContext, data); break; } - default: - DAWN_CHECK(false); + default: { + if (!CaptureDebugCommand(captureContext, commands, type)) { + return DAWN_UNIMPLEMENTED_ERROR("Unimplemented command"); + } + break; + } } } Serialize(captureContext, schema::CommandBufferCommand::End);
diff --git a/src/dawn/replay/Replay.cpp b/src/dawn/replay/Replay.cpp index d81445c..92e4532 100644 --- a/src/dawn/replay/Replay.cpp +++ b/src/dawn/replay/Replay.cpp
@@ -423,6 +423,32 @@ } template <typename T> +MaybeError ProcessDebugCommands(T pass, schema::CommandBufferCommand cmd, ReadHead& readHead) { + switch (cmd) { + case schema::CommandBufferCommand::PushDebugGroup: { + schema::CommandBufferCommandPushDebugGroupCmdData data; + DAWN_TRY(Deserialize(readHead, &data)); + pass.PushDebugGroup(wgpu::StringView(data.groupLabel)); + break; + } + case schema::CommandBufferCommand::InsertDebugMarker: { + schema::CommandBufferCommandInsertDebugMarkerCmdData data; + DAWN_TRY(Deserialize(readHead, &data)); + pass.InsertDebugMarker(wgpu::StringView(data.markerLabel)); + break; + } + case schema::CommandBufferCommand::PopDebugGroup: { + // PopDebugGroup has no data + pass.PopDebugGroup(); + break; + } + default: + DAWN_UNREACHABLE(); + } + return {}; +} + +template <typename T> MaybeError ProcessRenderCommand(const Replay& replay, ReadHead& readHead, wgpu::Device device, @@ -455,6 +481,11 @@ pass.Draw(data.vertexCount, data.instanceCount, data.firstVertex, data.firstInstance); break; } + case schema::CommandBufferCommand::PushDebugGroup: + case schema::CommandBufferCommand::InsertDebugMarker: + case schema::CommandBufferCommand::PopDebugGroup: + DAWN_TRY(ProcessDebugCommands(pass, cmd, readHead)); + break; default: return DAWN_INTERNAL_ERROR("Render Pass/Bundle Command not implemented"); } @@ -729,6 +760,11 @@ pass.DispatchWorkgroups(data.x, data.y, data.z); break; } + case schema::CommandBufferCommand::PushDebugGroup: + case schema::CommandBufferCommand::InsertDebugMarker: + case schema::CommandBufferCommand::PopDebugGroup: + DAWN_TRY(ProcessDebugCommands(pass, cmd, readHead)); + break; default: return DAWN_INTERNAL_ERROR("Compute Pass Command not implemented"); } @@ -892,6 +928,11 @@ data.destinationOffset); break; } + case schema::CommandBufferCommand::PushDebugGroup: + case schema::CommandBufferCommand::InsertDebugMarker: + case schema::CommandBufferCommand::PopDebugGroup: + DAWN_TRY(ProcessDebugCommands(encoder, cmd, readHead)); + break; default: return DAWN_INTERNAL_ERROR("Encoder Command not implemented"); }
diff --git a/src/dawn/serialization/Schema.h b/src/dawn/serialization/Schema.h index e2fb69f..ae3375e 100644 --- a/src/dawn/serialization/Schema.h +++ b/src/dawn/serialization/Schema.h
@@ -560,6 +560,16 @@ DAWN_REPLAY_MAKE_COMMAND_BUFFER_CMD_AND_CMD_DATA(SetRenderPipeline, SET_RENDER_PIPELINE_CMD_DATA_MEMBER){}; +#define PUSH_DEBUG_GROUP_CMD_DATA_MEMBER(X) X(std::string, groupLabel) + +DAWN_REPLAY_MAKE_COMMAND_BUFFER_CMD_AND_CMD_DATA(PushDebugGroup, + PUSH_DEBUG_GROUP_CMD_DATA_MEMBER){}; + +#define INSERT_DEBUG_MARKER_CMD_DATA_MEMBER(X) X(std::string, markerLabel) + +DAWN_REPLAY_MAKE_COMMAND_BUFFER_CMD_AND_CMD_DATA(InsertDebugMarker, + INSERT_DEBUG_MARKER_CMD_DATA_MEMBER){}; + #define BEGIN_OCCLUSION_QUERY_CMD_DATA_MEMBER(X) X(uint32_t, queryIndex) DAWN_REPLAY_MAKE_COMMAND_BUFFER_CMD_AND_CMD_DATA(BeginOcclusionQuery,
diff --git a/src/dawn/tests/white_box/CaptureAndReplayTests.cpp b/src/dawn/tests/white_box/CaptureAndReplayTests.cpp index 2155a57..879023e 100644 --- a/src/dawn/tests/white_box/CaptureAndReplayTests.cpp +++ b/src/dawn/tests/white_box/CaptureAndReplayTests.cpp
@@ -1714,6 +1714,43 @@ ExpectTextureEQ(replay.get(), "dstTexture", {1}, expected); } +// Test debug commands don't fail. +TEST_P(CaptureAndReplayTests, PushPopInsertDebug) { + utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 4, 4); + + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + encoder.PushDebugGroup("Event Start"); + encoder.InsertDebugMarker("Marker"); + encoder.PopDebugGroup(); + { + wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo); + pass.PushDebugGroup("Event Start"); + pass.InsertDebugMarker("Marker"); + pass.PopDebugGroup(); + pass.End(); + } + { + wgpu::ComputePassEncoder pass = encoder.BeginComputePass(); + pass.PushDebugGroup("Event Start"); + pass.InsertDebugMarker("Marker"); + pass.PopDebugGroup(); + pass.End(); + } + + wgpu::CommandBuffer commands = encoder.Finish(); + + // --- capture --- + auto recorder = Recorder::CreateAndStart(device); + + queue.Submit(1, &commands); + + // --- replay --- + auto capture = recorder.Finish(); + auto replay = capture.Replay(device); + + // just expect no errors. +} + DAWN_INSTANTIATE_TEST(CaptureAndReplayTests, WebGPUBackend()); } // anonymous namespace