Make GetBindGroupLayout error for indices past the last defined BGL.

Fixed: dawn:1565
Change-Id: I8a482623fcbd68648c451499ce769b871cf89c0a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/104820
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Auto-Submit: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2022-10-07 22:02:20 +00:00 committed by Dawn LUCI CQ
parent b68cd1a212
commit 174b6bd5d9
4 changed files with 85 additions and 27 deletions

View File

@ -191,26 +191,26 @@ wgpu::ShaderStage PipelineBase::GetStageMask() const {
return mStageMask; return mStageMask;
} }
MaybeError PipelineBase::ValidateGetBindGroupLayout(uint32_t groupIndex) { MaybeError PipelineBase::ValidateGetBindGroupLayout(BindGroupIndex groupIndex) {
DAWN_TRY(GetDevice()->ValidateIsAlive()); DAWN_TRY(GetDevice()->ValidateIsAlive());
DAWN_TRY(GetDevice()->ValidateObject(this)); DAWN_TRY(GetDevice()->ValidateObject(this));
DAWN_TRY(GetDevice()->ValidateObject(mLayout.Get())); DAWN_TRY(GetDevice()->ValidateObject(mLayout.Get()));
DAWN_INVALID_IF(groupIndex >= kMaxBindGroups, DAWN_INVALID_IF(groupIndex >= kMaxBindGroupsTyped,
"Bind group layout index (%u) exceeds the maximum number of bind groups (%u).", "Bind group layout index (%u) exceeds the maximum number of bind groups (%u).",
groupIndex, kMaxBindGroups); static_cast<uint32_t>(groupIndex), kMaxBindGroups);
DAWN_INVALID_IF(
!mLayout->GetBindGroupLayoutsMask()[groupIndex],
"Bind group layout index (%u) doesn't correspond to a bind group for this pipeline.",
static_cast<uint32_t>(groupIndex));
return {}; return {};
} }
ResultOrError<Ref<BindGroupLayoutBase>> PipelineBase::GetBindGroupLayout(uint32_t groupIndexIn) { ResultOrError<Ref<BindGroupLayoutBase>> PipelineBase::GetBindGroupLayout(uint32_t groupIndexIn) {
DAWN_TRY(ValidateGetBindGroupLayout(groupIndexIn));
BindGroupIndex groupIndex(groupIndexIn); BindGroupIndex groupIndex(groupIndexIn);
if (!mLayout->GetBindGroupLayoutsMask()[groupIndex]) {
return Ref<BindGroupLayoutBase>(GetDevice()->GetEmptyBindGroupLayout()); DAWN_TRY(ValidateGetBindGroupLayout(groupIndex));
} else {
return Ref<BindGroupLayoutBase>(mLayout->GetBindGroupLayout(groupIndex)); return Ref<BindGroupLayoutBase>(mLayout->GetBindGroupLayout(groupIndex));
} }
}
BindGroupLayoutBase* PipelineBase::APIGetBindGroupLayout(uint32_t groupIndexIn) { BindGroupLayoutBase* PipelineBase::APIGetBindGroupLayout(uint32_t groupIndexIn) {
Ref<BindGroupLayoutBase> result; Ref<BindGroupLayoutBase> result;

View File

@ -84,7 +84,7 @@ class PipelineBase : public ApiObjectBase, public CachedObject {
explicit PipelineBase(DeviceBase* device); explicit PipelineBase(DeviceBase* device);
private: private:
MaybeError ValidateGetBindGroupLayout(uint32_t group); MaybeError ValidateGetBindGroupLayout(BindGroupIndex group);
wgpu::ShaderStage mStageMask = wgpu::ShaderStage::None; wgpu::ShaderStage mStageMask = wgpu::ShaderStage::None;
PerStage<ProgrammableStage> mStages; PerStage<ProgrammableStage> mStages;

View File

@ -2062,6 +2062,51 @@ TEST_F(SetBindGroupValidationTest, ErrorBindGroup) {
TestComputePassBindGroup(bindGroup, nullptr, 0, false); TestComputePassBindGroup(bindGroup, nullptr, 0, false);
} }
// Test that a pipeline with empty bindgroups layouts requires empty bindgroups to be set.
TEST_F(SetBindGroupValidationTest, EmptyBindGroupsAreRequired) {
wgpu::BindGroupLayout emptyBGL = utils::MakeBindGroupLayout(device, {});
wgpu::PipelineLayout pl =
utils::MakePipelineLayout(device, {emptyBGL, emptyBGL, emptyBGL, emptyBGL});
wgpu::ComputePipelineDescriptor pipelineDesc;
pipelineDesc.layout = pl;
pipelineDesc.compute.entryPoint = "main";
pipelineDesc.compute.module = utils::CreateShaderModule(device, R"(
@compute @workgroup_size(1) fn main() {
}
)");
wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&pipelineDesc);
wgpu::BindGroup emptyBindGroup = utils::MakeBindGroup(device, emptyBGL, {});
// Control case, setting 4 empty bindgroups works.
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, emptyBindGroup);
pass.SetBindGroup(1, emptyBindGroup);
pass.SetBindGroup(2, emptyBindGroup);
pass.SetBindGroup(3, emptyBindGroup);
pass.DispatchWorkgroups(1);
pass.End();
encoder.Finish();
}
// Error case, setting only the first three empty bindgroups.
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, emptyBindGroup);
pass.SetBindGroup(1, emptyBindGroup);
pass.SetBindGroup(2, emptyBindGroup);
pass.DispatchWorkgroups(1);
pass.End();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
}
class SetBindGroupPersistenceValidationTest : public ValidationTest { class SetBindGroupPersistenceValidationTest : public ValidationTest {
protected: protected:
void SetUp() override { void SetUp() override {

View File

@ -980,7 +980,8 @@ TEST_F(GetBindGroupLayoutTests, OutOfRangeIndex) {
.GetBindGroupLayout(kMaxBindGroups + 1)); .GetBindGroupLayout(kMaxBindGroups + 1));
} }
// Test that unused indices return the empty bind group layout. // Test that unused indices return the empty bind group layout if before the last used index, an
// error otherwise.
TEST_F(GetBindGroupLayoutTests, UnusedIndex) { TEST_F(GetBindGroupLayoutTests, UnusedIndex) {
// This test works assuming Dawn Native's object deduplication. // This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn // Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
@ -1011,8 +1012,7 @@ TEST_F(GetBindGroupLayoutTests, UnusedIndex) {
pipeline.GetBindGroupLayout(1).Get(), emptyBindGroupLayout.Get())); // Not Used. pipeline.GetBindGroupLayout(1).Get(), emptyBindGroupLayout.Get())); // Not Used.
EXPECT_FALSE(dawn::native::BindGroupLayoutBindingsEqualForTesting( EXPECT_FALSE(dawn::native::BindGroupLayoutBindingsEqualForTesting(
pipeline.GetBindGroupLayout(2).Get(), emptyBindGroupLayout.Get())); // Used. pipeline.GetBindGroupLayout(2).Get(), emptyBindGroupLayout.Get())); // Used.
EXPECT_TRUE(dawn::native::BindGroupLayoutBindingsEqualForTesting( ASSERT_DEVICE_ERROR(pipeline.GetBindGroupLayout(3)); // Past last defined BGL, error!
pipeline.GetBindGroupLayout(3).Get(), emptyBindGroupLayout.Get())); // Not used
} }
// Test that after explicitly creating a pipeline with a pipeline layout, calling // Test that after explicitly creating a pipeline with a pipeline layout, calling
@ -1064,19 +1064,6 @@ TEST_F(GetBindGroupLayoutTests, Reflection) {
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc); wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
EXPECT_EQ(pipeline.GetBindGroupLayout(0).Get(), bindGroupLayout.Get()); EXPECT_EQ(pipeline.GetBindGroupLayout(0).Get(), bindGroupLayout.Get());
{
wgpu::BindGroupLayoutDescriptor emptyDesc = {};
emptyDesc.entryCount = 0;
emptyDesc.entries = nullptr;
wgpu::BindGroupLayout emptyBindGroupLayout = device.CreateBindGroupLayout(&emptyDesc);
// Check that the rest of the bind group layouts reflect the empty one.
EXPECT_EQ(pipeline.GetBindGroupLayout(1).Get(), emptyBindGroupLayout.Get());
EXPECT_EQ(pipeline.GetBindGroupLayout(2).Get(), emptyBindGroupLayout.Get());
EXPECT_EQ(pipeline.GetBindGroupLayout(3).Get(), emptyBindGroupLayout.Get());
}
} }
// Test that fragment output validation is for the correct entryPoint // Test that fragment output validation is for the correct entryPoint
@ -1123,3 +1110,29 @@ TEST_F(GetBindGroupLayoutTests, FromCorrectEntryPoint) {
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl0, {{1, buffer}})); ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl0, {{1, buffer}}));
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl1, {{0, buffer}})); ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl1, {{0, buffer}}));
} }
// Test that a pipeline full of explicitly empty BGLs correctly reflects them.
TEST_F(GetBindGroupLayoutTests, FullOfEmptyBGLs) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::BindGroupLayout emptyBGL = utils::MakeBindGroupLayout(device, {});
wgpu::PipelineLayout pl =
utils::MakePipelineLayout(device, {emptyBGL, emptyBGL, emptyBGL, emptyBGL});
wgpu::ComputePipelineDescriptor pipelineDesc;
pipelineDesc.layout = pl;
pipelineDesc.compute.entryPoint = "main";
pipelineDesc.compute.module = utils::CreateShaderModule(device, R"(
@compute @workgroup_size(1) fn main() {
}
)");
wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&pipelineDesc);
EXPECT_EQ(pipeline.GetBindGroupLayout(0).Get(), emptyBGL.Get());
EXPECT_EQ(pipeline.GetBindGroupLayout(1).Get(), emptyBGL.Get());
EXPECT_EQ(pipeline.GetBindGroupLayout(2).Get(), emptyBGL.Get());
EXPECT_EQ(pipeline.GetBindGroupLayout(3).Get(), emptyBGL.Get());
}