Capture: Support vertex attributes Bug: 454365240 Change-Id: I6a6a69646bc6948c26cd1d98ec9e4c40edd06a3f Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/268674 Reviewed-by: Kai Ninomiya <kainino@chromium.org> Reviewed-by: Loko Kung <lokokung@google.com> Auto-Submit: Gregg Tavares <gman@chromium.org> Commit-Queue: Gregg Tavares <gman@chromium.org>
diff --git a/src/dawn/native/PipelineLayout.cpp b/src/dawn/native/PipelineLayout.cpp index a49479a..3c0e18e 100644 --- a/src/dawn/native/PipelineLayout.cpp +++ b/src/dawn/native/PipelineLayout.cpp
@@ -613,13 +613,16 @@ } bool PipelineLayoutBase::IsImplicit() const { + uint32_t numBindGroups = 0; for (BindGroupIndex groupIndex : GetBindGroupLayoutsMask()) { const BindGroupLayoutBase* bgl = GetFrontendBindGroupLayout(groupIndex); if (bgl->GetPipelineCompatibilityToken() != kExplicitPCT) { return true; } + ++numBindGroups; } - return false; + // A pipeline layout with no bindgroups can be considered implicit. + return numBindGroups == 0; } uint32_t PipelineLayoutBase::GetImmediateDataRangeByteSize() const {
diff --git a/src/dawn/native/webgpu/CommandBufferWGPU.cpp b/src/dawn/native/webgpu/CommandBufferWGPU.cpp index 5a3c61d..24a404d 100644 --- a/src/dawn/native/webgpu/CommandBufferWGPU.cpp +++ b/src/dawn/native/webgpu/CommandBufferWGPU.cpp
@@ -655,6 +655,7 @@ DAWN_SKIP_COMMAND(PushDebugGroup) DAWN_SKIP_COMMAND(WriteTimestamp) DAWN_SKIP_COMMAND(SetImmediateData) + DAWN_SKIP_COMMAND(SetVertexBuffer) default: { DAWN_CHECK(false); break; @@ -761,6 +762,19 @@ } break; } + case Command::SetVertexBuffer: { + const auto& cmd = *commands.NextCommand<SetVertexBufferCmd>(); + schema::RenderPassCommandSetVertexBufferCmd data{{ + .data = {{ + .slot = uint32_t(cmd.slot), + .bufferId = captureContext.GetId(cmd.buffer), + .offset = cmd.offset, + .size = cmd.size, + }}, + }}; + Serialize(captureContext, data); + break; + } case Command::Draw: { const auto& cmd = *commands.NextCommand<DrawCmd>(); schema::RenderPassCommandDrawCmd data{{
diff --git a/src/dawn/native/webgpu/RenderPipelineWGPU.cpp b/src/dawn/native/webgpu/RenderPipelineWGPU.cpp index 1307fea..2b31bd7 100644 --- a/src/dawn/native/webgpu/RenderPipelineWGPU.cpp +++ b/src/dawn/native/webgpu/RenderPipelineWGPU.cpp
@@ -246,7 +246,19 @@ const auto& info = GetVertexBuffer(slot); std::vector<schema::VertexAttribute> attributes; - // TODO(454365240): handle attributes + + for (VertexAttributeLocation loc : GetAttributeLocationsUsed()) { + const VertexAttributeInfo& attrib = GetAttribute(loc); + // Only use the attributes that use the current input + if (attrib.vertexBufferSlot != slot) { + continue; + } + attributes.push_back({{ + .format = attrib.format, + .offset = attrib.offset, + .shaderLocation = uint32_t(attrib.shaderLocation), + }}); + } buffers.push_back({{ .arrayStride = info.arrayStride,
diff --git a/src/dawn/replay/Replay.cpp b/src/dawn/replay/Replay.cpp index 7cd05b1..ac155b9 100644 --- a/src/dawn/replay/Replay.cpp +++ b/src/dawn/replay/Replay.cpp
@@ -29,6 +29,7 @@ #include <algorithm> +#include "dawn/common/Constants.h" #include "dawn/replay/Deserialization.h" namespace dawn::replay { @@ -278,6 +279,26 @@ ToWGPU(pipeline.fragment.program.constants); std::vector<wgpu::ColorTargetState> colorTargets; std::vector<wgpu::BlendState> blendStates(pipeline.fragment.targets.size()); + std::vector<wgpu::VertexBufferLayout> buffers; + + std::vector<wgpu::VertexAttribute> attributes(kMaxVertexAttributes); + uint32_t attributeCount = 0; + + for (const auto& buffer : pipeline.vertex.buffers) { + const auto attributesForBuffer = &attributes[attributeCount]; + for (const auto& attrib : buffer.attributes) { + auto& attr = attributes[attributeCount++]; + attr.format = attrib.format; + attr.offset = attrib.offset; + attr.shaderLocation = attrib.shaderLocation; + } + buffers.push_back({ + .stepMode = buffer.stepMode, + .arrayStride = buffer.arrayStride, + .attributeCount = buffer.attributes.size(), + .attributes = attributesForBuffer, + }); + } wgpu::FragmentState* fragment = nullptr; wgpu::FragmentState fragmentState; @@ -327,6 +348,8 @@ .entryPoint = wgpu::StringView(pipeline.vertex.program.entryPoint), .constantCount = vertexConstants.size(), .constants = vertexConstants.data(), + .bufferCount = buffers.size(), + .buffers = buffers.data(), }, .primitive = { @@ -480,6 +503,13 @@ data.dynamicOffsets.size(), data.dynamicOffsets.data()); break; } + case schema::RenderPassCommand::SetVertexBuffer: { + schema::RenderPassCommandSetVertexBufferCmdData data; + DAWN_TRY(Deserialize(readHead, &data)); + pass.SetVertexBuffer(data.slot, replay.GetObjectById<wgpu::Buffer>(data.bufferId), + data.offset, data.size); + break; + } case schema::RenderPassCommand::Draw: { schema::RenderPassCommandDrawCmdData data; DAWN_TRY(Deserialize(readHead, &data));
diff --git a/src/dawn/serialization/Schema.h b/src/dawn/serialization/Schema.h index 80fbfef..9f999a9 100644 --- a/src/dawn/serialization/Schema.h +++ b/src/dawn/serialization/Schema.h
@@ -480,6 +480,14 @@ DAWN_REPLAY_MAKE_RENDER_PASS_CMD_AND_CMD_DATA(SetBindGroup, SET_BIND_GROUP_CMD_DATA_MEMBER){}; +#define SET_VERTEX_BUFFER_CMD_DATA_MEMBER(X) \ + X(uint32_t, slot) \ + X(ObjectId, bufferId) \ + X(uint64_t, offset) \ + X(uint64_t, size) + +DAWN_REPLAY_MAKE_RENDER_PASS_CMD_AND_CMD_DATA(SetVertexBuffer, SET_VERTEX_BUFFER_CMD_DATA_MEMBER){}; + #define DRAW_CMD_DATA_MEMBER(X) \ X(uint32_t, vertexCount) \ X(uint32_t, instanceCount) \
diff --git a/src/dawn/tests/white_box/CaptureAndReplayTests.cpp b/src/dawn/tests/white_box/CaptureAndReplayTests.cpp index 18dd68f..5d92ec6 100644 --- a/src/dawn/tests/white_box/CaptureAndReplayTests.cpp +++ b/src/dawn/tests/white_box/CaptureAndReplayTests.cpp
@@ -1306,6 +1306,83 @@ } } +TEST_P(CaptureAndReplayTests, CaptureRenderPassBasicWithAttributes) { + const float myVertices[] = { + -1, -1, 3, -1, -1, 3, + }; + + wgpu::BufferDescriptor descriptor; + descriptor.label = "vertexBuffer"; + descriptor.size = sizeof(myVertices); + descriptor.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Vertex; + wgpu::Buffer vertexBuffer = device.CreateBuffer(&descriptor); + + queue.WriteBuffer(vertexBuffer, 0, &myVertices, sizeof(myVertices)); + + wgpu::TextureDescriptor textureDesc; + textureDesc.label = "dstTexture"; + textureDesc.size = {1, 1, 1}; + textureDesc.format = wgpu::TextureFormat::RGBA8Uint; + textureDesc.usage = wgpu::TextureUsage::RenderAttachment; + wgpu::Texture dstTexture = device.CreateTexture(&textureDesc); + + const char* shader = R"( + @vertex fn vs(@location(0) pos: vec4f) -> @builtin(position) vec4f { + return pos; + } + + @fragment fn fs() -> @location(0) vec4u { + return vec4u(0x11, 0x22, 0x33, 0x44); + } + )"; + auto module = utils::CreateShaderModule(device, shader); + + utils::ComboRenderPipelineDescriptor desc; + desc.vertex.module = module; + desc.cFragment.module = module; + desc.cFragment.targetCount = 1; + desc.cTargets[0].format = wgpu::TextureFormat::RGBA8Uint; + desc.primitive.topology = wgpu::PrimitiveTopology::TriangleList; + desc.cBuffers[0].arrayStride = 2 * sizeof(float); + desc.cBuffers[0].attributeCount = 1; + desc.cBuffers[0].attributes = &desc.cAttributes[0]; + desc.cAttributes[0].shaderLocation = 0; + desc.cAttributes[0].format = wgpu::VertexFormat::Float32x2; + desc.vertex.bufferCount = 1; + wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc); + + wgpu::CommandBuffer commands; + { + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + + utils::ComboRenderPassDescriptor passDescriptor({dstTexture.CreateView()}); + wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&passDescriptor); + pass.SetPipeline(pipeline); + pass.SetVertexBuffer(0, vertexBuffer); + pass.Draw(3); + pass.End(); + + commands = encoder.Finish(); + } + + // --- capture --- + auto recorder = Recorder::CreateAndStart(device); + + queue.Submit(1, &commands); + + // --- replay --- + auto capture = recorder.Finish(); + auto replay = capture.Replay(device); + + { + wgpu::Texture texture = replay->GetObjectByLabel<wgpu::Texture>("dstTexture"); + ASSERT_NE(texture, nullptr); + + uint8_t expected[] = {0x11, 0x22, 0x33, 0x44}; + EXPECT_TEXTURE_EQ(&expected[0], texture, {0, 0}, {1, 1}, 0, wgpu::TextureAspect::All); + } +} + DAWN_INSTANTIATE_TEST(CaptureAndReplayTests, WebGPUBackend()); } // anonymous namespace