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/RenderBundleValidationTests.cpp",
|
||||
"unittests/validation/RenderPassDescriptorValidationTests.cpp",
|
||||
"unittests/validation/RenderPassValidationTests.cpp",
|
||||
"unittests/validation/RenderPipelineValidationTests.cpp",
|
||||
"unittests/validation/ResourceUsageTrackingTests.cpp",
|
||||
"unittests/validation/SamplerValidationTests.cpp",
|
||||
|
|
|
@ -21,6 +21,21 @@
|
|||
|
||||
class BindGroupValidationTest : public ValidationTest {
|
||||
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 {
|
||||
// Create objects to use as resources inside test bind groups.
|
||||
{
|
||||
|
@ -40,15 +55,8 @@ class BindGroupValidationTest : public ValidationTest {
|
|||
mSampler = device.CreateSampler(&descriptor);
|
||||
}
|
||||
{
|
||||
wgpu::TextureDescriptor descriptor;
|
||||
descriptor.dimension = wgpu::TextureDimension::e2D;
|
||||
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);
|
||||
mSampledTexture =
|
||||
CreateTexture(wgpu::TextureUsage::Sampled, wgpu::TextureFormat::RGBA8Unorm, 1);
|
||||
mSampledTextureView = mSampledTexture.CreateView();
|
||||
}
|
||||
}
|
||||
|
@ -288,15 +296,8 @@ TEST_F(BindGroupValidationTest, TextureUsage) {
|
|||
utils::MakeBindGroup(device, layout, {{0, mSampledTextureView}});
|
||||
|
||||
// Make an output attachment texture and try to set it for a SampledTexture binding
|
||||
wgpu::TextureDescriptor descriptor;
|
||||
descriptor.dimension = wgpu::TextureDimension::e2D;
|
||||
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::Texture outputTexture =
|
||||
CreateTexture(wgpu::TextureUsage::OutputAttachment, wgpu::TextureFormat::RGBA8Unorm, 1);
|
||||
wgpu::TextureView outputTextureView = outputTexture.CreateView();
|
||||
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, outputTextureView}}));
|
||||
}
|
||||
|
@ -311,15 +312,8 @@ TEST_F(BindGroupValidationTest, TextureComponentType) {
|
|||
utils::MakeBindGroup(device, layout, {{0, mSampledTextureView}});
|
||||
|
||||
// Make a Uint component typed texture and try to set it to a Float component binding.
|
||||
wgpu::TextureDescriptor descriptor;
|
||||
descriptor.dimension = wgpu::TextureDimension::e2D;
|
||||
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::Texture uintTexture =
|
||||
CreateTexture(wgpu::TextureUsage::Sampled, wgpu::TextureFormat::RGBA8Uint, 1);
|
||||
wgpu::TextureView uintTextureView = uintTexture.CreateView();
|
||||
|
||||
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, uintTextureView}}));
|
||||
|
@ -335,15 +329,8 @@ TEST_F(BindGroupValidationTest, TextureDimension) {
|
|||
utils::MakeBindGroup(device, layout, {{0, mSampledTextureView}});
|
||||
|
||||
// Make a 2DArray texture and try to set it to a 2D binding.
|
||||
wgpu::TextureDescriptor descriptor;
|
||||
descriptor.dimension = wgpu::TextureDimension::e2D;
|
||||
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::Texture arrayTexture =
|
||||
CreateTexture(wgpu::TextureUsage::Sampled, wgpu::TextureFormat::RGBA8Uint, 2);
|
||||
wgpu::TextureView arrayTextureView = arrayTexture.CreateView();
|
||||
|
||||
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, arrayTextureView}}));
|
||||
|
@ -1226,7 +1213,7 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
|
|||
return device.CreateBuffer(&bufferDescriptor);
|
||||
}
|
||||
|
||||
wgpu::RenderPipeline CreateRenderPipeline(wgpu::BindGroupLayout* bindGroupLayout) {
|
||||
wgpu::RenderPipeline CreateRenderPipeline(std::vector<wgpu::BindGroupLayout> bindGroupLayout) {
|
||||
wgpu::ShaderModule vsModule =
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
|
@ -1239,23 +1226,26 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
|
|||
layout(std140, set = 0, binding = 0) buffer SBuffer {
|
||||
vec2 value2;
|
||||
} sBuffer;
|
||||
layout(std140, set = 0, binding = 1) readonly buffer RBuffer {
|
||||
layout(std140, set = 1, binding = 0) readonly buffer RBuffer {
|
||||
vec2 value3;
|
||||
} rBuffer;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
})");
|
||||
|
||||
wgpu::PipelineLayoutDescriptor descriptor;
|
||||
descriptor.bindGroupLayoutCount = bindGroupLayout.size();
|
||||
descriptor.bindGroupLayouts = bindGroupLayout.data();
|
||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
|
||||
pipelineDescriptor.vertexStage.module = vsModule;
|
||||
pipelineDescriptor.cFragmentStage.module = fsModule;
|
||||
wgpu::PipelineLayout pipelineLayout =
|
||||
utils::MakeBasicPipelineLayout(device, bindGroupLayout);
|
||||
wgpu::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&descriptor);
|
||||
pipelineDescriptor.layout = pipelineLayout;
|
||||
return device.CreateRenderPipeline(&pipelineDescriptor);
|
||||
}
|
||||
|
||||
wgpu::ComputePipeline CreateComputePipeline(wgpu::BindGroupLayout* bindGroupLayout) {
|
||||
wgpu::ComputePipeline CreateComputePipeline(
|
||||
std::vector<wgpu::BindGroupLayout> bindGroupLayout) {
|
||||
wgpu::ShaderModule csModule =
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
|
||||
#version 450
|
||||
|
@ -1266,14 +1256,16 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
|
|||
layout(std140, set = 0, binding = 0) buffer SBuffer {
|
||||
float value2;
|
||||
} dst;
|
||||
layout(std140, set = 0, binding = 1) readonly buffer RBuffer {
|
||||
layout(std140, set = 1, binding = 0) readonly buffer RBuffer {
|
||||
readonly float value3;
|
||||
} rdst;
|
||||
void main() {
|
||||
})");
|
||||
|
||||
wgpu::PipelineLayout pipelineLayout =
|
||||
utils::MakeBasicPipelineLayout(device, bindGroupLayout);
|
||||
wgpu::PipelineLayoutDescriptor descriptor;
|
||||
descriptor.bindGroupLayoutCount = bindGroupLayout.size();
|
||||
descriptor.bindGroupLayouts = bindGroupLayout.data();
|
||||
wgpu::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&descriptor);
|
||||
|
||||
wgpu::ComputePipelineDescriptor csDesc;
|
||||
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
|
||||
// is a writable storage buffer, but the second item in shader is a readonly storage buffer. It is
|
||||
// valid.
|
||||
// Test that it is valid to pass a writable storage buffer in the pipeline layout when the shader
|
||||
// uses the binding as a readonly storage buffer.
|
||||
TEST_F(BindGroupLayoutCompatibilityTest, RWStorageInBGLWithROStorageInShader) {
|
||||
// Set up the bind group layout.
|
||||
wgpu::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
|
||||
wgpu::BindGroupLayout bgl0 = utils::MakeBindGroupLayout(
|
||||
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||
wgpu::BindingType::StorageBuffer, true},
|
||||
{1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||
wgpu::BindingType::StorageBuffer, true}});
|
||||
wgpu::BindingType::StorageBuffer}});
|
||||
wgpu::BindGroupLayout bgl1 = utils::MakeBindGroupLayout(
|
||||
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
|
||||
// is a readonly storage buffer, but the first item in shader is a writable storage buffer. It is
|
||||
// invalid.
|
||||
// Test that it is invalid to pass a readonly storage buffer in the pipeline layout when the shader
|
||||
// uses the binding as a writable storage buffer.
|
||||
TEST_F(BindGroupLayoutCompatibilityTest, ROStorageInBGLWithRWStorageInShader) {
|
||||
// Set up the bind group layout.
|
||||
wgpu::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
|
||||
wgpu::BindGroupLayout bgl0 = utils::MakeBindGroupLayout(
|
||||
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||
wgpu::BindingType::ReadonlyStorageBuffer, true},
|
||||
{1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||
wgpu::BindingType::ReadonlyStorageBuffer, true}});
|
||||
wgpu::BindingType::ReadonlyStorageBuffer}});
|
||||
wgpu::BindGroupLayout bgl1 = utils::MakeBindGroupLayout(
|
||||
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…
Reference in New Issue