Capture: DrawIndirect

Bug: 463425874
Change-Id: I6a6a6964470436508e42856936b842e79375d112
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/276674
Commit-Queue: Gregg Tavares <gman@chromium.org>
Reviewed-by: Shrek Shao <shrekshao@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/webgpu/CommandBufferHelpers.cpp b/src/dawn/native/webgpu/CommandBufferHelpers.cpp
index 819d378..1510fea 100644
--- a/src/dawn/native/webgpu/CommandBufferHelpers.cpp
+++ b/src/dawn/native/webgpu/CommandBufferHelpers.cpp
@@ -161,6 +161,17 @@
             Serialize(captureContext, data);
             break;
         }
+        case Command::DrawIndirect: {
+            const auto& cmd = *commands.NextCommand<DrawIndirectCmd>();
+            schema::CommandBufferCommandDrawIndirectCmd data{{
+                .data = {{
+                    .indirectBufferId = captureContext.GetId(cmd.indirectBuffer),
+                    .indirectOffset = cmd.indirectOffset,
+                }},
+            }};
+            Serialize(captureContext, data);
+            break;
+        }
         default: {
             if (!CaptureDebugCommand(captureContext, commands, type)) {
                 return DAWN_UNIMPLEMENTED_ERROR("Unimplemented command");
diff --git a/src/dawn/replay/Replay.cpp b/src/dawn/replay/Replay.cpp
index 3d74ff6..32cf9fb 100644
--- a/src/dawn/replay/Replay.cpp
+++ b/src/dawn/replay/Replay.cpp
@@ -495,6 +495,13 @@
                              data.firstInstance);
             break;
         }
+        case schema::CommandBufferCommand::DrawIndirect: {
+            schema::CommandBufferCommandDrawIndirectCmdData data;
+            DAWN_TRY(Deserialize(readHead, &data));
+            pass.DrawIndirect(replay.GetObjectById<wgpu::Buffer>(data.indirectBufferId),
+                              data.indirectOffset);
+            break;
+        }
         case schema::CommandBufferCommand::PushDebugGroup:
         case schema::CommandBufferCommand::InsertDebugMarker:
         case schema::CommandBufferCommand::PopDebugGroup:
diff --git a/src/dawn/serialization/Schema.h b/src/dawn/serialization/Schema.h
index fcba3e5..8eb15c3 100644
--- a/src/dawn/serialization/Schema.h
+++ b/src/dawn/serialization/Schema.h
@@ -624,6 +624,12 @@
 
 DAWN_REPLAY_MAKE_COMMAND_BUFFER_CMD_AND_CMD_DATA(DrawIndexed, DRAW_INDEXED_CMD_DATA_MEMBER){};
 
+#define DRAW_INDIRECT_CMD_DATA_MEMBER(X) \
+    X(ObjectId, indirectBufferId)        \
+    X(uint64_t, indirectOffset)
+
+DAWN_REPLAY_MAKE_COMMAND_BUFFER_CMD_AND_CMD_DATA(DrawIndirect, DRAW_INDIRECT_CMD_DATA_MEMBER){};
+
 }  // namespace schema
 
 #endif  // SRC_DAWN_SERIALIZATION_SCHEMA_H_
diff --git a/src/dawn/tests/white_box/CaptureAndReplayTests.cpp b/src/dawn/tests/white_box/CaptureAndReplayTests.cpp
index 5f42ee0..c5129ca 100644
--- a/src/dawn/tests/white_box/CaptureAndReplayTests.cpp
+++ b/src/dawn/tests/white_box/CaptureAndReplayTests.cpp
@@ -1992,6 +1992,23 @@
         expected);
 }
 
+// Capture DrawIndirect
+TEST_P(CaptureAndReplayDrawTests, CaptureDrawIndirect) {
+    uint32_t indirect[] = {
+        0x11,  // vertexCount
+        0x22,  // instanceCount
+        0,     // firstVertex
+        0,     // firstInstance (must be 0 without "indirect-first-instance")
+    };
+    wgpu::Buffer indirectBuffer = CreateBuffer(
+        "indirect", sizeof(indirect), wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Indirect);
+    queue.WriteBuffer(indirectBuffer, 0, indirect, sizeof(indirect));
+
+    utils::RGBA8 expected[] = {{0x10, 0x21, 0x33, 0x44}};
+    TestDrawCommand([&](wgpu::RenderPassEncoder pass) { pass.DrawIndirect(indirectBuffer, 0); },
+                    expected);
+}
+
 DAWN_INSTANTIATE_TEST(CaptureAndReplayDrawTests, WebGPUBackend());
 
 }  // anonymous namespace