From 148e7fab1ca1c6134f2e6e242115bfaf3fb39c8c Mon Sep 17 00:00:00 2001 From: Austin Eng Date: Mon, 27 Feb 2023 20:22:51 +0000 Subject: [PATCH] Raise maxStorageTexturesPerShaderStage to 8 The higher tier for this limit is available on all D3D12, all Metal, and most Vulkan devices. Bug: dawn:685 Change-Id: Ic2a39ad7908ea178e7aac48b7bb54b262d7039cf Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/121543 Kokoro: Kokoro Reviewed-by: Shrek Shao Reviewed-by: Corentin Wallez Commit-Queue: Austin Eng --- src/dawn/common/Constants.h | 4 +- src/dawn/native/BindingInfo.cpp | 57 +++---- src/dawn/native/Limits.cpp | 10 +- src/dawn/tests/end2end/BindGroupTests.cpp | 144 ----------------- src/dawn/tests/end2end/MaxLimitTests.cpp | 146 ++++++++++++++++++ .../validation/BindGroupValidationTests.cpp | 35 +++-- 6 files changed, 207 insertions(+), 189 deletions(-) diff --git a/src/dawn/common/Constants.h b/src/dawn/common/Constants.h index ca4c3b6b88..3604b5c8ab 100644 --- a/src/dawn/common/Constants.h +++ b/src/dawn/common/Constants.h @@ -31,11 +31,11 @@ static constexpr uint32_t kMaxInterStageShaderVariables = 16u; static constexpr uint64_t kAssumedMaxBufferSize = 0x80000000u; // Use 2 GB when the limit is unavailable -// Per stage limits +// Per stage maximum limits used to optimized Dawn internals. static constexpr uint32_t kMaxSampledTexturesPerShaderStage = 16; static constexpr uint32_t kMaxSamplersPerShaderStage = 16; static constexpr uint32_t kMaxStorageBuffersPerShaderStage = 8; -static constexpr uint32_t kMaxStorageTexturesPerShaderStage = 4; +static constexpr uint32_t kMaxStorageTexturesPerShaderStage = 8; static constexpr uint32_t kMaxUniformBuffersPerShaderStage = 12; // Indirect command sizes diff --git a/src/dawn/native/BindingInfo.cpp b/src/dawn/native/BindingInfo.cpp index ba969373be..24ce3f5e05 100644 --- a/src/dawn/native/BindingInfo.cpp +++ b/src/dawn/native/BindingInfo.cpp @@ -112,80 +112,85 @@ MaybeError ValidateBindingCounts(const CombinedLimits& limits, const BindingCoun limits.v1.maxDynamicStorageBuffersPerPipelineLayout); for (SingleShaderStage stage : IterateStages(kAllStages)) { - DAWN_INVALID_IF( - bindingCounts.perStage[stage].sampledTextureCount > kMaxSampledTexturesPerShaderStage, - "The number of sampled textures (%u) in the %s stage exceeds the maximum " - "per-stage limit (%u).", - bindingCounts.perStage[stage].sampledTextureCount, stage, - kMaxSampledTexturesPerShaderStage); + DAWN_INVALID_IF(bindingCounts.perStage[stage].sampledTextureCount > + limits.v1.maxSampledTexturesPerShaderStage, + "The number of sampled textures (%u) in the %s stage exceeds the maximum " + "per-stage limit (%u).", + bindingCounts.perStage[stage].sampledTextureCount, stage, + limits.v1.maxSampledTexturesPerShaderStage); // The per-stage number of external textures is bound by the maximum sampled textures // per stage. - DAWN_INVALID_IF(bindingCounts.perStage[stage].externalTextureCount > - kMaxSampledTexturesPerShaderStage / kSampledTexturesPerExternalTexture, - "The number of external textures (%u) in the %s stage exceeds the maximum " - "per-stage limit (%u).", - bindingCounts.perStage[stage].externalTextureCount, stage, - kMaxSampledTexturesPerShaderStage / kSampledTexturesPerExternalTexture); + DAWN_INVALID_IF( + bindingCounts.perStage[stage].externalTextureCount > + limits.v1.maxSampledTexturesPerShaderStage / kSampledTexturesPerExternalTexture, + "The number of external textures (%u) in the %s stage exceeds the maximum " + "per-stage limit (%u).", + bindingCounts.perStage[stage].externalTextureCount, stage, + limits.v1.maxSampledTexturesPerShaderStage / kSampledTexturesPerExternalTexture); DAWN_INVALID_IF( bindingCounts.perStage[stage].sampledTextureCount + (bindingCounts.perStage[stage].externalTextureCount * kSampledTexturesPerExternalTexture) > - kMaxSampledTexturesPerShaderStage, + limits.v1.maxSampledTexturesPerShaderStage, "The combination of sampled textures (%u) and external textures (%u) in the %s " "stage exceeds the maximum per-stage limit (%u).", bindingCounts.perStage[stage].sampledTextureCount, bindingCounts.perStage[stage].externalTextureCount, stage, - kMaxSampledTexturesPerShaderStage); + limits.v1.maxSampledTexturesPerShaderStage); DAWN_INVALID_IF( - bindingCounts.perStage[stage].samplerCount > kMaxSamplersPerShaderStage, + bindingCounts.perStage[stage].samplerCount > limits.v1.maxSamplersPerShaderStage, "The number of samplers (%u) in the %s stage exceeds the maximum per-stage limit " "(%u).", - bindingCounts.perStage[stage].samplerCount, stage, kMaxSamplersPerShaderStage); + bindingCounts.perStage[stage].samplerCount, stage, limits.v1.maxSamplersPerShaderStage); DAWN_INVALID_IF( bindingCounts.perStage[stage].samplerCount + (bindingCounts.perStage[stage].externalTextureCount * kSamplersPerExternalTexture) > - kMaxSamplersPerShaderStage, + limits.v1.maxSamplersPerShaderStage, "The combination of samplers (%u) and external textures (%u) in the %s stage " "exceeds the maximum per-stage limit (%u).", bindingCounts.perStage[stage].samplerCount, - bindingCounts.perStage[stage].externalTextureCount, stage, kMaxSamplersPerShaderStage); + bindingCounts.perStage[stage].externalTextureCount, stage, + limits.v1.maxSamplersPerShaderStage); DAWN_INVALID_IF( - bindingCounts.perStage[stage].storageBufferCount > kMaxStorageBuffersPerShaderStage, + bindingCounts.perStage[stage].storageBufferCount > + limits.v1.maxStorageBuffersPerShaderStage, "The number of storage buffers (%u) in the %s stage exceeds the maximum per-stage " "limit (%u).", bindingCounts.perStage[stage].storageBufferCount, stage, - kMaxStorageBuffersPerShaderStage); + limits.v1.maxStorageBuffersPerShaderStage); DAWN_INVALID_IF( - bindingCounts.perStage[stage].storageTextureCount > kMaxStorageTexturesPerShaderStage, + bindingCounts.perStage[stage].storageTextureCount > + limits.v1.maxStorageTexturesPerShaderStage, "The number of storage textures (%u) in the %s stage exceeds the maximum per-stage " "limit (%u).", bindingCounts.perStage[stage].storageTextureCount, stage, - kMaxStorageTexturesPerShaderStage); + limits.v1.maxStorageTexturesPerShaderStage); DAWN_INVALID_IF( - bindingCounts.perStage[stage].uniformBufferCount > kMaxUniformBuffersPerShaderStage, + bindingCounts.perStage[stage].uniformBufferCount > + limits.v1.maxUniformBuffersPerShaderStage, "The number of uniform buffers (%u) in the %s stage exceeds the maximum per-stage " "limit (%u).", bindingCounts.perStage[stage].uniformBufferCount, stage, - kMaxUniformBuffersPerShaderStage); + limits.v1.maxUniformBuffersPerShaderStage); DAWN_INVALID_IF( bindingCounts.perStage[stage].uniformBufferCount + (bindingCounts.perStage[stage].externalTextureCount * kUniformsPerExternalTexture) > - kMaxUniformBuffersPerShaderStage, + limits.v1.maxUniformBuffersPerShaderStage, "The combination of uniform buffers (%u) and external textures (%u) in the %s " "stage exceeds the maximum per-stage limit (%u).", bindingCounts.perStage[stage].uniformBufferCount, bindingCounts.perStage[stage].externalTextureCount, stage, - kMaxUniformBuffersPerShaderStage); + limits.v1.maxUniformBuffersPerShaderStage); } return {}; diff --git a/src/dawn/native/Limits.cpp b/src/dawn/native/Limits.cpp index a17c355592..fb14fd2165 100644 --- a/src/dawn/native/Limits.cpp +++ b/src/dawn/native/Limits.cpp @@ -38,6 +38,11 @@ #define LIMITS_RESOURCE_BINDINGS(X) \ X(Maximum, maxDynamicUniformBuffersPerPipelineLayout, 8, 10) \ X(Maximum, maxDynamicStorageBuffersPerPipelineLayout, 4, 8) \ + X(Maximum, maxSampledTexturesPerShaderStage, 16, 16) \ + X(Maximum, maxSamplersPerShaderStage, 16, 16) \ + X(Maximum, maxStorageBuffersPerShaderStage, 8, 8) \ + X(Maximum, maxStorageTexturesPerShaderStage, 4, 8) \ + X(Maximum, maxUniformBuffersPerShaderStage, 12, 12) // TODO(crbug.com/dawn/685): // These limits don't have tiers yet. Define two tiers with the same values since the macros @@ -49,11 +54,6 @@ X(Maximum, maxTextureArrayLayers, 256, 256) \ X(Maximum, maxBindGroups, 4, 4) \ X(Maximum, maxBindingsPerBindGroup, 640, 640) \ - X(Maximum, maxSampledTexturesPerShaderStage, 16, 16) \ - X(Maximum, maxSamplersPerShaderStage, 16, 16) \ - X(Maximum, maxStorageBuffersPerShaderStage, 8, 8) \ - X(Maximum, maxStorageTexturesPerShaderStage, 4, 4) \ - X(Maximum, maxUniformBuffersPerShaderStage, 12, 12) \ X(Maximum, maxUniformBufferBindingSize, 65536, 65536) \ X(Alignment, minUniformBufferOffsetAlignment, 256, 256) \ X(Alignment, minStorageBufferOffsetAlignment, 256, 256) \ diff --git a/src/dawn/tests/end2end/BindGroupTests.cpp b/src/dawn/tests/end2end/BindGroupTests.cpp index a7b6e0ddc0..2117c2e0a7 100644 --- a/src/dawn/tests/end2end/BindGroupTests.cpp +++ b/src/dawn/tests/end2end/BindGroupTests.cpp @@ -1427,150 +1427,6 @@ TEST_P(BindGroupTests, ReadonlyStorage) { EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8::kGreen, renderPass.color, 0, 0); } -// Test that creating a large bind group, with each binding type at the max count, works and can be -// used correctly. The test loads a different value from each binding, and writes 1 to a storage -// buffer if all values are correct. -TEST_P(BindGroupTests, ReallyLargeBindGroup) { - DAWN_SUPPRESS_TEST_IF(IsOpenGLES()); - std::ostringstream interface; - std::ostringstream body; - uint32_t binding = 0; - uint32_t expectedValue = 42; - - wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); - - auto CreateTextureWithRedData = [&](wgpu::TextureFormat format, uint32_t value, - wgpu::TextureUsage usage) { - wgpu::TextureDescriptor textureDesc = {}; - textureDesc.usage = wgpu::TextureUsage::CopyDst | usage; - textureDesc.size = {1, 1, 1}; - textureDesc.format = format; - wgpu::Texture texture = device.CreateTexture(&textureDesc); - - if (format == wgpu::TextureFormat::R8Unorm) { - ASSERT(expectedValue < 255u); - } - wgpu::Buffer textureData = - utils::CreateBufferFromData(device, wgpu::BufferUsage::CopySrc, {value}); - - wgpu::ImageCopyBuffer imageCopyBuffer = {}; - imageCopyBuffer.buffer = textureData; - imageCopyBuffer.layout.bytesPerRow = 256; - - wgpu::ImageCopyTexture imageCopyTexture = {}; - imageCopyTexture.texture = texture; - - wgpu::Extent3D copySize = {1, 1, 1}; - - commandEncoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, ©Size); - return texture; - }; - - std::vector bgEntries; - static_assert(kMaxSampledTexturesPerShaderStage == kMaxSamplersPerShaderStage, - "Please update this test"); - for (uint32_t i = 0; i < kMaxSampledTexturesPerShaderStage; ++i) { - wgpu::Texture texture = CreateTextureWithRedData( - wgpu::TextureFormat::R8Unorm, expectedValue, wgpu::TextureUsage::TextureBinding); - bgEntries.push_back({nullptr, binding, nullptr, 0, 0, nullptr, texture.CreateView()}); - - interface << "@group(0) @binding(" << binding++ << ") " - << "var tex" << i << " : texture_2d;\n"; - - bgEntries.push_back({nullptr, binding, nullptr, 0, 0, device.CreateSampler(), nullptr}); - - interface << "@group(0) @binding(" << binding++ << ")" - << "var samp" << i << " : sampler;\n"; - - body << "if (abs(textureSampleLevel(tex" << i << ", samp" << i - << ", vec2f(0.5, 0.5), 0.0).r - " << expectedValue++ << ".0 / 255.0) > 0.0001) {\n"; - body << " return;\n"; - body << "}\n"; - } - for (uint32_t i = 0; i < kMaxStorageTexturesPerShaderStage; ++i) { - wgpu::Texture texture = CreateTextureWithRedData( - wgpu::TextureFormat::R32Uint, expectedValue, wgpu::TextureUsage::StorageBinding); - bgEntries.push_back({nullptr, binding, nullptr, 0, 0, nullptr, texture.CreateView()}); - - interface << "@group(0) @binding(" << binding++ << ") " - << "var image" << i << " : texture_storage_2d;\n"; - - body << "_ = image" << i << ";"; - } - - for (uint32_t i = 0; i < kMaxUniformBuffersPerShaderStage; ++i) { - wgpu::Buffer buffer = utils::CreateBufferFromData( - device, wgpu::BufferUsage::Uniform, {expectedValue, 0, 0, 0}); - bgEntries.push_back({nullptr, binding, buffer, 0, 4 * sizeof(uint32_t), nullptr, nullptr}); - - interface << "struct UniformBuffer" << i << R"({ - value : u32 - } - )"; - interface << "@group(0) @binding(" << binding++ << ") " - << "var ubuf" << i << " : UniformBuffer" << i << ";\n"; - - body << "if (ubuf" << i << ".value != " << expectedValue++ << "u) {\n"; - body << " return;\n"; - body << "}\n"; - } - // Save one storage buffer for writing the result - for (uint32_t i = 0; i < kMaxStorageBuffersPerShaderStage - 1; ++i) { - wgpu::Buffer buffer = utils::CreateBufferFromData( - device, wgpu::BufferUsage::Storage, {expectedValue}); - bgEntries.push_back({nullptr, binding, buffer, 0, sizeof(uint32_t), nullptr, nullptr}); - - interface << "struct ReadOnlyStorageBuffer" << i << R"({ - value : u32 - } - )"; - interface << "@group(0) @binding(" << binding++ << ") " - << "var sbuf" << i << " : ReadOnlyStorageBuffer" << i << ";\n"; - - body << "if (sbuf" << i << ".value != " << expectedValue++ << "u) {\n"; - body << " return;\n"; - body << "}\n"; - } - - wgpu::Buffer result = utils::CreateBufferFromData( - device, wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc, {0}); - bgEntries.push_back({nullptr, binding, result, 0, sizeof(uint32_t), nullptr, nullptr}); - - interface << R"(struct ReadWriteStorageBuffer{ - value : u32 - } - )"; - interface << "@group(0) @binding(" << binding++ << ") " - << "var result : ReadWriteStorageBuffer;\n"; - - body << "result.value = 1u;\n"; - - std::string shader = - interface.str() + "@compute @workgroup_size(1) fn main() {\n" + body.str() + "}\n"; - wgpu::ComputePipelineDescriptor cpDesc; - cpDesc.compute.module = utils::CreateShaderModule(device, shader.c_str()); - cpDesc.compute.entryPoint = "main"; - wgpu::ComputePipeline cp = device.CreateComputePipeline(&cpDesc); - - wgpu::BindGroupDescriptor bgDesc = {}; - bgDesc.layout = cp.GetBindGroupLayout(0); - bgDesc.entryCount = static_cast(bgEntries.size()); - bgDesc.entries = bgEntries.data(); - - wgpu::BindGroup bg = device.CreateBindGroup(&bgDesc); - - wgpu::ComputePassEncoder pass = commandEncoder.BeginComputePass(); - pass.SetPipeline(cp); - pass.SetBindGroup(0, bg); - pass.DispatchWorkgroups(1, 1, 1); - pass.End(); - - wgpu::CommandBuffer commands = commandEncoder.Finish(); - queue.Submit(1, &commands); - - EXPECT_BUFFER_U32_EQ(1, result, 0); -} - // This is a regression test for crbug.com/dawn/319 where creating a bind group with a // destroyed resource would crash the backend. TEST_P(BindGroupTests, CreateWithDestroyedResource) { diff --git a/src/dawn/tests/end2end/MaxLimitTests.cpp b/src/dawn/tests/end2end/MaxLimitTests.cpp index 2e3320e4a6..1654bb90e2 100644 --- a/src/dawn/tests/end2end/MaxLimitTests.cpp +++ b/src/dawn/tests/end2end/MaxLimitTests.cpp @@ -392,6 +392,152 @@ TEST_P(MaxLimitTests, MaxDynamicBuffers) { EXPECT_TEXTURE_EQ(&expected, renderTarget, {0, 0}, {1, 1}); } +// Test that creating a large bind group, with each binding type at the max count, works and can be +// used correctly. The test loads a different value from each binding, and writes 1 to a storage +// buffer if all values are correct. +TEST_P(MaxLimitTests, ReallyLargeBindGroup) { + DAWN_SUPPRESS_TEST_IF(IsOpenGLES()); + wgpu::Limits limits = GetSupportedLimits().limits; + + std::ostringstream interface; + std::ostringstream body; + uint32_t binding = 0; + uint32_t expectedValue = 42; + + wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); + + auto CreateTextureWithRedData = [&](wgpu::TextureFormat format, uint32_t value, + wgpu::TextureUsage usage) { + wgpu::TextureDescriptor textureDesc = {}; + textureDesc.usage = wgpu::TextureUsage::CopyDst | usage; + textureDesc.size = {1, 1, 1}; + textureDesc.format = format; + wgpu::Texture texture = device.CreateTexture(&textureDesc); + + if (format == wgpu::TextureFormat::R8Unorm) { + ASSERT(expectedValue < 255u); + } + wgpu::Buffer textureData = + utils::CreateBufferFromData(device, wgpu::BufferUsage::CopySrc, {value}); + + wgpu::ImageCopyBuffer imageCopyBuffer = {}; + imageCopyBuffer.buffer = textureData; + imageCopyBuffer.layout.bytesPerRow = 256; + + wgpu::ImageCopyTexture imageCopyTexture = {}; + imageCopyTexture.texture = texture; + + wgpu::Extent3D copySize = {1, 1, 1}; + + commandEncoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, ©Size); + return texture; + }; + + std::vector bgEntries; + for (uint32_t i = 0; + i < std::min(limits.maxSampledTexturesPerShaderStage, limits.maxSamplersPerShaderStage); + ++i) { + wgpu::Texture texture = CreateTextureWithRedData( + wgpu::TextureFormat::R8Unorm, expectedValue, wgpu::TextureUsage::TextureBinding); + bgEntries.push_back({nullptr, binding, nullptr, 0, 0, nullptr, texture.CreateView()}); + + interface << "@group(0) @binding(" << binding++ << ") " + << "var tex" << i << " : texture_2d;\n"; + + bgEntries.push_back({nullptr, binding, nullptr, 0, 0, device.CreateSampler(), nullptr}); + + interface << "@group(0) @binding(" << binding++ << ")" + << "var samp" << i << " : sampler;\n"; + + body << "if (abs(textureSampleLevel(tex" << i << ", samp" << i + << ", vec2f(0.5, 0.5), 0.0).r - " << expectedValue++ << ".0 / 255.0) > 0.0001) {\n"; + body << " return;\n"; + body << "}\n"; + } + for (uint32_t i = 0; i < limits.maxStorageTexturesPerShaderStage; ++i) { + wgpu::Texture texture = CreateTextureWithRedData( + wgpu::TextureFormat::R32Uint, expectedValue, wgpu::TextureUsage::StorageBinding); + bgEntries.push_back({nullptr, binding, nullptr, 0, 0, nullptr, texture.CreateView()}); + + interface << "@group(0) @binding(" << binding++ << ") " + << "var image" << i << " : texture_storage_2d;\n"; + + body << "_ = image" << i << ";"; + } + + for (uint32_t i = 0; i < limits.maxUniformBuffersPerShaderStage; ++i) { + wgpu::Buffer buffer = utils::CreateBufferFromData( + device, wgpu::BufferUsage::Uniform, {expectedValue, 0, 0, 0}); + bgEntries.push_back({nullptr, binding, buffer, 0, 4 * sizeof(uint32_t), nullptr, nullptr}); + + interface << "struct UniformBuffer" << i << R"({ + value : u32 + } + )"; + interface << "@group(0) @binding(" << binding++ << ") " + << "var ubuf" << i << " : UniformBuffer" << i << ";\n"; + + body << "if (ubuf" << i << ".value != " << expectedValue++ << "u) {\n"; + body << " return;\n"; + body << "}\n"; + } + // Save one storage buffer for writing the result + for (uint32_t i = 0; i < limits.maxStorageBuffersPerShaderStage - 1; ++i) { + wgpu::Buffer buffer = utils::CreateBufferFromData( + device, wgpu::BufferUsage::Storage, {expectedValue}); + bgEntries.push_back({nullptr, binding, buffer, 0, sizeof(uint32_t), nullptr, nullptr}); + + interface << "struct ReadOnlyStorageBuffer" << i << R"({ + value : u32 + } + )"; + interface << "@group(0) @binding(" << binding++ << ") " + << "var sbuf" << i << " : ReadOnlyStorageBuffer" << i << ";\n"; + + body << "if (sbuf" << i << ".value != " << expectedValue++ << "u) {\n"; + body << " return;\n"; + body << "}\n"; + } + + wgpu::Buffer result = utils::CreateBufferFromData( + device, wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc, {0}); + bgEntries.push_back({nullptr, binding, result, 0, sizeof(uint32_t), nullptr, nullptr}); + + interface << R"(struct ReadWriteStorageBuffer{ + value : u32 + } + )"; + interface << "@group(0) @binding(" << binding++ << ") " + << "var result : ReadWriteStorageBuffer;\n"; + + body << "result.value = 1u;\n"; + + std::string shader = + interface.str() + "@compute @workgroup_size(1) fn main() {\n" + body.str() + "}\n"; + wgpu::ComputePipelineDescriptor cpDesc; + cpDesc.compute.module = utils::CreateShaderModule(device, shader.c_str()); + cpDesc.compute.entryPoint = "main"; + wgpu::ComputePipeline cp = device.CreateComputePipeline(&cpDesc); + + wgpu::BindGroupDescriptor bgDesc = {}; + bgDesc.layout = cp.GetBindGroupLayout(0); + bgDesc.entryCount = static_cast(bgEntries.size()); + bgDesc.entries = bgEntries.data(); + + wgpu::BindGroup bg = device.CreateBindGroup(&bgDesc); + + wgpu::ComputePassEncoder pass = commandEncoder.BeginComputePass(); + pass.SetPipeline(cp); + pass.SetBindGroup(0, bg); + pass.DispatchWorkgroups(1, 1, 1); + pass.End(); + + wgpu::CommandBuffer commands = commandEncoder.Finish(); + queue.Submit(1, &commands); + + EXPECT_BUFFER_U32_EQ(1, result, 0); +} + DAWN_INSTANTIATE_TEST(MaxLimitTests, D3D12Backend(), MetalBackend(), diff --git a/src/dawn/tests/unittests/validation/BindGroupValidationTests.cpp b/src/dawn/tests/unittests/validation/BindGroupValidationTests.cpp index 4e8c069d36..87c0f6f2a1 100644 --- a/src/dawn/tests/unittests/validation/BindGroupValidationTests.cpp +++ b/src/dawn/tests/unittests/validation/BindGroupValidationTests.cpp @@ -1293,25 +1293,32 @@ TEST_F(BindGroupLayoutValidationTest, PerStageLimits) { wgpu::BindGroupLayoutEntry otherEntry; }; + wgpu::Limits limits = GetSupportedLimits().limits; + std::array kTestInfos = { - TestInfo{kMaxSampledTexturesPerShaderStage, BGLEntryType(wgpu::TextureSampleType::Float), + TestInfo{limits.maxSampledTexturesPerShaderStage, + BGLEntryType(wgpu::TextureSampleType::Float), BGLEntryType(wgpu::BufferBindingType::Uniform)}, - TestInfo{kMaxSamplersPerShaderStage, BGLEntryType(wgpu::SamplerBindingType::Filtering), + TestInfo{limits.maxSamplersPerShaderStage, + BGLEntryType(wgpu::SamplerBindingType::Filtering), BGLEntryType(wgpu::BufferBindingType::Uniform)}, - TestInfo{kMaxSamplersPerShaderStage, BGLEntryType(wgpu::SamplerBindingType::Comparison), + TestInfo{limits.maxSamplersPerShaderStage, + BGLEntryType(wgpu::SamplerBindingType::Comparison), BGLEntryType(wgpu::BufferBindingType::Uniform)}, - TestInfo{kMaxStorageBuffersPerShaderStage, BGLEntryType(wgpu::BufferBindingType::Storage), + TestInfo{limits.maxStorageBuffersPerShaderStage, + BGLEntryType(wgpu::BufferBindingType::Storage), BGLEntryType(wgpu::BufferBindingType::Uniform)}, TestInfo{ - kMaxStorageTexturesPerShaderStage, + limits.maxStorageTexturesPerShaderStage, BGLEntryType(wgpu::StorageTextureAccess::WriteOnly, wgpu::TextureFormat::RGBA8Unorm), BGLEntryType(wgpu::BufferBindingType::Uniform)}, - TestInfo{kMaxUniformBuffersPerShaderStage, BGLEntryType(wgpu::BufferBindingType::Uniform), + TestInfo{limits.maxUniformBuffersPerShaderStage, + BGLEntryType(wgpu::BufferBindingType::Uniform), BGLEntryType(wgpu::TextureSampleType::Float)}, // External textures use multiple bindings (3 sampled textures, 1 sampler, 1 uniform buffer) // that count towards the per stage binding limits. The number of external textures are // currently restricted by the maximum number of sampled textures. - TestInfo{kMaxSampledTexturesPerShaderStage / kSampledTexturesPerExternalTexture, + TestInfo{limits.maxSampledTexturesPerShaderStage / kSampledTexturesPerExternalTexture, BGLEntryType(&utils::kExternalTextureBindingLayout), BGLEntryType(wgpu::BufferBindingType::Uniform)}}; @@ -1388,14 +1395,16 @@ TEST_F(BindGroupLayoutValidationTest, PerStageLimitsWithExternalTexture) { wgpu::BindGroupLayoutEntry otherEntry; }; + wgpu::Limits limits = GetSupportedLimits().limits; + std::array kTestInfos = { - TestInfo{kMaxSampledTexturesPerShaderStage, kSampledTexturesPerExternalTexture, + TestInfo{limits.maxSampledTexturesPerShaderStage, kSampledTexturesPerExternalTexture, BGLEntryType(wgpu::TextureSampleType::Float), BGLEntryType(wgpu::BufferBindingType::Uniform)}, - TestInfo{kMaxSamplersPerShaderStage, kSamplersPerExternalTexture, + TestInfo{limits.maxSamplersPerShaderStage, kSamplersPerExternalTexture, BGLEntryType(wgpu::SamplerBindingType::Filtering), BGLEntryType(wgpu::BufferBindingType::Uniform)}, - TestInfo{kMaxUniformBuffersPerShaderStage, kUniformsPerExternalTexture, + TestInfo{limits.maxUniformBuffersPerShaderStage, kUniformsPerExternalTexture, BGLEntryType(wgpu::BufferBindingType::Uniform), BGLEntryType(wgpu::TextureSampleType::Float)}, }; @@ -1480,8 +1489,10 @@ TEST_F(BindGroupLayoutValidationTest, DynamicBufferNumberLimit) { // In this test, we use all the same shader stage. Ensure that this does not exceed the // per-stage limit. - ASSERT(limits.maxDynamicUniformBuffersPerPipelineLayout <= kMaxUniformBuffersPerShaderStage); - ASSERT(limits.maxDynamicStorageBuffersPerPipelineLayout <= kMaxStorageBuffersPerShaderStage); + ASSERT(limits.maxDynamicUniformBuffersPerPipelineLayout <= + limits.maxUniformBuffersPerShaderStage); + ASSERT(limits.maxDynamicStorageBuffersPerPipelineLayout <= + limits.maxStorageBuffersPerShaderStage); for (uint32_t i = 0; i < limits.maxDynamicUniformBuffersPerPipelineLayout; ++i) { maxUniformDB.push_back(utils::BindingLayoutEntryInitializationHelper(