metal: Use single-entry point transform

We only remap bindings for the target entry point, so we need to strip
all other entry points to avoid generating invalid bindings for them.

Bug: tint:1170
Change-Id: Ia1a73601e8d620341fb4f7170dfa856632a04245
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/63880
Commit-Queue: James Price <jrprice@google.com>
Auto-Submit: James Price <jrprice@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
James Price 2021-09-09 20:40:31 +00:00 committed by Dawn LUCI CQ
parent 3bc6716a77
commit 6e1f01f32b
2 changed files with 124 additions and 1 deletions

View File

@ -92,6 +92,11 @@ namespace dawn_native { namespace metal {
tint::transform::Manager transformManager;
tint::transform::DataMap transformInputs;
// We only remap bindings for the target entry point, so we need to strip all other entry
// points to avoid generating invalid bindings for them.
transformManager.Add<tint::transform::SingleEntryPoint>();
transformInputs.Add<tint::transform::SingleEntryPoint::Config>(entryPointName);
if (stage == SingleShaderStage::Vertex &&
GetDevice()->IsToggleEnabled(Toggle::MetalEnableVertexPulling)) {
transformManager.Add<tint::transform::VertexPulling>();
@ -123,7 +128,6 @@ namespace dawn_native { namespace metal {
tint::transform::Renamer::Target::kMslKeywords);
}
transformInputs.Add<BindingRemapper::Remappings>(std::move(bindingPoints),
std::move(accessControls),
/* mayCollide */ true);

View File

@ -421,6 +421,125 @@ TEST_P(BindGroupTests, MultipleBindLayouts) {
EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, max, max);
}
// This is a regression test for crbug.com/dawn/1170 that tests a module that contains multiple
// entry points, using non-zero binding groups. This has the potential to cause problems when we
// only remap bindings for one entry point, as the remaining unmapped binding numbers may be invalid
// for certain backends.
// This test passes by not asserting or crashing.
TEST_P(BindGroupTests, MultipleEntryPointsWithMultipleNonZeroGroups) {
wgpu::ShaderModule module = utils::CreateShaderModule(device, R"(
[[block]] struct Contents {
f : f32;
};
[[group(0), binding(0)]] var <uniform> contents0: Contents;
[[group(1), binding(0)]] var <uniform> contents1: Contents;
[[group(2), binding(0)]] var <uniform> contents2: Contents;
[[stage(compute), workgroup_size(1)]] fn main0() {
var a : f32 = contents0.f;
}
[[stage(compute), workgroup_size(1)]] fn main1() {
var a : f32 = contents1.f;
var b : f32 = contents2.f;
}
[[stage(compute), workgroup_size(1)]] fn main2() {
var a : f32 = contents0.f;
var b : f32 = contents1.f;
var c : f32 = contents2.f;
})");
// main0: bind (0,0)
{
wgpu::ComputePipelineDescriptor cpDesc;
cpDesc.compute.module = module;
cpDesc.compute.entryPoint = "main0";
wgpu::ComputePipeline cp = device.CreateComputePipeline(&cpDesc);
wgpu::BufferDescriptor bufferDesc;
bufferDesc.size = sizeof(float);
bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform;
wgpu::Buffer buffer0 = device.CreateBuffer(&bufferDesc);
wgpu::BindGroup bindGroup0 =
utils::MakeBindGroup(device, cp.GetBindGroupLayout(0), {{0, buffer0}});
wgpu::CommandBuffer cb;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(cp);
pass.SetBindGroup(0, bindGroup0);
pass.Dispatch(1);
pass.EndPass();
cb = encoder.Finish();
queue.Submit(1, &cb);
}
// main1: bind (1,0) and (2,0)
{
wgpu::ComputePipelineDescriptor cpDesc;
cpDesc.compute.module = module;
cpDesc.compute.entryPoint = "main1";
wgpu::ComputePipeline cp = device.CreateComputePipeline(&cpDesc);
wgpu::BufferDescriptor bufferDesc;
bufferDesc.size = sizeof(float);
bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform;
wgpu::Buffer buffer1 = device.CreateBuffer(&bufferDesc);
wgpu::Buffer buffer2 = device.CreateBuffer(&bufferDesc);
wgpu::BindGroup bindGroup0 = utils::MakeBindGroup(device, cp.GetBindGroupLayout(0), {});
wgpu::BindGroup bindGroup1 =
utils::MakeBindGroup(device, cp.GetBindGroupLayout(1), {{0, buffer1}});
wgpu::BindGroup bindGroup2 =
utils::MakeBindGroup(device, cp.GetBindGroupLayout(2), {{0, buffer2}});
wgpu::CommandBuffer cb;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(cp);
pass.SetBindGroup(0, bindGroup0);
pass.SetBindGroup(1, bindGroup1);
pass.SetBindGroup(2, bindGroup2);
pass.Dispatch(1);
pass.EndPass();
cb = encoder.Finish();
queue.Submit(1, &cb);
}
// main2: bind (0,0), (1,0), and (2,0)
{
wgpu::ComputePipelineDescriptor cpDesc;
cpDesc.compute.module = module;
cpDesc.compute.entryPoint = "main2";
wgpu::ComputePipeline cp = device.CreateComputePipeline(&cpDesc);
wgpu::BufferDescriptor bufferDesc;
bufferDesc.size = sizeof(float);
bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform;
wgpu::Buffer buffer0 = device.CreateBuffer(&bufferDesc);
wgpu::Buffer buffer1 = device.CreateBuffer(&bufferDesc);
wgpu::Buffer buffer2 = device.CreateBuffer(&bufferDesc);
wgpu::BindGroup bindGroup0 =
utils::MakeBindGroup(device, cp.GetBindGroupLayout(0), {{0, buffer0}});
wgpu::BindGroup bindGroup1 =
utils::MakeBindGroup(device, cp.GetBindGroupLayout(1), {{0, buffer1}});
wgpu::BindGroup bindGroup2 =
utils::MakeBindGroup(device, cp.GetBindGroupLayout(2), {{0, buffer2}});
wgpu::CommandBuffer cb;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(cp);
pass.SetBindGroup(0, bindGroup0);
pass.SetBindGroup(1, bindGroup1);
pass.SetBindGroup(2, bindGroup2);
pass.Dispatch(1);
pass.EndPass();
cb = encoder.Finish();
queue.Submit(1, &cb);
}
}
// This test reproduces an out-of-bound bug on D3D12 backends when calling draw command twice with
// one pipeline that has 4 bind group sets in one render pass.
TEST_P(BindGroupTests, DrawTwiceInSamePipelineWithFourBindGroupSets) {