diff --git a/src/dawn_native/Limits.cpp b/src/dawn_native/Limits.cpp index 33cffdc907..b4b61c9aec 100644 --- a/src/dawn_native/Limits.cpp +++ b/src/dawn_native/Limits.cpp @@ -57,8 +57,13 @@ namespace dawn_native { template <> struct CheckLimit { template - static MaybeError Invoke(T supported, T required) { - if (required < supported) { + static bool IsBetter(T lhs, T rhs) { + return lhs < rhs; + } + + template + static MaybeError Validate(T supported, T required) { + if (IsBetter(required, supported)) { return DAWN_VALIDATION_ERROR("requiredLimit lower than supported limit"); } return {}; @@ -68,8 +73,13 @@ namespace dawn_native { template <> struct CheckLimit { template - static MaybeError Invoke(T supported, T required) { - if (required > supported) { + static bool IsBetter(T lhs, T rhs) { + return lhs > rhs; + } + + template + static MaybeError Validate(T supported, T required) { + if (IsBetter(required, supported)) { return DAWN_VALIDATION_ERROR("requiredLimit greater than supported limit"); } return {}; @@ -103,11 +113,14 @@ namespace dawn_native { Limits ReifyDefaultLimits(const Limits& limits) { Limits out; -#define X(Better, limitName, defaultValue) \ - if (!IsLimitUndefined(limits.limitName)) { \ - out.limitName = limits.limitName; \ - } else { \ - out.limitName = defaultValue; \ +#define X(Better, limitName, defaultValue) \ + if (IsLimitUndefined(limits.limitName) || \ + CheckLimit::IsBetter( \ + static_cast(defaultValue), limits.limitName)) { \ + /* If the limit is undefined or the default is better, use the default */ \ + out.limitName = defaultValue; \ + } else { \ + out.limitName = limits.limitName; \ } LIMITS(X) #undef X @@ -115,10 +128,10 @@ namespace dawn_native { } MaybeError ValidateLimits(const Limits& supportedLimits, const Limits& requiredLimits) { -#define X(Better, limitName, defaultValue) \ - if (!IsLimitUndefined(requiredLimits.limitName)) { \ - DAWN_TRY(CheckLimit::Invoke(supportedLimits.limitName, \ - requiredLimits.limitName)); \ +#define X(Better, limitName, defaultValue) \ + if (!IsLimitUndefined(requiredLimits.limitName)) { \ + DAWN_TRY(CheckLimit::Validate(supportedLimits.limitName, \ + requiredLimits.limitName)); \ } LIMITS(X) #undef X diff --git a/src/dawn_native/Limits.h b/src/dawn_native/Limits.h index 76f8ec3f55..409c1ffe85 100644 --- a/src/dawn_native/Limits.h +++ b/src/dawn_native/Limits.h @@ -28,7 +28,8 @@ namespace dawn_native { void GetDefaultLimits(Limits* limits); // Returns a copy of |limits| where all undefined values are replaced - // with their defaults. + // with their defaults. Also clamps to the defaults if the provided limits + // are worse. Limits ReifyDefaultLimits(const Limits& limits); // Validate that |requiredLimits| are no better than |supportedLimits|. diff --git a/src/tests/unittests/validation/RequestDeviceValidationTests.cpp b/src/tests/unittests/validation/RequestDeviceValidationTests.cpp index 5e8bd9b25a..d64b78e20d 100644 --- a/src/tests/unittests/validation/RequestDeviceValidationTests.cpp +++ b/src/tests/unittests/validation/RequestDeviceValidationTests.cpp @@ -91,18 +91,20 @@ TEST_F(RequestDeviceValidationTest, HigherIsBetter) { wgpu::SupportedLimits supportedLimits; EXPECT_TRUE(adapter.GetLimits(reinterpret_cast(&supportedLimits))); - // Test below the max. - limits.limits.maxBindGroups = supportedLimits.limits.maxBindGroups - 1; - adapter.RequestDevice( - &descriptor, ExpectRequestDeviceSuccess, CheckDevice([&](wgpu::Device device) { - wgpu::SupportedLimits limits; - device.GetLimits(&limits); + // If we can support better than the default, test below the max. + if (supportedLimits.limits.maxBindGroups > 4u) { + limits.limits.maxBindGroups = supportedLimits.limits.maxBindGroups - 1; + adapter.RequestDevice( + &descriptor, ExpectRequestDeviceSuccess, CheckDevice([&](wgpu::Device device) { + wgpu::SupportedLimits limits; + device.GetLimits(&limits); - // Check we got exactly the request. - EXPECT_EQ(limits.limits.maxBindGroups, supportedLimits.limits.maxBindGroups - 1); - // Check another default limit. - EXPECT_EQ(limits.limits.maxTextureArrayLayers, 256u); - })); + // Check we got exactly the request. + EXPECT_EQ(limits.limits.maxBindGroups, supportedLimits.limits.maxBindGroups - 1); + // Check another default limit. + EXPECT_EQ(limits.limits.maxTextureArrayLayers, 256u); + })); + } // Test the max. limits.limits.maxBindGroups = supportedLimits.limits.maxBindGroups; @@ -120,6 +122,17 @@ TEST_F(RequestDeviceValidationTest, HigherIsBetter) { // Test above the max. limits.limits.maxBindGroups = supportedLimits.limits.maxBindGroups + 1; adapter.RequestDevice(&descriptor, ExpectRequestDeviceError, nullptr); + + // Test worse than the default + limits.limits.maxBindGroups = 3u; + adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess, + CheckDevice([&](wgpu::Device device) { + wgpu::SupportedLimits limits; + device.GetLimits(&limits); + + // Check we got the default. + EXPECT_EQ(limits.limits.maxBindGroups, 4u); + })); } // Test that requesting a device where a required limit is below the minimum value. @@ -151,19 +164,32 @@ TEST_F(RequestDeviceValidationTest, LowerIsBetter) { EXPECT_EQ(limits.limits.maxTextureArrayLayers, 256u); })); - // Test above the min. - limits.limits.minUniformBufferOffsetAlignment = - supportedLimits.limits.minUniformBufferOffsetAlignment * 2; + // IF we can support better than the default, test above the min. + if (supportedLimits.limits.minUniformBufferOffsetAlignment > 256u) { + limits.limits.minUniformBufferOffsetAlignment = + supportedLimits.limits.minUniformBufferOffsetAlignment * 2; + adapter.RequestDevice( + &descriptor, ExpectRequestDeviceSuccess, CheckDevice([&](wgpu::Device device) { + wgpu::SupportedLimits limits; + device.GetLimits(&limits); + + // Check we got exactly the request. + EXPECT_EQ(limits.limits.minUniformBufferOffsetAlignment, + supportedLimits.limits.minUniformBufferOffsetAlignment * 2); + // Check another default limit. + EXPECT_EQ(limits.limits.maxTextureArrayLayers, 256u); + })); + } + + // Test worse than the default + limits.limits.minUniformBufferOffsetAlignment = 2u * 256u; adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess, CheckDevice([&](wgpu::Device device) { wgpu::SupportedLimits limits; device.GetLimits(&limits); - // Check we got exactly the request. - EXPECT_EQ(limits.limits.minUniformBufferOffsetAlignment, - supportedLimits.limits.minUniformBufferOffsetAlignment * 2); - // Check another default limit. - EXPECT_EQ(limits.limits.maxTextureArrayLayers, 256u); + // Check we got the default. + EXPECT_EQ(limits.limits.minUniformBufferOffsetAlignment, 256u); })); }