From 73b7cd624f220e84152778368684b081478c711c Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Tue, 29 Jun 2021 08:12:00 +0000 Subject: [PATCH] Add missing WebGPU limits to Constants.h This will help check that the Vulkan devices are enough for WebGPU in a following CL. In addition to additional limits this CL: - Change maxColorAttachments 4 -> 8 to match WebGPU - Renames kMinDynamicBufferOffsetAlignment to kMinUniformBufferOffsetAlignment. - Renames kMaxVertexBufferStride to kMaxVertexBufferArrayStride. - Changes validation of buffer offsets to use the separate uniform and storage limits (but no test is added because they are the same). - Adds validation and a test for kMaxStorageBufferBindingSize. - Augment the null::Device memory limit for that new test (it allocates a buffer of 512MB). - Fix the maxColorAttachment test to not use hardcoded values. Bug: dawn:796 Change-Id: Ibe4219130a44355ae91c02aaa0a41cf5d9f9e234 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/56081 Commit-Queue: Corentin Wallez Reviewed-by: Kai Ninomiya --- examples/Animometer.cpp | 2 +- src/common/Constants.h | 17 +++--- src/dawn_native/BindGroup.cpp | 12 +++-- src/dawn_native/ProgrammablePassEncoder.cpp | 17 +++++- src/dawn_native/RenderPipeline.cpp | 12 ++--- src/dawn_native/null/DeviceNull.h | 2 +- src/tests/end2end/BindGroupTests.cpp | 18 +++---- .../end2end/DynamicBufferOffsetTests.cpp | 34 ++++++------ src/tests/perf_tests/DrawCallPerf.cpp | 2 +- .../validation/BindGroupValidationTests.cpp | 50 +++++++++++++---- .../RenderPassDescriptorValidationTests.cpp | 53 +++++++------------ .../validation/VertexStateValidationTests.cpp | 8 +-- 12 files changed, 133 insertions(+), 94 deletions(-) diff --git a/examples/Animometer.cpp b/examples/Animometer.cpp index 1f3fa0300c..2b1873a5dd 100644 --- a/examples/Animometer.cpp +++ b/examples/Animometer.cpp @@ -37,7 +37,7 @@ float RandomFloat(float min, float max) { constexpr size_t kNumTriangles = 10000; -struct alignas(kMinDynamicBufferOffsetAlignment) ShaderData { +struct alignas(kMinUniformBufferOffsetAlignment) ShaderData { float scale; float time; float offsetX; diff --git a/src/common/Constants.h b/src/common/Constants.h index 3afb7681be..be8668e7bb 100644 --- a/src/common/Constants.h +++ b/src/common/Constants.h @@ -20,26 +20,31 @@ static constexpr uint32_t kMaxBindGroups = 4u; static constexpr uint8_t kMaxVertexAttributes = 16u; static constexpr uint8_t kMaxVertexBuffers = 8u; -static constexpr uint32_t kMaxVertexBufferStride = 2048u; +static constexpr uint32_t kMaxVertexBufferArrayStride = 2048u; static constexpr uint32_t kNumStages = 3; -static constexpr uint8_t kMaxColorAttachments = 4u; +static constexpr uint8_t kMaxColorAttachments = 8u; static constexpr uint32_t kTextureBytesPerRowAlignment = 256u; -// Dynamic buffer offsets require offset to be divisible by 256 -static constexpr uint64_t kMinDynamicBufferOffsetAlignment = 256u; +static constexpr uint32_t kMaxInterStageShaderComponents = 60u; +static constexpr uint32_t kMaxComputeWorkgroupStorageSize = 16352u; +static constexpr uint32_t kMaxComputeWorkgroupInvocations = 256u; +static constexpr uint32_t kMaxComputePerDimensionDispatchSize = 65535u; // Per stage limits static constexpr uint32_t kMaxSampledTexturesPerShaderStage = 16; static constexpr uint32_t kMaxSamplersPerShaderStage = 16; static constexpr uint32_t kMaxStorageBuffersPerShaderStage = 8; -static constexpr uint32_t kMaxStorageTexturesPerShaderStage = 8; +static constexpr uint32_t kMaxStorageTexturesPerShaderStage = 4; static constexpr uint32_t kMaxUniformBuffersPerShaderStage = 12; // Per pipeline layout limits static constexpr uint32_t kMaxDynamicUniformBuffersPerPipelineLayout = 8u; static constexpr uint32_t kMaxDynamicStorageBuffersPerPipelineLayout = 4u; -// Max size of uniform buffer binding +// Buffer binding constraints static constexpr uint64_t kMaxUniformBufferBindingSize = 16384u; +static constexpr uint64_t kMaxStorageBufferBindingSize = 134217728u; +static constexpr uint64_t kMinUniformBufferOffsetAlignment = 256u; +static constexpr uint64_t kMinStorageBufferOffsetAlignment = 256u; // Indirect command sizes static constexpr uint64_t kDispatchIndirectSize = 3 * sizeof(uint32_t); diff --git a/src/dawn_native/BindGroup.cpp b/src/dawn_native/BindGroup.cpp index d590117cb8..b4bbfd7038 100644 --- a/src/dawn_native/BindGroup.cpp +++ b/src/dawn_native/BindGroup.cpp @@ -44,19 +44,23 @@ namespace dawn_native { wgpu::BufferUsage requiredUsage; uint64_t maxBindingSize; + uint64_t requiredBindingAlignment; switch (bindingInfo.buffer.type) { case wgpu::BufferBindingType::Uniform: requiredUsage = wgpu::BufferUsage::Uniform; maxBindingSize = kMaxUniformBufferBindingSize; + requiredBindingAlignment = kMinUniformBufferOffsetAlignment; break; case wgpu::BufferBindingType::Storage: case wgpu::BufferBindingType::ReadOnlyStorage: requiredUsage = wgpu::BufferUsage::Storage; - maxBindingSize = std::numeric_limits::max(); + maxBindingSize = kMaxStorageBufferBindingSize; + requiredBindingAlignment = kMinStorageBufferOffsetAlignment; break; case kInternalStorageBufferBinding: requiredUsage = kInternalStorageBuffer; - maxBindingSize = std::numeric_limits::max(); + maxBindingSize = kMaxStorageBufferBindingSize; + requiredBindingAlignment = kMinStorageBufferOffsetAlignment; break; case wgpu::BufferBindingType::Undefined: UNREACHABLE(); @@ -85,9 +89,9 @@ namespace dawn_native { return DAWN_VALIDATION_ERROR("Buffer binding doesn't fit in the buffer"); } - if (!IsAligned(entry.offset, 256)) { + if (!IsAligned(entry.offset, requiredBindingAlignment)) { return DAWN_VALIDATION_ERROR( - "Buffer offset for bind group needs to be 256-byte aligned"); + "Buffer offset for bind group needs to satisfy the minimum alignment"); } if (!(entry.buffer->GetUsage() & requiredUsage)) { diff --git a/src/dawn_native/ProgrammablePassEncoder.cpp b/src/dawn_native/ProgrammablePassEncoder.cpp index c4be109a5c..47d095368e 100644 --- a/src/dawn_native/ProgrammablePassEncoder.cpp +++ b/src/dawn_native/ProgrammablePassEncoder.cpp @@ -123,7 +123,22 @@ namespace dawn_native { ASSERT(bindingInfo.bindingType == BindingInfoType::Buffer); ASSERT(bindingInfo.buffer.hasDynamicOffset); - if (dynamicOffsets[i] % kMinDynamicBufferOffsetAlignment != 0) { + uint64_t requiredAlignment; + switch (bindingInfo.buffer.type) { + case wgpu::BufferBindingType::Uniform: + requiredAlignment = kMinUniformBufferOffsetAlignment; + break; + case wgpu::BufferBindingType::Storage: + case wgpu::BufferBindingType::ReadOnlyStorage: + case kInternalStorageBufferBinding: + requiredAlignment = kMinStorageBufferOffsetAlignment; + requiredAlignment = kMinStorageBufferOffsetAlignment; + break; + case wgpu::BufferBindingType::Undefined: + UNREACHABLE(); + } + + if (!IsAligned(dynamicOffsets[i], requiredAlignment)) { return DAWN_VALIDATION_ERROR("Dynamic Buffer Offset need to be aligned"); } diff --git a/src/dawn_native/RenderPipeline.cpp b/src/dawn_native/RenderPipeline.cpp index 1a8f37cdf1..456acce676 100644 --- a/src/dawn_native/RenderPipeline.cpp +++ b/src/dawn_native/RenderPipeline.cpp @@ -39,16 +39,16 @@ namespace dawn_native { } // No underflow is possible because the max vertex format size is smaller than - // kMaxVertexBufferStride. - ASSERT(kMaxVertexBufferStride >= dawn::VertexFormatSize(attribute->format)); + // kMaxVertexBufferArrayStride. + ASSERT(kMaxVertexBufferArrayStride >= dawn::VertexFormatSize(attribute->format)); if (attribute->offset > - kMaxVertexBufferStride - dawn::VertexFormatSize(attribute->format)) { + kMaxVertexBufferArrayStride - dawn::VertexFormatSize(attribute->format)) { return DAWN_VALIDATION_ERROR("Setting attribute offset out of bounds"); } // No overflow is possible because the offset is already validated to be less - // than kMaxVertexBufferStride. - ASSERT(attribute->offset < kMaxVertexBufferStride); + // than kMaxVertexBufferArrayStride. + ASSERT(attribute->offset < kMaxVertexBufferArrayStride); if (vertexBufferStride > 0 && attribute->offset + dawn::VertexFormatSize(attribute->format) > vertexBufferStride) { @@ -73,7 +73,7 @@ namespace dawn_native { const VertexBufferLayout* buffer, std::bitset* attributesSetMask) { DAWN_TRY(ValidateInputStepMode(buffer->stepMode)); - if (buffer->arrayStride > kMaxVertexBufferStride) { + if (buffer->arrayStride > kMaxVertexBufferArrayStride) { return DAWN_VALIDATION_ERROR("Setting arrayStride out of bounds"); } diff --git a/src/dawn_native/null/DeviceNull.h b/src/dawn_native/null/DeviceNull.h index 17e7756568..afa141f9be 100644 --- a/src/dawn_native/null/DeviceNull.h +++ b/src/dawn_native/null/DeviceNull.h @@ -160,7 +160,7 @@ namespace dawn_native { namespace null { std::vector> mPendingOperations; - static constexpr uint64_t kMaxMemoryUsage = 256 * 1024 * 1024; + static constexpr uint64_t kMaxMemoryUsage = 512 * 1024 * 1024; size_t mMemoryUsage = 0; }; diff --git a/src/tests/end2end/BindGroupTests.cpp b/src/tests/end2end/BindGroupTests.cpp index 279c764108..763977cdc6 100644 --- a/src/tests/end2end/BindGroupTests.cpp +++ b/src/tests/end2end/BindGroupTests.cpp @@ -542,7 +542,7 @@ TEST_P(BindGroupTests, SetDynamicBindGroupBeforePipeline) { std::array color0 = {1, 0, 0, 0.501}; std::array color1 = {0, 1, 0, 0.501}; - size_t color1Offset = Align(sizeof(color0), kMinDynamicBufferOffsetAlignment); + size_t color1Offset = Align(sizeof(color0), kMinUniformBufferOffsetAlignment); std::vector data(color1Offset + sizeof(color1)); memcpy(data.data(), color0.data(), sizeof(color0)); @@ -612,7 +612,7 @@ TEST_P(BindGroupTests, BindGroupsPersistAfterPipelineChange) { std::array color0 = {1, 0, 0, 0.5}; std::array color1 = {0, 1, 0, 0.5}; - size_t color1Offset = Align(sizeof(color0), kMinDynamicBufferOffsetAlignment); + size_t color1Offset = Align(sizeof(color0), kMinUniformBufferOffsetAlignment); std::vector data(color1Offset + sizeof(color1)); memcpy(data.data(), color0.data(), sizeof(color0)); @@ -699,9 +699,9 @@ TEST_P(BindGroupTests, DrawThenChangePipelineAndBindGroup) { std::array color2 = {0, 0, 0, 0.501}; std::array color3 = {0, 0, 1, 0}; - size_t color1Offset = Align(sizeof(color0), kMinDynamicBufferOffsetAlignment); - size_t color2Offset = Align(color1Offset + sizeof(color1), kMinDynamicBufferOffsetAlignment); - size_t color3Offset = Align(color2Offset + sizeof(color2), kMinDynamicBufferOffsetAlignment); + size_t color1Offset = Align(sizeof(color0), kMinUniformBufferOffsetAlignment); + size_t color2Offset = Align(color1Offset + sizeof(color1), kMinUniformBufferOffsetAlignment); + size_t color3Offset = Align(color2Offset + sizeof(color2), kMinUniformBufferOffsetAlignment); std::vector data(color3Offset + sizeof(color3), 0); memcpy(data.data(), color0.data(), sizeof(color0)); @@ -773,14 +773,14 @@ TEST_P(BindGroupTests, DynamicOffsetOrder) { // We will put the following values and the respective offsets into a buffer. // The test will ensure that the correct dynamic offset is applied to each buffer by reading the // value from an offset binding. - std::array offsets = {3 * kMinDynamicBufferOffsetAlignment, - 1 * kMinDynamicBufferOffsetAlignment, - 2 * kMinDynamicBufferOffsetAlignment}; + std::array offsets = {3 * kMinUniformBufferOffsetAlignment, + 1 * kMinUniformBufferOffsetAlignment, + 2 * kMinUniformBufferOffsetAlignment}; std::array values = {21, 67, 32}; // Create three buffers large enough to by offset by the largest offset. wgpu::BufferDescriptor bufferDescriptor; - bufferDescriptor.size = 3 * kMinDynamicBufferOffsetAlignment + sizeof(uint32_t); + bufferDescriptor.size = 3 * kMinUniformBufferOffsetAlignment + sizeof(uint32_t); bufferDescriptor.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst; wgpu::Buffer buffer0 = device.CreateBuffer(&bufferDescriptor); diff --git a/src/tests/end2end/DynamicBufferOffsetTests.cpp b/src/tests/end2end/DynamicBufferOffsetTests.cpp index f735a55b42..5f91cabd59 100644 --- a/src/tests/end2end/DynamicBufferOffsetTests.cpp +++ b/src/tests/end2end/DynamicBufferOffsetTests.cpp @@ -18,7 +18,7 @@ #include "utils/WGPUHelpers.h" constexpr uint32_t kRTSize = 400; -constexpr uint32_t kBufferElementsCount = kMinDynamicBufferOffsetAlignment / sizeof(uint32_t) + 2; +constexpr uint32_t kBufferElementsCount = kMinUniformBufferOffsetAlignment / sizeof(uint32_t) + 2; constexpr uint32_t kBufferSize = kBufferElementsCount * sizeof(uint32_t); constexpr uint32_t kBindingSize = 8; @@ -261,8 +261,8 @@ TEST_P(DynamicBufferOffsetTests, SetDynamicOffestsRenderPipeline) { utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize); wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); - std::array offsets = {kMinDynamicBufferOffsetAlignment, - kMinDynamicBufferOffsetAlignment}; + std::array offsets = {kMinUniformBufferOffsetAlignment, + kMinUniformBufferOffsetAlignment}; wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPass.renderPassInfo); renderPassEncoder.SetPipeline(pipeline); @@ -275,7 +275,7 @@ TEST_P(DynamicBufferOffsetTests, SetDynamicOffestsRenderPipeline) { std::vector expectedData = {6, 8}; EXPECT_PIXEL_RGBA8_EQ(RGBA8(5, 6, 255, 255), renderPass.color, 0, 0); EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), mStorageBuffers[1], - kMinDynamicBufferOffsetAlignment, expectedData.size()); + kMinUniformBufferOffsetAlignment, expectedData.size()); } // Dynamic offsets are all zero and no effect to result. @@ -301,8 +301,8 @@ TEST_P(DynamicBufferOffsetTests, BasicComputePipeline) { TEST_P(DynamicBufferOffsetTests, SetDynamicOffestsComputePipeline) { wgpu::ComputePipeline pipeline = CreateComputePipeline(); - std::array offsets = {kMinDynamicBufferOffsetAlignment, - kMinDynamicBufferOffsetAlignment}; + std::array offsets = {kMinUniformBufferOffsetAlignment, + kMinUniformBufferOffsetAlignment}; wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); wgpu::ComputePassEncoder computePassEncoder = commandEncoder.BeginComputePass(); @@ -315,7 +315,7 @@ TEST_P(DynamicBufferOffsetTests, SetDynamicOffestsComputePipeline) { std::vector expectedData = {6, 8}; EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), mStorageBuffers[1], - kMinDynamicBufferOffsetAlignment, expectedData.size()); + kMinUniformBufferOffsetAlignment, expectedData.size()); } // Test inherit dynamic offsets on render pipeline @@ -327,8 +327,8 @@ TEST_P(DynamicBufferOffsetTests, InheritDynamicOffestsRenderPipeline) { utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize); wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); - std::array offsets = {kMinDynamicBufferOffsetAlignment, - kMinDynamicBufferOffsetAlignment}; + std::array offsets = {kMinUniformBufferOffsetAlignment, + kMinUniformBufferOffsetAlignment}; wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPass.renderPassInfo); renderPassEncoder.SetPipeline(pipeline); @@ -344,7 +344,7 @@ TEST_P(DynamicBufferOffsetTests, InheritDynamicOffestsRenderPipeline) { std::vector expectedData = {12, 16}; EXPECT_PIXEL_RGBA8_EQ(RGBA8(5, 6, 255, 255), renderPass.color, 0, 0); EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), mStorageBuffers[1], - kMinDynamicBufferOffsetAlignment, expectedData.size()); + kMinUniformBufferOffsetAlignment, expectedData.size()); } // Test inherit dynamic offsets on compute pipeline @@ -356,8 +356,8 @@ TEST_P(DynamicBufferOffsetTests, InheritDynamicOffestsComputePipeline) { wgpu::ComputePipeline pipeline = CreateComputePipeline(); wgpu::ComputePipeline testPipeline = CreateComputePipeline(true); - std::array offsets = {kMinDynamicBufferOffsetAlignment, - kMinDynamicBufferOffsetAlignment}; + std::array offsets = {kMinUniformBufferOffsetAlignment, + kMinUniformBufferOffsetAlignment}; wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); wgpu::ComputePassEncoder computePassEncoder = commandEncoder.BeginComputePass(); @@ -373,7 +373,7 @@ TEST_P(DynamicBufferOffsetTests, InheritDynamicOffestsComputePipeline) { std::vector expectedData = {12, 16}; EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), mStorageBuffers[1], - kMinDynamicBufferOffsetAlignment, expectedData.size()); + kMinUniformBufferOffsetAlignment, expectedData.size()); } // Setting multiple dynamic offsets for the same bindgroup in one render pass. @@ -384,8 +384,8 @@ TEST_P(DynamicBufferOffsetTests, UpdateDynamicOffestsMultipleTimesRenderPipeline utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize); wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); - std::array offsets = {kMinDynamicBufferOffsetAlignment, - kMinDynamicBufferOffsetAlignment}; + std::array offsets = {kMinUniformBufferOffsetAlignment, + kMinUniformBufferOffsetAlignment}; std::array testOffsets = {0, 0}; wgpu::RenderPassEncoder renderPassEncoder = @@ -408,8 +408,8 @@ TEST_P(DynamicBufferOffsetTests, UpdateDynamicOffestsMultipleTimesRenderPipeline TEST_P(DynamicBufferOffsetTests, UpdateDynamicOffsetsMultipleTimesComputePipeline) { wgpu::ComputePipeline pipeline = CreateComputePipeline(); - std::array offsets = {kMinDynamicBufferOffsetAlignment, - kMinDynamicBufferOffsetAlignment}; + std::array offsets = {kMinUniformBufferOffsetAlignment, + kMinUniformBufferOffsetAlignment}; std::array testOffsets = {0, 0}; wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); diff --git a/src/tests/perf_tests/DrawCallPerf.cpp b/src/tests/perf_tests/DrawCallPerf.cpp index 74e5f371ec..97991a064b 100644 --- a/src/tests/perf_tests/DrawCallPerf.cpp +++ b/src/tests/perf_tests/DrawCallPerf.cpp @@ -270,7 +270,7 @@ void DrawCallPerf::SetUp() { DawnPerfTestWithParams::SetUp(); // Compute aligned uniform / vertex data sizes. - mAlignedUniformSize = Align(kUniformSize, kMinDynamicBufferOffsetAlignment); + mAlignedUniformSize = Align(kUniformSize, kMinUniformBufferOffsetAlignment); mAlignedVertexDataSize = Align(sizeof(kVertexData), 4); // Initialize uniform buffer data. diff --git a/src/tests/unittests/validation/BindGroupValidationTests.cpp b/src/tests/unittests/validation/BindGroupValidationTests.cpp index 430ca11a0d..04f62dccdc 100644 --- a/src/tests/unittests/validation/BindGroupValidationTests.cpp +++ b/src/tests/unittests/validation/BindGroupValidationTests.cpp @@ -731,6 +731,36 @@ TEST_F(BindGroupValidationTest, MaxUniformBufferBindingSize) { utils::MakeBindGroup(device, storageLayout, {{0, buffer, 0, 2 * kMaxUniformBufferBindingSize}}); } +// Tests constraints to be sure the storage buffer binding isn't too large +TEST_F(BindGroupValidationTest, MaxStorageBufferBindingSize) { + wgpu::BufferDescriptor descriptor; + descriptor.size = 2 * kMaxStorageBufferBindingSize; + descriptor.usage = wgpu::BufferUsage::Storage; + wgpu::Buffer buffer = device.CreateBuffer(&descriptor); + + wgpu::BindGroupLayout uniformLayout = utils::MakeBindGroupLayout( + device, {{0, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Storage}}); + + // Success case, this is exactly the limit + utils::MakeBindGroup(device, uniformLayout, {{0, buffer, 0, kMaxStorageBufferBindingSize}}); + + // Success case, this is one less than the limit (check it is not an alignment constraint) + utils::MakeBindGroup(device, uniformLayout, {{0, buffer, 0, kMaxStorageBufferBindingSize - 1}}); + + wgpu::BindGroupLayout doubleUniformLayout = utils::MakeBindGroupLayout( + device, {{0, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Storage}, + {1, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Storage}}); + + // Success case, individual bindings don't exceed the limit + utils::MakeBindGroup(device, doubleUniformLayout, + {{0, buffer, 0, kMaxStorageBufferBindingSize}, + {1, buffer, kMaxStorageBufferBindingSize, kMaxStorageBufferBindingSize}}); + + // Error case, this is above the limit + ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, uniformLayout, + {{0, buffer, 0, kMaxStorageBufferBindingSize + 1}})); +} + // Test what happens when the layout is an error. TEST_F(BindGroupValidationTest, ErrorLayout) { wgpu::BindGroupLayout goodLayout = utils::MakeBindGroupLayout( @@ -1267,7 +1297,7 @@ TEST_F(BindGroupLayoutValidationTest, MultisampledTextureComponentType) { })); } -constexpr uint64_t kBufferSize = 3 * kMinDynamicBufferOffsetAlignment + 8; +constexpr uint64_t kBufferSize = 3 * kMinUniformBufferOffsetAlignment + 8; constexpr uint32_t kBindingSize = 9; class SetBindGroupValidationTest : public ValidationTest { @@ -1610,11 +1640,11 @@ TEST_F(SetBindGroupValidationTest, DynamicOffsetOrder) { // end of the buffer. Any mismatch applying too-large of an offset to a smaller buffer will hit // the out-of-bounds condition during validation. wgpu::Buffer buffer3x = - CreateBuffer(3 * kMinDynamicBufferOffsetAlignment + 4, wgpu::BufferUsage::Storage); + CreateBuffer(3 * kMinUniformBufferOffsetAlignment + 4, wgpu::BufferUsage::Storage); wgpu::Buffer buffer2x = - CreateBuffer(2 * kMinDynamicBufferOffsetAlignment + 4, wgpu::BufferUsage::Storage); + CreateBuffer(2 * kMinUniformBufferOffsetAlignment + 4, wgpu::BufferUsage::Storage); wgpu::Buffer buffer1x = - CreateBuffer(1 * kMinDynamicBufferOffsetAlignment + 4, wgpu::BufferUsage::Uniform); + CreateBuffer(1 * kMinUniformBufferOffsetAlignment + 4, wgpu::BufferUsage::Uniform); wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, { {0, buffer3x, 0, 4}, @@ -1638,7 +1668,7 @@ TEST_F(SetBindGroupValidationTest, DynamicOffsetOrder) { // Offset the first binding to touch the end of the buffer. Should succeed. // Will fail if the offset is applied to the first or second bindings since their buffers // are too small. - offsets = {/* binding 0 */ 3 * kMinDynamicBufferOffsetAlignment, + offsets = {/* binding 0 */ 3 * kMinUniformBufferOffsetAlignment, /* binding 2 */ 0, /* binding 3 */ 0}; wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); @@ -1650,7 +1680,7 @@ TEST_F(SetBindGroupValidationTest, DynamicOffsetOrder) { { // Offset the second binding to touch the end of the buffer. Should succeed. offsets = {/* binding 0 */ 0, - /* binding 2 */ 1 * kMinDynamicBufferOffsetAlignment, + /* binding 2 */ 1 * kMinUniformBufferOffsetAlignment, /* binding 3 */ 0}; wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); wgpu::ComputePassEncoder computePassEncoder = commandEncoder.BeginComputePass(); @@ -1664,7 +1694,7 @@ TEST_F(SetBindGroupValidationTest, DynamicOffsetOrder) { // is too small. offsets = {/* binding 0 */ 0, /* binding 2 */ 0, - /* binding 3 */ 2 * kMinDynamicBufferOffsetAlignment}; + /* binding 3 */ 2 * kMinUniformBufferOffsetAlignment}; wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); wgpu::ComputePassEncoder computePassEncoder = commandEncoder.BeginComputePass(); computePassEncoder.SetBindGroup(0, bindGroup, offsets.size(), offsets.data()); @@ -1673,9 +1703,9 @@ TEST_F(SetBindGroupValidationTest, DynamicOffsetOrder) { } { // Offset each binding to touch the end of their buffer. Should succeed. - offsets = {/* binding 0 */ 3 * kMinDynamicBufferOffsetAlignment, - /* binding 2 */ 1 * kMinDynamicBufferOffsetAlignment, - /* binding 3 */ 2 * kMinDynamicBufferOffsetAlignment}; + offsets = {/* binding 0 */ 3 * kMinUniformBufferOffsetAlignment, + /* binding 2 */ 1 * kMinUniformBufferOffsetAlignment, + /* binding 3 */ 2 * kMinUniformBufferOffsetAlignment}; wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); wgpu::ComputePassEncoder computePassEncoder = commandEncoder.BeginComputePass(); computePassEncoder.SetBindGroup(0, bindGroup, offsets.size(), offsets.data()); diff --git a/src/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp b/src/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp index 249325a100..4505398edd 100644 --- a/src/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp +++ b/src/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp @@ -101,45 +101,30 @@ namespace { // Test OOB color attachment indices are handled TEST_F(RenderPassDescriptorValidationTest, ColorAttachmentOutOfBounds) { - wgpu::TextureView color0 = - Create2DAttachment(device, 1, 1, wgpu::TextureFormat::RGBA8Unorm); - wgpu::TextureView color1 = - Create2DAttachment(device, 1, 1, wgpu::TextureFormat::RGBA8Unorm); - wgpu::TextureView color2 = - Create2DAttachment(device, 1, 1, wgpu::TextureFormat::RGBA8Unorm); - wgpu::TextureView color3 = - Create2DAttachment(device, 1, 1, wgpu::TextureFormat::RGBA8Unorm); - // For setting the color attachment, control case + std::array + colorAttachments; + for (uint32_t i = 0; i < colorAttachments.size(); i++) { + colorAttachments[i].view = + Create2DAttachment(device, 1, 1, wgpu::TextureFormat::RGBA8Unorm); + colorAttachments[i].resolveTarget = nullptr; + colorAttachments[i].clearColor = {0.0f, 0.0f, 0.0f, 0.0f}; + colorAttachments[i].loadOp = wgpu::LoadOp::Clear; + colorAttachments[i].storeOp = wgpu::StoreOp::Store; + } + + // Control case: kMaxColorAttachments is valid. { - utils::ComboRenderPassDescriptor renderPass({color0, color1, color2, color3}); + wgpu::RenderPassDescriptor renderPass; + renderPass.colorAttachmentCount = kMaxColorAttachments; + renderPass.colorAttachments = colorAttachments.data(); + renderPass.depthStencilAttachment = nullptr; AssertBeginRenderPassSuccess(&renderPass); } - // For setting the color attachment, OOB + + // Error case: kMaxColorAttachments + 1 is an error. { - // We cannot use utils::ComboRenderPassDescriptor here because it only supports at most - // kMaxColorAttachments(4) color attachments. - std::array colorAttachments; - colorAttachments[0].view = color0; - colorAttachments[0].resolveTarget = nullptr; - colorAttachments[0].clearColor = {0.0f, 0.0f, 0.0f, 0.0f}; - colorAttachments[0].loadOp = wgpu::LoadOp::Clear; - colorAttachments[0].storeOp = wgpu::StoreOp::Store; - - colorAttachments[1] = colorAttachments[0]; - colorAttachments[1].view = color1; - - colorAttachments[2] = colorAttachments[0]; - colorAttachments[2].view = color2; - - colorAttachments[3] = colorAttachments[0]; - colorAttachments[3].view = color3; - - colorAttachments[4] = colorAttachments[0]; - colorAttachments[4].view = - Create2DAttachment(device, 1, 1, wgpu::TextureFormat::RGBA8Unorm); - wgpu::RenderPassDescriptor renderPass; - renderPass.colorAttachmentCount = 5; + renderPass.colorAttachmentCount = kMaxColorAttachments + 1; renderPass.colorAttachments = colorAttachments.data(); renderPass.depthStencilAttachment = nullptr; AssertBeginRenderPassError(&renderPass); diff --git a/src/tests/unittests/validation/VertexStateValidationTests.cpp b/src/tests/unittests/validation/VertexStateValidationTests.cpp index 9e264a9582..9ebea1e592 100644 --- a/src/tests/unittests/validation/VertexStateValidationTests.cpp +++ b/src/tests/unittests/validation/VertexStateValidationTests.cpp @@ -199,12 +199,12 @@ TEST_F(VertexStateTest, SetInputStrideOutOfBounds) { // Control case, setting max input arrayStride utils::ComboVertexStateDescriptor state; state.vertexBufferCount = 1; - state.cVertexBuffers[0].arrayStride = kMaxVertexBufferStride; + state.cVertexBuffers[0].arrayStride = kMaxVertexBufferArrayStride; state.cVertexBuffers[0].attributeCount = 1; CreatePipeline(true, state, kDummyVertexShader); // Test input arrayStride OOB - state.cVertexBuffers[0].arrayStride = kMaxVertexBufferStride + 1; + state.cVertexBuffers[0].arrayStride = kMaxVertexBufferArrayStride + 1; CreatePipeline(false, state, kDummyVertexShader); } @@ -283,11 +283,11 @@ TEST_F(VertexStateTest, SetAttributeOffsetOutOfBounds) { utils::ComboVertexStateDescriptor state; state.vertexBufferCount = 1; state.cVertexBuffers[0].attributeCount = 1; - state.cAttributes[0].offset = kMaxVertexBufferStride - sizeof(wgpu::VertexFormat::Float32); + state.cAttributes[0].offset = kMaxVertexBufferArrayStride - sizeof(wgpu::VertexFormat::Float32); CreatePipeline(true, state, kDummyVertexShader); // Test attribute offset out of bounds - state.cAttributes[0].offset = kMaxVertexBufferStride - 1; + state.cAttributes[0].offset = kMaxVertexBufferArrayStride - 1; CreatePipeline(false, state, kDummyVertexShader); }