mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-08 06:05:55 +00:00
Add more resource binding related validation tests
This change adds more resource binding related tests to clarify some validation rules. Bug: dawn:359 Change-Id: I16eca96c22c0d5f3f16dce5151bcabfd04d28349 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/18940 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Yunchao He <yunchao.he@intel.com>
This commit is contained in:
parent
37193aa3b3
commit
81091b7434
@ -166,7 +166,6 @@ test("dawn_unittests") {
|
|||||||
"unittests/validation/QueueSubmitValidationTests.cpp",
|
"unittests/validation/QueueSubmitValidationTests.cpp",
|
||||||
"unittests/validation/RenderBundleValidationTests.cpp",
|
"unittests/validation/RenderBundleValidationTests.cpp",
|
||||||
"unittests/validation/RenderPassDescriptorValidationTests.cpp",
|
"unittests/validation/RenderPassDescriptorValidationTests.cpp",
|
||||||
"unittests/validation/RenderPassValidationTests.cpp",
|
|
||||||
"unittests/validation/RenderPipelineValidationTests.cpp",
|
"unittests/validation/RenderPipelineValidationTests.cpp",
|
||||||
"unittests/validation/ResourceUsageTrackingTests.cpp",
|
"unittests/validation/ResourceUsageTrackingTests.cpp",
|
||||||
"unittests/validation/SamplerValidationTests.cpp",
|
"unittests/validation/SamplerValidationTests.cpp",
|
||||||
|
@ -21,6 +21,21 @@
|
|||||||
|
|
||||||
class BindGroupValidationTest : public ValidationTest {
|
class BindGroupValidationTest : public ValidationTest {
|
||||||
public:
|
public:
|
||||||
|
wgpu::Texture CreateTexture(wgpu::TextureUsage usage,
|
||||||
|
wgpu::TextureFormat format,
|
||||||
|
uint32_t layerCount) {
|
||||||
|
wgpu::TextureDescriptor descriptor;
|
||||||
|
descriptor.dimension = wgpu::TextureDimension::e2D;
|
||||||
|
descriptor.size = {16, 16, 1};
|
||||||
|
descriptor.sampleCount = 1;
|
||||||
|
descriptor.mipLevelCount = 1;
|
||||||
|
descriptor.usage = usage;
|
||||||
|
descriptor.format = format;
|
||||||
|
descriptor.arrayLayerCount = layerCount;
|
||||||
|
|
||||||
|
return device.CreateTexture(&descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
// Create objects to use as resources inside test bind groups.
|
// Create objects to use as resources inside test bind groups.
|
||||||
{
|
{
|
||||||
@ -40,15 +55,8 @@ class BindGroupValidationTest : public ValidationTest {
|
|||||||
mSampler = device.CreateSampler(&descriptor);
|
mSampler = device.CreateSampler(&descriptor);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
wgpu::TextureDescriptor descriptor;
|
mSampledTexture =
|
||||||
descriptor.dimension = wgpu::TextureDimension::e2D;
|
CreateTexture(wgpu::TextureUsage::Sampled, wgpu::TextureFormat::RGBA8Unorm, 1);
|
||||||
descriptor.size = {16, 16, 1};
|
|
||||||
descriptor.arrayLayerCount = 1;
|
|
||||||
descriptor.sampleCount = 1;
|
|
||||||
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
|
|
||||||
descriptor.mipLevelCount = 1;
|
|
||||||
descriptor.usage = wgpu::TextureUsage::Sampled;
|
|
||||||
mSampledTexture = device.CreateTexture(&descriptor);
|
|
||||||
mSampledTextureView = mSampledTexture.CreateView();
|
mSampledTextureView = mSampledTexture.CreateView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -288,15 +296,8 @@ TEST_F(BindGroupValidationTest, TextureUsage) {
|
|||||||
utils::MakeBindGroup(device, layout, {{0, mSampledTextureView}});
|
utils::MakeBindGroup(device, layout, {{0, mSampledTextureView}});
|
||||||
|
|
||||||
// Make an output attachment texture and try to set it for a SampledTexture binding
|
// Make an output attachment texture and try to set it for a SampledTexture binding
|
||||||
wgpu::TextureDescriptor descriptor;
|
wgpu::Texture outputTexture =
|
||||||
descriptor.dimension = wgpu::TextureDimension::e2D;
|
CreateTexture(wgpu::TextureUsage::OutputAttachment, wgpu::TextureFormat::RGBA8Unorm, 1);
|
||||||
descriptor.size = {16, 16, 1};
|
|
||||||
descriptor.arrayLayerCount = 1;
|
|
||||||
descriptor.sampleCount = 1;
|
|
||||||
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
|
|
||||||
descriptor.mipLevelCount = 1;
|
|
||||||
descriptor.usage = wgpu::TextureUsage::OutputAttachment;
|
|
||||||
wgpu::Texture outputTexture = device.CreateTexture(&descriptor);
|
|
||||||
wgpu::TextureView outputTextureView = outputTexture.CreateView();
|
wgpu::TextureView outputTextureView = outputTexture.CreateView();
|
||||||
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, outputTextureView}}));
|
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, outputTextureView}}));
|
||||||
}
|
}
|
||||||
@ -311,15 +312,8 @@ TEST_F(BindGroupValidationTest, TextureComponentType) {
|
|||||||
utils::MakeBindGroup(device, layout, {{0, mSampledTextureView}});
|
utils::MakeBindGroup(device, layout, {{0, mSampledTextureView}});
|
||||||
|
|
||||||
// Make a Uint component typed texture and try to set it to a Float component binding.
|
// Make a Uint component typed texture and try to set it to a Float component binding.
|
||||||
wgpu::TextureDescriptor descriptor;
|
wgpu::Texture uintTexture =
|
||||||
descriptor.dimension = wgpu::TextureDimension::e2D;
|
CreateTexture(wgpu::TextureUsage::Sampled, wgpu::TextureFormat::RGBA8Uint, 1);
|
||||||
descriptor.size = {16, 16, 1};
|
|
||||||
descriptor.arrayLayerCount = 1;
|
|
||||||
descriptor.sampleCount = 1;
|
|
||||||
descriptor.format = wgpu::TextureFormat::RGBA8Uint;
|
|
||||||
descriptor.mipLevelCount = 1;
|
|
||||||
descriptor.usage = wgpu::TextureUsage::Sampled;
|
|
||||||
wgpu::Texture uintTexture = device.CreateTexture(&descriptor);
|
|
||||||
wgpu::TextureView uintTextureView = uintTexture.CreateView();
|
wgpu::TextureView uintTextureView = uintTexture.CreateView();
|
||||||
|
|
||||||
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, uintTextureView}}));
|
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, uintTextureView}}));
|
||||||
@ -335,15 +329,8 @@ TEST_F(BindGroupValidationTest, TextureDimension) {
|
|||||||
utils::MakeBindGroup(device, layout, {{0, mSampledTextureView}});
|
utils::MakeBindGroup(device, layout, {{0, mSampledTextureView}});
|
||||||
|
|
||||||
// Make a 2DArray texture and try to set it to a 2D binding.
|
// Make a 2DArray texture and try to set it to a 2D binding.
|
||||||
wgpu::TextureDescriptor descriptor;
|
wgpu::Texture arrayTexture =
|
||||||
descriptor.dimension = wgpu::TextureDimension::e2D;
|
CreateTexture(wgpu::TextureUsage::Sampled, wgpu::TextureFormat::RGBA8Uint, 2);
|
||||||
descriptor.size = {16, 16, 1};
|
|
||||||
descriptor.arrayLayerCount = 2;
|
|
||||||
descriptor.sampleCount = 1;
|
|
||||||
descriptor.format = wgpu::TextureFormat::RGBA8Uint;
|
|
||||||
descriptor.mipLevelCount = 1;
|
|
||||||
descriptor.usage = wgpu::TextureUsage::Sampled;
|
|
||||||
wgpu::Texture arrayTexture = device.CreateTexture(&descriptor);
|
|
||||||
wgpu::TextureView arrayTextureView = arrayTexture.CreateView();
|
wgpu::TextureView arrayTextureView = arrayTexture.CreateView();
|
||||||
|
|
||||||
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, arrayTextureView}}));
|
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, arrayTextureView}}));
|
||||||
@ -1226,7 +1213,7 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
|
|||||||
return device.CreateBuffer(&bufferDescriptor);
|
return device.CreateBuffer(&bufferDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu::RenderPipeline CreateRenderPipeline(wgpu::BindGroupLayout* bindGroupLayout) {
|
wgpu::RenderPipeline CreateRenderPipeline(std::vector<wgpu::BindGroupLayout> bindGroupLayout) {
|
||||||
wgpu::ShaderModule vsModule =
|
wgpu::ShaderModule vsModule =
|
||||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
||||||
#version 450
|
#version 450
|
||||||
@ -1239,23 +1226,26 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
|
|||||||
layout(std140, set = 0, binding = 0) buffer SBuffer {
|
layout(std140, set = 0, binding = 0) buffer SBuffer {
|
||||||
vec2 value2;
|
vec2 value2;
|
||||||
} sBuffer;
|
} sBuffer;
|
||||||
layout(std140, set = 0, binding = 1) readonly buffer RBuffer {
|
layout(std140, set = 1, binding = 0) readonly buffer RBuffer {
|
||||||
vec2 value3;
|
vec2 value3;
|
||||||
} rBuffer;
|
} rBuffer;
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
void main() {
|
void main() {
|
||||||
})");
|
})");
|
||||||
|
|
||||||
|
wgpu::PipelineLayoutDescriptor descriptor;
|
||||||
|
descriptor.bindGroupLayoutCount = bindGroupLayout.size();
|
||||||
|
descriptor.bindGroupLayouts = bindGroupLayout.data();
|
||||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
|
||||||
pipelineDescriptor.vertexStage.module = vsModule;
|
pipelineDescriptor.vertexStage.module = vsModule;
|
||||||
pipelineDescriptor.cFragmentStage.module = fsModule;
|
pipelineDescriptor.cFragmentStage.module = fsModule;
|
||||||
wgpu::PipelineLayout pipelineLayout =
|
wgpu::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&descriptor);
|
||||||
utils::MakeBasicPipelineLayout(device, bindGroupLayout);
|
|
||||||
pipelineDescriptor.layout = pipelineLayout;
|
pipelineDescriptor.layout = pipelineLayout;
|
||||||
return device.CreateRenderPipeline(&pipelineDescriptor);
|
return device.CreateRenderPipeline(&pipelineDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgpu::ComputePipeline CreateComputePipeline(wgpu::BindGroupLayout* bindGroupLayout) {
|
wgpu::ComputePipeline CreateComputePipeline(
|
||||||
|
std::vector<wgpu::BindGroupLayout> bindGroupLayout) {
|
||||||
wgpu::ShaderModule csModule =
|
wgpu::ShaderModule csModule =
|
||||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
|
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
|
||||||
#version 450
|
#version 450
|
||||||
@ -1266,14 +1256,16 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
|
|||||||
layout(std140, set = 0, binding = 0) buffer SBuffer {
|
layout(std140, set = 0, binding = 0) buffer SBuffer {
|
||||||
float value2;
|
float value2;
|
||||||
} dst;
|
} dst;
|
||||||
layout(std140, set = 0, binding = 1) readonly buffer RBuffer {
|
layout(std140, set = 1, binding = 0) readonly buffer RBuffer {
|
||||||
readonly float value3;
|
readonly float value3;
|
||||||
} rdst;
|
} rdst;
|
||||||
void main() {
|
void main() {
|
||||||
})");
|
})");
|
||||||
|
|
||||||
wgpu::PipelineLayout pipelineLayout =
|
wgpu::PipelineLayoutDescriptor descriptor;
|
||||||
utils::MakeBasicPipelineLayout(device, bindGroupLayout);
|
descriptor.bindGroupLayoutCount = bindGroupLayout.size();
|
||||||
|
descriptor.bindGroupLayouts = bindGroupLayout.data();
|
||||||
|
wgpu::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&descriptor);
|
||||||
|
|
||||||
wgpu::ComputePipelineDescriptor csDesc;
|
wgpu::ComputePipelineDescriptor csDesc;
|
||||||
csDesc.layout = pipelineLayout;
|
csDesc.layout = pipelineLayout;
|
||||||
@ -1284,34 +1276,221 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Test cases that test bind group layout mismatch with shader. The second item in bind group layout
|
// Test that it is valid to pass a writable storage buffer in the pipeline layout when the shader
|
||||||
// is a writable storage buffer, but the second item in shader is a readonly storage buffer. It is
|
// uses the binding as a readonly storage buffer.
|
||||||
// valid.
|
|
||||||
TEST_F(BindGroupLayoutCompatibilityTest, RWStorageInBGLWithROStorageInShader) {
|
TEST_F(BindGroupLayoutCompatibilityTest, RWStorageInBGLWithROStorageInShader) {
|
||||||
// Set up the bind group layout.
|
// Set up the bind group layout.
|
||||||
wgpu::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
|
wgpu::BindGroupLayout bgl0 = utils::MakeBindGroupLayout(
|
||||||
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
wgpu::BindingType::StorageBuffer, true},
|
wgpu::BindingType::StorageBuffer}});
|
||||||
{1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
wgpu::BindGroupLayout bgl1 = utils::MakeBindGroupLayout(
|
||||||
wgpu::BindingType::StorageBuffer, true}});
|
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::StorageBuffer}});
|
||||||
|
|
||||||
CreateRenderPipeline(&bindGroupLayout);
|
CreateRenderPipeline({bgl0, bgl1});
|
||||||
|
|
||||||
CreateComputePipeline(&bindGroupLayout);
|
CreateComputePipeline({bgl0, bgl1});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test cases that test bind group layout mismatch with shader. The first item in bind group layout
|
// Test that it is invalid to pass a readonly storage buffer in the pipeline layout when the shader
|
||||||
// is a readonly storage buffer, but the first item in shader is a writable storage buffer. It is
|
// uses the binding as a writable storage buffer.
|
||||||
// invalid.
|
|
||||||
TEST_F(BindGroupLayoutCompatibilityTest, ROStorageInBGLWithRWStorageInShader) {
|
TEST_F(BindGroupLayoutCompatibilityTest, ROStorageInBGLWithRWStorageInShader) {
|
||||||
// Set up the bind group layout.
|
// Set up the bind group layout.
|
||||||
wgpu::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
|
wgpu::BindGroupLayout bgl0 = utils::MakeBindGroupLayout(
|
||||||
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
wgpu::BindingType::ReadonlyStorageBuffer, true},
|
wgpu::BindingType::ReadonlyStorageBuffer}});
|
||||||
{1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
wgpu::BindGroupLayout bgl1 = utils::MakeBindGroupLayout(
|
||||||
wgpu::BindingType::ReadonlyStorageBuffer, true}});
|
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::ReadonlyStorageBuffer}});
|
||||||
|
|
||||||
ASSERT_DEVICE_ERROR(CreateRenderPipeline(&bindGroupLayout));
|
ASSERT_DEVICE_ERROR(CreateRenderPipeline({bgl0, bgl1}));
|
||||||
|
|
||||||
ASSERT_DEVICE_ERROR(CreateComputePipeline(&bindGroupLayout));
|
ASSERT_DEVICE_ERROR(CreateComputePipeline({bgl0, bgl1}));
|
||||||
|
}
|
||||||
|
|
||||||
|
class BindingsValidationTest : public BindGroupLayoutCompatibilityTest {
|
||||||
|
public:
|
||||||
|
void TestRenderPassBindings(const wgpu::BindGroup* bg,
|
||||||
|
uint32_t count,
|
||||||
|
wgpu::RenderPipeline pipeline,
|
||||||
|
bool expectation) {
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
DummyRenderPass dummyRenderPass(device);
|
||||||
|
wgpu::RenderPassEncoder rp = encoder.BeginRenderPass(&dummyRenderPass);
|
||||||
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
|
rp.SetBindGroup(i, bg[i]);
|
||||||
|
}
|
||||||
|
rp.SetPipeline(pipeline);
|
||||||
|
rp.Draw(3);
|
||||||
|
rp.EndPass();
|
||||||
|
if (!expectation) {
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
} else {
|
||||||
|
encoder.Finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestComputePassBindings(const wgpu::BindGroup* bg,
|
||||||
|
uint32_t count,
|
||||||
|
wgpu::ComputePipeline pipeline,
|
||||||
|
bool expectation) {
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::ComputePassEncoder cp = encoder.BeginComputePass();
|
||||||
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
|
cp.SetBindGroup(i, bg[i]);
|
||||||
|
}
|
||||||
|
cp.SetPipeline(pipeline);
|
||||||
|
cp.Dispatch(1);
|
||||||
|
cp.EndPass();
|
||||||
|
if (!expectation) {
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
} else {
|
||||||
|
encoder.Finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t kBindingNum = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test that it is valid to set a pipeline layout with bindings unused by the pipeline.
|
||||||
|
TEST_F(BindingsValidationTest, PipelineLayoutWithMoreBindingsThanPipeline) {
|
||||||
|
// Set up bind group layouts.
|
||||||
|
wgpu::BindGroupLayout bgl0 = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::StorageBuffer},
|
||||||
|
{1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::UniformBuffer}});
|
||||||
|
wgpu::BindGroupLayout bgl1 = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::ReadonlyStorageBuffer}});
|
||||||
|
wgpu::BindGroupLayout bgl2 = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::StorageBuffer}});
|
||||||
|
|
||||||
|
// pipelineLayout has unused binding set (bgl2) and unused entry in a binding set (bgl0).
|
||||||
|
CreateRenderPipeline({bgl0, bgl1, bgl2});
|
||||||
|
|
||||||
|
CreateComputePipeline({bgl0, bgl1, bgl2});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that it is invalid to set a pipeline layout that doesn't have all necessary bindings
|
||||||
|
// required by the pipeline.
|
||||||
|
TEST_F(BindingsValidationTest, PipelineLayoutWithLessBindingsThanPipeline) {
|
||||||
|
// Set up bind group layout.
|
||||||
|
wgpu::BindGroupLayout bgl0 = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::StorageBuffer}});
|
||||||
|
|
||||||
|
// missing a binding set (bgl1) in pipeline layout
|
||||||
|
{
|
||||||
|
ASSERT_DEVICE_ERROR(CreateRenderPipeline({bgl0}));
|
||||||
|
|
||||||
|
ASSERT_DEVICE_ERROR(CreateComputePipeline({bgl0}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// bgl1 is not missing, but it is empty
|
||||||
|
{
|
||||||
|
wgpu::BindGroupLayout bgl1 = utils::MakeBindGroupLayout(device, {});
|
||||||
|
|
||||||
|
ASSERT_DEVICE_ERROR(CreateRenderPipeline({bgl0, bgl1}));
|
||||||
|
|
||||||
|
ASSERT_DEVICE_ERROR(CreateComputePipeline({bgl0, bgl1}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// bgl1 is neither missing nor empty, but it doesn't contain the necessary binding
|
||||||
|
{
|
||||||
|
wgpu::BindGroupLayout bgl1 = utils::MakeBindGroupLayout(
|
||||||
|
device, {{1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::UniformBuffer}});
|
||||||
|
|
||||||
|
ASSERT_DEVICE_ERROR(CreateRenderPipeline({bgl0, bgl1}));
|
||||||
|
|
||||||
|
ASSERT_DEVICE_ERROR(CreateComputePipeline({bgl0, bgl1}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that it is valid to set bind groups whose layout is not set in the pipeline layout.
|
||||||
|
// But it's invalid to set extra entry for a given bind group's layout if that layout is set in
|
||||||
|
// the pipeline layout.
|
||||||
|
TEST_F(BindingsValidationTest, BindGroupsWithMoreBindingsThanPipelineLayout) {
|
||||||
|
// Set up bind group layouts, buffers, bind groups, pipeline layouts and pipelines.
|
||||||
|
std::array<wgpu::BindGroupLayout, kBindingNum + 1> bgl;
|
||||||
|
std::array<wgpu::BindGroup, kBindingNum + 1> bg;
|
||||||
|
std::array<wgpu::Buffer, kBindingNum + 1> buffer;
|
||||||
|
for (uint32_t i = 0; i < kBindingNum + 1; ++i) {
|
||||||
|
bgl[i] = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::StorageBuffer}});
|
||||||
|
buffer[i] = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
|
||||||
|
bg[i] = utils::MakeBindGroup(device, bgl[i], {{0, buffer[i]}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set 3 bindings (and 3 pipeline layouts) in pipeline.
|
||||||
|
wgpu::RenderPipeline renderPipeline = CreateRenderPipeline({bgl[0], bgl[1], bgl[2]});
|
||||||
|
wgpu::ComputePipeline computePipeline = CreateComputePipeline({bgl[0], bgl[1], bgl[2]});
|
||||||
|
|
||||||
|
// Comprared to pipeline layout, there is an extra bind group (bg[3])
|
||||||
|
TestRenderPassBindings(bg.data(), kBindingNum + 1, renderPipeline, true);
|
||||||
|
|
||||||
|
TestComputePassBindings(bg.data(), kBindingNum + 1, computePipeline, true);
|
||||||
|
|
||||||
|
// If a bind group has entry (like bgl1_1 below) unused by the pipeline layout, it is invalid.
|
||||||
|
// Bind groups associated layout should exactly match bind group layout if that layout is
|
||||||
|
// set in pipeline layout.
|
||||||
|
bgl[1] = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::ReadonlyStorageBuffer},
|
||||||
|
{1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::UniformBuffer}});
|
||||||
|
buffer[1] = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage | wgpu::BufferUsage::Uniform);
|
||||||
|
bg[1] = utils::MakeBindGroup(device, bgl[1], {{0, buffer[1]}, {1, buffer[1]}});
|
||||||
|
|
||||||
|
TestRenderPassBindings(bg.data(), kBindingNum, renderPipeline, false);
|
||||||
|
|
||||||
|
TestComputePassBindings(bg.data(), kBindingNum, computePipeline, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that it is invalid to set bind groups that don't have all necessary bindings required
|
||||||
|
// by the pipeline layout. Note that both pipeline layout and bind group have enough bindings for
|
||||||
|
// pipeline in the following test.
|
||||||
|
TEST_F(BindingsValidationTest, BindGroupsWithLessBindingsThanPipelineLayout) {
|
||||||
|
// Set up bind group layouts, buffers, bind groups, pipeline layouts and pipelines.
|
||||||
|
std::array<wgpu::BindGroupLayout, kBindingNum> bgl;
|
||||||
|
std::array<wgpu::BindGroup, kBindingNum> bg;
|
||||||
|
std::array<wgpu::Buffer, kBindingNum> buffer;
|
||||||
|
for (uint32_t i = 0; i < kBindingNum; ++i) {
|
||||||
|
bgl[i] = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::StorageBuffer}});
|
||||||
|
buffer[i] = CreateBuffer(kBufferSize, wgpu::BufferUsage::Storage);
|
||||||
|
bg[i] = utils::MakeBindGroup(device, bgl[i], {{0, buffer[i]}});
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::RenderPipeline renderPipeline = CreateRenderPipeline({bgl[0], bgl[1], bgl[2]});
|
||||||
|
wgpu::ComputePipeline computePipeline = CreateComputePipeline({bgl[0], bgl[1], bgl[2]});
|
||||||
|
|
||||||
|
// Compared to pipeline layout, a binding set (bgl2) related bind group is missing
|
||||||
|
TestRenderPassBindings(bg.data(), kBindingNum - 1, renderPipeline, false);
|
||||||
|
|
||||||
|
TestComputePassBindings(bg.data(), kBindingNum - 1, computePipeline, false);
|
||||||
|
|
||||||
|
// bgl[2] related bind group is not missing, but its bind group is empty
|
||||||
|
bgl[2] = utils::MakeBindGroupLayout(device, {});
|
||||||
|
bg[2] = utils::MakeBindGroup(device, bgl[2], {});
|
||||||
|
|
||||||
|
TestRenderPassBindings(bg.data(), kBindingNum, renderPipeline, false);
|
||||||
|
|
||||||
|
TestComputePassBindings(bg.data(), kBindingNum, computePipeline, false);
|
||||||
|
|
||||||
|
// bgl[2] related bind group is neither missing nor empty, but it doesn't contain the necessary
|
||||||
|
// binding
|
||||||
|
bgl[2] = utils::MakeBindGroupLayout(
|
||||||
|
device, {{1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||||
|
wgpu::BindingType::UniformBuffer}});
|
||||||
|
buffer[2] = CreateBuffer(kBufferSize, wgpu::BufferUsage::Uniform);
|
||||||
|
bg[2] = utils::MakeBindGroup(device, bgl[2], {{1, buffer[2]}});
|
||||||
|
|
||||||
|
TestRenderPassBindings(bg.data(), kBindingNum, renderPipeline, false);
|
||||||
|
|
||||||
|
TestComputePassBindings(bg.data(), kBindingNum, computePipeline, false);
|
||||||
}
|
}
|
||||||
|
@ -1,117 +0,0 @@
|
|||||||
// Copyright 2019 The Dawn Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
#include "tests/unittests/validation/ValidationTest.h"
|
|
||||||
|
|
||||||
#include "common/Constants.h"
|
|
||||||
|
|
||||||
#include "utils/ComboRenderPipelineDescriptor.h"
|
|
||||||
#include "utils/WGPUHelpers.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class RenderPassValidationTest : public ValidationTest {};
|
|
||||||
|
|
||||||
// Test that it is invalid to draw in a render pass with missing bind groups
|
|
||||||
TEST_F(RenderPassValidationTest, MissingBindGroup) {
|
|
||||||
wgpu::ShaderModule vsModule =
|
|
||||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
|
||||||
#version 450
|
|
||||||
layout (set = 0, binding = 0) uniform vertexUniformBuffer {
|
|
||||||
mat2 transform;
|
|
||||||
};
|
|
||||||
void main() {
|
|
||||||
const vec2 pos[3] = vec2[3](vec2(-1.f, -1.f), vec2(1.f, -1.f), vec2(-1.f, 1.f));
|
|
||||||
gl_Position = vec4(transform * pos[gl_VertexIndex], 0.f, 1.f);
|
|
||||||
})");
|
|
||||||
|
|
||||||
wgpu::ShaderModule fsModule =
|
|
||||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
|
|
||||||
#version 450
|
|
||||||
layout (set = 1, binding = 0) uniform fragmentUniformBuffer {
|
|
||||||
vec4 color;
|
|
||||||
};
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
void main() {
|
|
||||||
fragColor = color;
|
|
||||||
})");
|
|
||||||
|
|
||||||
wgpu::BindGroupLayout bgls[] = {
|
|
||||||
utils::MakeBindGroupLayout(
|
|
||||||
device, {{0, wgpu::ShaderStage::Vertex, wgpu::BindingType::UniformBuffer}}),
|
|
||||||
utils::MakeBindGroupLayout(
|
|
||||||
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::UniformBuffer}})};
|
|
||||||
|
|
||||||
wgpu::PipelineLayoutDescriptor pipelineLayoutDesc;
|
|
||||||
pipelineLayoutDesc.bindGroupLayoutCount = 2;
|
|
||||||
pipelineLayoutDesc.bindGroupLayouts = bgls;
|
|
||||||
|
|
||||||
wgpu::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&pipelineLayoutDesc);
|
|
||||||
|
|
||||||
utils::ComboRenderPipelineDescriptor descriptor(device);
|
|
||||||
descriptor.layout = pipelineLayout;
|
|
||||||
descriptor.vertexStage.module = vsModule;
|
|
||||||
descriptor.cFragmentStage.module = fsModule;
|
|
||||||
|
|
||||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
|
|
||||||
|
|
||||||
float data[4];
|
|
||||||
wgpu::Buffer buffer =
|
|
||||||
utils::CreateBufferFromData(device, data, 4 * sizeof(float), wgpu::BufferUsage::Uniform);
|
|
||||||
|
|
||||||
wgpu::BindGroup bg1 =
|
|
||||||
utils::MakeBindGroup(device, bgls[0], {{0, buffer, 0, 4 * sizeof(float)}});
|
|
||||||
wgpu::BindGroup bg2 =
|
|
||||||
utils::MakeBindGroup(device, bgls[1], {{0, buffer, 0, 4 * sizeof(float)}});
|
|
||||||
|
|
||||||
DummyRenderPass renderPass(device);
|
|
||||||
{
|
|
||||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
|
||||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
|
|
||||||
pass.SetPipeline(pipeline);
|
|
||||||
pass.SetBindGroup(0, bg1);
|
|
||||||
pass.SetBindGroup(1, bg2);
|
|
||||||
pass.Draw(3);
|
|
||||||
pass.EndPass();
|
|
||||||
commandEncoder.Finish();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
|
||||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
|
|
||||||
pass.SetPipeline(pipeline);
|
|
||||||
pass.Draw(3);
|
|
||||||
pass.EndPass();
|
|
||||||
ASSERT_DEVICE_ERROR(commandEncoder.Finish());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
|
||||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
|
|
||||||
pass.SetPipeline(pipeline);
|
|
||||||
pass.SetBindGroup(1, bg2);
|
|
||||||
pass.Draw(3);
|
|
||||||
pass.EndPass();
|
|
||||||
ASSERT_DEVICE_ERROR(commandEncoder.Finish());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
|
||||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPass);
|
|
||||||
pass.SetPipeline(pipeline);
|
|
||||||
pass.SetBindGroup(0, bg1);
|
|
||||||
pass.Draw(3);
|
|
||||||
pass.EndPass();
|
|
||||||
ASSERT_DEVICE_ERROR(commandEncoder.Finish());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
Loading…
x
Reference in New Issue
Block a user