Skip to content

Commit 6ec2b46

Browse files
greggmanDawn LUCI CQ
authored andcommitted
Capture: Render Pass with pipeline/bindGroup
This is the next step up from a pass with no pipeline Bug: 451389801 Change-Id: I6a6a696417e832fb0a478bece207c55af3a340b8 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/268314 Reviewed-by: Kai Ninomiya <[email protected]> Commit-Queue: Gregg Tavares <[email protected]>
1 parent dd8f458 commit 6ec2b46

File tree

3 files changed

+237
-4
lines changed

3 files changed

+237
-4
lines changed

src/dawn/native/webgpu/BindGroupWGPU.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ MaybeError BindGroup::AddReferenced(CaptureContext& captureContext) {
135135
{
136136
BindGroupLayoutInternalBase* layout = GetLayout();
137137
const auto& bindingMap = layout->GetBindingMap();
138-
for (const auto& [bindingNumbers, apiBindingIndex] : bindingMap) {
138+
for (const auto& [bindingNumber, apiBindingIndex] : bindingMap) {
139139
BindingIndex bindingIndex = layout->AsBindingIndex(apiBindingIndex);
140140
const auto& bindingInfo = layout->GetAPIBindingInfo(apiBindingIndex);
141141

@@ -160,20 +160,32 @@ MaybeError BindGroup::CaptureCreationParameters(CaptureContext& captureContext)
160160
for (const auto& [bindingNumber, apiBindingIndex] : bindingMap) {
161161
BindingIndex bindingIndex = layout->AsBindingIndex(apiBindingIndex);
162162
const auto& bindingInfo = layout->GetAPIBindingInfo(apiBindingIndex);
163+
uint32_t binding = uint32_t(bindingNumber);
163164

164165
MatchVariant(
165166
bindingInfo.bindingLayout,
166167
[&](const BufferBindingInfo& info) {
167168
const auto& entry = GetBindingAsBufferBinding(bindingIndex);
168169
entries.push_back(schema::BindGroupEntry{{
169-
.binding = uint32_t(bindingNumber),
170+
.binding = binding,
170171
.bufferId = captureContext.GetId(entry.buffer),
171172
.offset = entry.offset,
172173
.size = entry.size,
173174
.samplerId = 0,
174175
.textureViewId = 0,
175176
}});
176177
},
178+
[&](const TextureBindingInfo& info) {
179+
const auto& entry = GetBindingAsTextureView(bindingIndex);
180+
entries.push_back(schema::BindGroupEntry{{
181+
.binding = binding,
182+
.bufferId = 0,
183+
.offset = 0,
184+
.size = 0,
185+
.samplerId = 0,
186+
.textureViewId = captureContext.GetId(entry),
187+
}});
188+
},
177189
[&](const auto& info) { DAWN_CHECK(false); });
178190
}
179191

src/dawn/replay/Replay.cpp

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,40 @@ wgpu::BindGroupEntry ToWGPU(const Replay& replay, const schema::BindGroupEntry&
117117
};
118118
}
119119

120+
wgpu::StencilFaceState ToWGPU(const schema::StencilFaceState& state) {
121+
return wgpu::StencilFaceState{
122+
.compare = state.compare,
123+
.failOp = state.failOp,
124+
.depthFailOp = state.depthFailOp,
125+
.passOp = state.passOp,
126+
};
127+
}
128+
129+
wgpu::BlendComponent ToWGPU(const schema::BlendComponent& component) {
130+
return wgpu::BlendComponent{
131+
.operation = component.operation,
132+
.srcFactor = component.srcFactor,
133+
.dstFactor = component.dstFactor,
134+
};
135+
}
136+
137+
wgpu::BlendState ToWGPU(const schema::BlendState& state) {
138+
return wgpu::BlendState{
139+
.color = ToWGPU(state.color),
140+
.alpha = ToWGPU(state.alpha),
141+
};
142+
}
143+
144+
bool IsBlendComponentEnabled(const wgpu::BlendComponent& component) {
145+
return component.operation != wgpu::BlendOperation::Add ||
146+
component.srcFactor != wgpu::BlendFactor::One ||
147+
component.dstFactor != wgpu::BlendFactor::Zero;
148+
}
149+
150+
bool IsBlendEnabled(const wgpu::BlendState& blend) {
151+
return IsBlendComponentEnabled(blend.color) || IsBlendComponentEnabled(blend.alpha);
152+
}
153+
120154
MaybeError ReadContentIntoBuffer(ReadHead& readHead,
121155
wgpu::Device device,
122156
wgpu::Buffer buffer,
@@ -230,6 +264,92 @@ ResultOrError<wgpu::ComputePipeline> CreateComputePipeline(const Replay& replay,
230264
return {computePipeline};
231265
}
232266

267+
template <typename F>
268+
ResultOrError<wgpu::RenderPipeline> CreateRenderPipeline(const Replay& replay,
269+
wgpu::Device device,
270+
ReadHead& readHead,
271+
const std::string& label,
272+
F func) {
273+
schema::RenderPipeline pipeline;
274+
DAWN_TRY(Deserialize(readHead, &pipeline));
275+
276+
std::vector<wgpu::ConstantEntry> vertexConstants = ToWGPU(pipeline.vertex.program.constants);
277+
std::vector<wgpu::ConstantEntry> fragmentConstants =
278+
ToWGPU(pipeline.fragment.program.constants);
279+
std::vector<wgpu::ColorTargetState> colorTargets;
280+
std::vector<wgpu::BlendState> blendStates(pipeline.fragment.targets.size());
281+
282+
wgpu::FragmentState* fragment = nullptr;
283+
wgpu::FragmentState fragmentState;
284+
if (pipeline.fragment.program.moduleId) {
285+
fragment = &fragmentState;
286+
fragmentState.module =
287+
replay.GetObjectById<wgpu::ShaderModule>(pipeline.fragment.program.moduleId);
288+
fragmentState.entryPoint = wgpu::StringView(pipeline.fragment.program.entryPoint);
289+
fragmentState.constantCount = fragmentConstants.size();
290+
fragmentState.constants = fragmentConstants.data();
291+
for (const auto& target : pipeline.fragment.targets) {
292+
wgpu::BlendState& blend = blendStates[colorTargets.size()];
293+
blend = ToWGPU(target.blend);
294+
colorTargets.push_back({
295+
.format = target.format,
296+
.blend = IsBlendEnabled(blend) ? &blend : nullptr,
297+
.writeMask = target.writeMask,
298+
});
299+
}
300+
fragmentState.targetCount = colorTargets.size();
301+
fragmentState.targets = colorTargets.data();
302+
}
303+
304+
wgpu::DepthStencilState* depthStencil = nullptr;
305+
wgpu::DepthStencilState depthStencilState;
306+
if (pipeline.depthStencil.format != wgpu::TextureFormat::Undefined) {
307+
depthStencil = &depthStencilState;
308+
depthStencilState.format = pipeline.depthStencil.format;
309+
depthStencilState.depthWriteEnabled = pipeline.depthStencil.depthWriteEnabled;
310+
depthStencilState.depthCompare = pipeline.depthStencil.depthCompare;
311+
depthStencilState.stencilFront = ToWGPU(pipeline.depthStencil.stencilFront);
312+
depthStencilState.stencilBack = ToWGPU(pipeline.depthStencil.stencilBack);
313+
depthStencilState.stencilReadMask = pipeline.depthStencil.stencilReadMask;
314+
depthStencilState.stencilWriteMask = pipeline.depthStencil.stencilWriteMask;
315+
depthStencilState.depthBias = pipeline.depthStencil.depthBias;
316+
depthStencilState.depthBiasSlopeScale = pipeline.depthStencil.depthBiasSlopeScale;
317+
depthStencilState.depthBiasClamp = pipeline.depthStencil.depthBiasClamp;
318+
}
319+
320+
wgpu::RenderPipelineDescriptor desc{
321+
.label = wgpu::StringView(label),
322+
.layout = replay.GetObjectById<wgpu::PipelineLayout>(pipeline.layoutId),
323+
.vertex =
324+
{
325+
.module =
326+
replay.GetObjectById<wgpu::ShaderModule>(pipeline.vertex.program.moduleId),
327+
.entryPoint = wgpu::StringView(pipeline.vertex.program.entryPoint),
328+
.constantCount = vertexConstants.size(),
329+
.constants = vertexConstants.data(),
330+
},
331+
.primitive =
332+
{
333+
.topology = pipeline.primitive.topology,
334+
.stripIndexFormat = pipeline.primitive.stripIndexFormat,
335+
.frontFace = pipeline.primitive.frontFace,
336+
.cullMode = pipeline.primitive.cullMode,
337+
.unclippedDepth = pipeline.primitive.unclippedDepth,
338+
},
339+
.depthStencil = depthStencil,
340+
.multisample =
341+
{
342+
.count = pipeline.multisample.count,
343+
.mask = pipeline.multisample.mask,
344+
.alphaToCoverageEnabled = pipeline.multisample.alphaToCoverageEnabled,
345+
},
346+
.fragment = fragment,
347+
};
348+
wgpu::RenderPipeline renderPipeline = device.CreateRenderPipeline(&desc);
349+
func(renderPipeline, pipeline.groupIndexIds);
350+
return {renderPipeline};
351+
}
352+
233353
ResultOrError<wgpu::ShaderModule> CreateShaderModule(wgpu::Device device,
234354
ReadHead& readHead,
235355
const std::string& label) {
@@ -554,6 +674,25 @@ MaybeError Replay::CreateResource(wgpu::Device device, ReadHead& readHead) {
554674
return {};
555675
}
556676

677+
case schema::ObjectType::RenderPipeline: {
678+
wgpu::RenderPipeline renderPipeline;
679+
DAWN_TRY_ASSIGN(
680+
renderPipeline,
681+
CreateRenderPipeline(
682+
*this, device, readHead, resource.label,
683+
[this](wgpu::RenderPipeline& renderPipeline,
684+
const std::vector<schema::BindGroupLayoutIndexIdPair>& groupIndexIds) {
685+
// Register any implicit bindgroups.
686+
for (const auto& groupIndexId : groupIndexIds) {
687+
wgpu::BindGroupLayout bgl =
688+
renderPipeline.GetBindGroupLayout(groupIndexId.groupIndex);
689+
mResources.insert({groupIndexId.bindGroupLayoutId, {"", bgl}});
690+
}
691+
}));
692+
mResources.insert({resource.id, {resource.label, renderPipeline}});
693+
return {};
694+
}
695+
557696
case schema::ObjectType::ShaderModule: {
558697
wgpu::ShaderModule shaderModule;
559698
DAWN_TRY_ASSIGN(shaderModule, CreateShaderModule(device, readHead, resource.label));
@@ -629,8 +768,7 @@ MaybeError Replay::Play() {
629768
break;
630769
}
631770
default: {
632-
// UNIMPLEMENTED();
633-
break;
771+
return DAWN_INTERNAL_ERROR("unimplemented root command");
634772
}
635773
}
636774
}

src/dawn/tests/white_box/CaptureAndReplayTests.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "dawn/replay/Replay.h"
3636
#include "dawn/tests/DawnTest.h"
3737
#include "dawn/tests/MockCallback.h"
38+
#include "dawn/utils/ComboRenderPipelineDescriptor.h"
3839
#include "dawn/utils/TestUtils.h"
3940
#include "dawn/utils/WGPUHelpers.h"
4041

@@ -1223,6 +1224,88 @@ TEST_P(CaptureAndReplayTests, CaptureRenderPassBasic) {
12231224
}
12241225
}
12251226

1227+
// Capture and replay the a render pass where a texture is rendered into another.
1228+
TEST_P(CaptureAndReplayTests, CaptureRenderPassBasicWithBindGroup) {
1229+
const uint8_t myData[] = {0x11, 0x22, 0x33, 0x44};
1230+
1231+
wgpu::TextureDescriptor textureDesc;
1232+
textureDesc.label = "srcTexture";
1233+
textureDesc.size = {1, 1, 1};
1234+
textureDesc.format = wgpu::TextureFormat::RGBA8Uint;
1235+
textureDesc.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst;
1236+
wgpu::Texture srcTexture = device.CreateTexture(&textureDesc);
1237+
1238+
{
1239+
wgpu::TexelCopyBufferLayout texelCopyBufferLayout =
1240+
utils::CreateTexelCopyBufferLayout(0, 4);
1241+
wgpu::TexelCopyTextureInfo texelCopyTextureInfo =
1242+
utils::CreateTexelCopyTextureInfo(srcTexture, 0, {0, 0, 0}, wgpu::TextureAspect::All);
1243+
wgpu::Extent3D extent = {1, 1, 1};
1244+
queue.WriteTexture(&texelCopyTextureInfo, myData, sizeof(myData), &texelCopyBufferLayout,
1245+
&extent);
1246+
}
1247+
1248+
textureDesc.usage = wgpu::TextureUsage::RenderAttachment;
1249+
textureDesc.label = "dstTexture";
1250+
wgpu::Texture dstTexture = device.CreateTexture(&textureDesc);
1251+
1252+
const char* shader = R"(
1253+
@group(0) @binding(0) var tex: texture_2d<u32>;
1254+
1255+
@vertex fn vs() -> @builtin(position) vec4f {
1256+
return vec4f(0.0, 0.0, 0.0, 1.0);
1257+
}
1258+
1259+
@fragment fn fs() -> @location(0) vec4u {
1260+
return textureLoad(tex, vec2u(0), 0);
1261+
}
1262+
)";
1263+
auto module = utils::CreateShaderModule(device, shader);
1264+
1265+
utils::ComboRenderPipelineDescriptor desc;
1266+
desc.vertex.module = module;
1267+
desc.cFragment.module = module;
1268+
desc.cFragment.targetCount = 1;
1269+
desc.cTargets[0].format = wgpu::TextureFormat::RGBA8Uint;
1270+
desc.primitive.topology = wgpu::PrimitiveTopology::PointList;
1271+
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
1272+
1273+
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
1274+
{
1275+
{0, srcTexture.CreateView()},
1276+
});
1277+
wgpu::CommandBuffer commands;
1278+
{
1279+
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1280+
1281+
utils::ComboRenderPassDescriptor passDescriptor({dstTexture.CreateView()});
1282+
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&passDescriptor);
1283+
pass.SetPipeline(pipeline);
1284+
pass.SetBindGroup(0, bindGroup);
1285+
pass.Draw(1);
1286+
pass.End();
1287+
1288+
commands = encoder.Finish();
1289+
}
1290+
1291+
// --- capture ---
1292+
auto recorder = Recorder::CreateAndStart(device);
1293+
1294+
queue.Submit(1, &commands);
1295+
1296+
// --- replay ---
1297+
auto capture = recorder.Finish();
1298+
auto replay = capture.Replay(device);
1299+
1300+
{
1301+
wgpu::Texture texture = replay->GetObjectByLabel<wgpu::Texture>("dstTexture");
1302+
ASSERT_NE(texture, nullptr);
1303+
1304+
uint8_t expected[] = {0x11, 0x22, 0x33, 0x44};
1305+
EXPECT_TEXTURE_EQ(&expected[0], texture, {0, 0}, {1, 1}, 0, wgpu::TextureAspect::All);
1306+
}
1307+
}
1308+
12261309
DAWN_INSTANTIATE_TEST(CaptureAndReplayTests, WebGPUBackend());
12271310

12281311
} // anonymous namespace

0 commit comments

Comments
 (0)