| // Copyright 2021 The Dawn & Tint Authors | |
| // | |
| // Redistribution and use in source and binary forms, with or without | |
| // modification, are permitted provided that the following conditions are met: | |
| // | |
| // 1. Redistributions of source code must retain the above copyright notice, this | |
| // list of conditions and the following disclaimer. | |
| // | |
| // 2. Redistributions in binary form must reproduce the above copyright notice, | |
| // this list of conditions and the following disclaimer in the documentation | |
| // and/or other materials provided with the distribution. | |
| // | |
| // 3. Neither the name of the copyright holder nor the names of its | |
| // contributors may be used to endorse or promote products derived from | |
| // this software without specific prior written permission. | |
| // | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| #include <utility> | |
| #include <vector> | |
| #include "src/dawn/native/Device.h" | |
| #include "src/dawn/native/dawn_platform.h" | |
| #include "src/dawn/tests/MockCallback.h" | |
| #include "src/dawn/tests/StringViewMatchers.h" | |
| #include "src/dawn/tests/unittests/validation/ValidationTest.h" | |
| namespace dawn { | |
| namespace { | |
| using testing::_; | |
| using testing::EmptySizedString; | |
| using testing::InSequence; | |
| using testing::IsNull; | |
| using testing::MockCppCallback; | |
| using testing::NonEmptySizedString; | |
| using testing::NotNull; | |
| using testing::WithArgs; | |
| class RequestDeviceValidationTest : public ValidationTest { | |
| protected: | |
| using MockDeviceLostCallback = MockCppCallback<wgpu::DeviceLostCallback<void>*>; | |
| void SetUp() override { | |
| ValidationTest::SetUp(); | |
| DAWN_SKIP_TEST_IF(UsesWire()); | |
| } | |
| MockCppCallback<wgpu::RequestDeviceCallback<void>*> mRequestDeviceCallback; | |
| }; | |
| // Test that requesting a device without specifying limits is valid. | |
| TEST_F(RequestDeviceValidationTest, NoRequiredLimits) { | |
| wgpu::DeviceDescriptor descriptor; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([](wgpu::Device device) { | |
| // Check one of the default limits. | |
| wgpu::Limits limits; | |
| device.GetLimits(&limits); | |
| EXPECT_EQ(limits.maxBindGroups, 4u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| // Test that requesting a device with the default limits is valid. | |
| TEST_F(RequestDeviceValidationTest, DefaultLimits) { | |
| wgpu::Limits limits = {}; | |
| wgpu::DeviceDescriptor descriptor; | |
| descriptor.requiredLimits = &limits; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([](wgpu::Device device) { | |
| // Check one of the default limits. | |
| wgpu::Limits limits; | |
| device.GetLimits(&limits); | |
| EXPECT_EQ(limits.maxTextureArrayLayers, 256u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| // Test that requesting a device where a required limit is above the maximum value. | |
| TEST_F(RequestDeviceValidationTest, HigherIsBetter) { | |
| wgpu::Limits limits = {}; | |
| wgpu::DeviceDescriptor descriptor; | |
| descriptor.requiredLimits = &limits; | |
| wgpu::Limits supportedLimits; | |
| EXPECT_EQ(adapter.GetLimits(&supportedLimits), wgpu::Status::Success); | |
| // If we can support better than the default, test below the max. | |
| if (supportedLimits.maxBindGroups > 4u) { | |
| limits.maxBindGroups = supportedLimits.maxBindGroups - 1; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([&](wgpu::Device device) { | |
| wgpu::Limits limits; | |
| device.GetLimits(&limits); | |
| // Check we got exactly the request. | |
| EXPECT_EQ(limits.maxBindGroups, supportedLimits.maxBindGroups - 1); | |
| // Check another default limit. | |
| EXPECT_EQ(limits.maxTextureArrayLayers, 256u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| // Test the max. | |
| limits.maxBindGroups = supportedLimits.maxBindGroups; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([&](wgpu::Device device) { | |
| wgpu::Limits limits; | |
| device.GetLimits(&limits); | |
| // Check we got exactly the request. | |
| EXPECT_EQ(limits.maxBindGroups, supportedLimits.maxBindGroups); | |
| // Check another default limit. | |
| EXPECT_EQ(limits.maxTextureArrayLayers, 256u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| // Test above the max. | |
| limits.maxBindGroups = supportedLimits.maxBindGroups + 1; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Error, IsNull(), NonEmptySizedString())) | |
| .Times(1); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| // Test worse than the default | |
| limits.maxBindGroups = 3u; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([&](wgpu::Device device) { | |
| wgpu::Limits limits; | |
| device.GetLimits(&limits); | |
| // Check we got the default. | |
| EXPECT_EQ(limits.maxBindGroups, 4u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| // Test that requesting a device where a required limit is below the minimum value. | |
| TEST_F(RequestDeviceValidationTest, LowerIsBetter) { | |
| wgpu::Limits limits = {}; | |
| wgpu::DeviceDescriptor descriptor; | |
| descriptor.requiredLimits = &limits; | |
| wgpu::Limits supportedLimits; | |
| EXPECT_EQ(adapter.GetLimits(&supportedLimits), wgpu::Status::Success); | |
| // Test below the min. | |
| limits.minUniformBufferOffsetAlignment = supportedLimits.minUniformBufferOffsetAlignment / 2; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Error, IsNull(), NonEmptySizedString())) | |
| .Times(1); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| // Test the min. | |
| limits.minUniformBufferOffsetAlignment = supportedLimits.minUniformBufferOffsetAlignment; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([&](wgpu::Device device) { | |
| wgpu::Limits limits; | |
| device.GetLimits(&limits); | |
| // Check we got exactly the request. | |
| EXPECT_EQ(limits.minUniformBufferOffsetAlignment, | |
| supportedLimits.minUniformBufferOffsetAlignment); | |
| // Check another default limit. | |
| EXPECT_EQ(limits.maxTextureArrayLayers, 256u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| // IF we can support better than the default, test above the min. | |
| if (supportedLimits.minUniformBufferOffsetAlignment > 256u) { | |
| limits.minUniformBufferOffsetAlignment = | |
| supportedLimits.minUniformBufferOffsetAlignment * 2; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([&](wgpu::Device device) { | |
| wgpu::Limits limits; | |
| device.GetLimits(&limits); | |
| // Check we got exactly the request. | |
| EXPECT_EQ(limits.minUniformBufferOffsetAlignment, | |
| supportedLimits.minUniformBufferOffsetAlignment * 2); | |
| // Check another default limit. | |
| EXPECT_EQ(limits.maxTextureArrayLayers, 256u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| // Test worse than the default | |
| limits.minUniformBufferOffsetAlignment = 2u * 256u; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([&](wgpu::Device device) { | |
| wgpu::Limits limits; | |
| device.GetLimits(&limits); | |
| // Check we got the default. | |
| EXPECT_EQ(limits.minUniformBufferOffsetAlignment, 256u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| // Test that if an error occurs when requesting a device, the device lost callback is called | |
| // appropriately. | |
| TEST_F(RequestDeviceValidationTest, ErrorTriggersDeviceLost) { | |
| // Invalid descriptor chains: | |
| // - ChainedStruct: This should cause an early validation error. | |
| // - DawnFakeDeviceInitializeErrorForTesting: This should cause an internal device error. | |
| wgpu::ChainedStruct chain1; | |
| wgpu::DawnFakeDeviceInitializeErrorForTesting chain2; | |
| std::array<wgpu::ChainedStruct*, 2> chains = {&chain1, &chain2}; | |
| for (const auto* chain : chains) { | |
| SCOPED_TRACE(absl::StrFormat("Chain SType: %s", chain->sType)); | |
| { | |
| wgpu::DeviceDescriptor descriptor; | |
| descriptor.nextInChain = chain; | |
| // Device lost callback mode: AllowSpontaneous. | |
| MockDeviceLostCallback lostCb; | |
| descriptor.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous, | |
| lostCb.Callback()); | |
| // When in spontaneous mode, the request device callback should fire immediately before | |
| // the device lost callback. | |
| InSequence s; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Error, IsNull(), NonEmptySizedString())) | |
| .Times(1); | |
| EXPECT_CALL(lostCb, Call(_, wgpu::DeviceLostReason::FailedCreation, _)).Times(1); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| { | |
| wgpu::DeviceDescriptor descriptor; | |
| descriptor.nextInChain = chain; | |
| // Device lost callback mode: AllowProcessEvents. | |
| MockDeviceLostCallback lostCb; | |
| descriptor.SetDeviceLostCallback(wgpu::CallbackMode::AllowProcessEvents, | |
| lostCb.Callback()); | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Error, IsNull(), NonEmptySizedString())) | |
| .Times(1); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| // When in a non-spontaneous mode for the device lost, the request device callback | |
| // should fire, but the device lost callback should only fire when the Instance level | |
| // API is called. | |
| EXPECT_CALL(lostCb, Call(_, wgpu::DeviceLostReason::FailedCreation, _)).Times(1); | |
| instance.ProcessEvents(); | |
| } | |
| } | |
| } | |
| // Test that RG11B10UfloatRenderable is implicitly enabled when TextureFormatsTier1 is active. | |
| TEST_F(RequestDeviceValidationTest, TextureFormatsTier1ImpliesRG11B10UfloatRenderable) { | |
| wgpu::DeviceDescriptor descriptor = {}; | |
| std::vector<wgpu::FeatureName> features = {wgpu::FeatureName::TextureFormatsTier1}; | |
| descriptor.requiredFeatures = features.data(); | |
| descriptor.requiredFeatureCount = features.size(); | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([](wgpu::Device device) { | |
| EXPECT_TRUE(device.HasFeature(wgpu::FeatureName::RG11B10UfloatRenderable)); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| // Test that TextureFormatsTier1 is implicitly enabled when TextureFormatsTier2 is active. | |
| TEST_F(RequestDeviceValidationTest, TextureFormatsTier2ImpliesTextureFormatsTier1) { | |
| wgpu::DeviceDescriptor descriptor = {}; | |
| std::vector<wgpu::FeatureName> features = {wgpu::FeatureName::TextureFormatsTier2}; | |
| descriptor.requiredFeatures = features.data(); | |
| descriptor.requiredFeatureCount = features.size(); | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([](wgpu::Device device) { | |
| EXPECT_TRUE(device.HasFeature(wgpu::FeatureName::TextureFormatsTier1)); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| class DeviceTickValidationTest : public ValidationTest {}; | |
| // Device destroy before API-level Tick should always result in no-op and false. | |
| TEST_F(DeviceTickValidationTest, DestroyDeviceBeforeAPITick) { | |
| ExpectDeviceDestruction(); | |
| device.Destroy(); | |
| device.Tick(); | |
| } | |
| class DeviceGetAHardwareBufferPropertiesValidationTest : public ValidationTest { | |
| void SetUp() override { | |
| ValidationTest::SetUp(); | |
| DAWN_SKIP_TEST_IF(UsesWire()); | |
| } | |
| }; | |
| // Test that calling GetAHardwareBufferProperties will generate an error | |
| // if the required feature is not present. | |
| TEST_F(DeviceGetAHardwareBufferPropertiesValidationTest, | |
| GetAHardwareBufferPropertiesRequiresAHBFeature) { | |
| // The parameter values shouldn't matter, as the call should fail validation | |
| // before calling into the implementation (verified by checking the error | |
| // message). | |
| void* handle = nullptr; | |
| wgpu::AHardwareBufferProperties* properties = nullptr; | |
| ASSERT_DEVICE_ERROR( | |
| device.GetAHardwareBufferProperties(handle, properties), | |
| testing::HasSubstr( | |
| "without the FeatureName::SharedTextureMemoryAHardwareBuffer feature being set")); | |
| } | |
| class RequestDeviceCoreValidationTest : public RequestDeviceValidationTest { | |
| // Create a core-defaulting adapter | |
| bool UseCompatibilityMode() const override { return false; } | |
| }; | |
| // Test that requiring wgpu::FeatureName::CoreFeaturesAndLimits explicitly when calling | |
| // RequestingDevice on a core-defaulting adapter gives a device with core limits. | |
| TEST_F(RequestDeviceCoreValidationTest, Explicit) { | |
| wgpu::DeviceDescriptor descriptor = {}; | |
| std::vector<wgpu::FeatureName> features = {wgpu::FeatureName::CoreFeaturesAndLimits}; | |
| descriptor.requiredFeatures = features.data(); | |
| descriptor.requiredFeatureCount = features.size(); | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([](wgpu::Device device) { | |
| EXPECT_TRUE(device.HasFeature(wgpu::FeatureName::CoreFeaturesAndLimits)); | |
| // Check one of limits to be greater than compat tier. | |
| dawn::utils::ComboLimits limits; | |
| device.GetLimits(limits.GetLinked()); | |
| EXPECT_GT(limits.maxStorageBuffersInVertexStage, 0u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| // Test that calling RequestingDevice on a core-defaulting adapter gives a device with core | |
| // limits on default. | |
| TEST_F(RequestDeviceCoreValidationTest, Implicit) { | |
| wgpu::DeviceDescriptor descriptor = {}; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([](wgpu::Device device) { | |
| EXPECT_TRUE(device.HasFeature(wgpu::FeatureName::CoreFeaturesAndLimits)); | |
| // Check one of limits to be greater than compat tier. | |
| dawn::utils::ComboLimits limits; | |
| device.GetLimits(limits.GetLinked()); | |
| EXPECT_GT(limits.maxStorageBuffersInVertexStage, 0u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| class RequestDeviceCompatValidationTest : public RequestDeviceValidationTest { | |
| // Create a compat-defaulting adapter | |
| bool UseCompatibilityMode() const override { return true; } | |
| }; | |
| // Test that requiring wgpu::FeatureName::CoreFeaturesAndLimits when calling RequestingDevice on a | |
| // compat-defaulting adapter gives a device with core limits. | |
| TEST_F(RequestDeviceCompatValidationTest, CreateCore) { | |
| wgpu::DeviceDescriptor descriptor = {}; | |
| std::vector<wgpu::FeatureName> features = {wgpu::FeatureName::CoreFeaturesAndLimits}; | |
| descriptor.requiredFeatures = features.data(); | |
| descriptor.requiredFeatureCount = features.size(); | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([](wgpu::Device device) { | |
| EXPECT_TRUE(device.HasFeature(wgpu::FeatureName::CoreFeaturesAndLimits)); | |
| // Check one of limits to be greater than compat tier. | |
| dawn::utils::ComboLimits limits; | |
| device.GetLimits(limits.GetLinked()); | |
| EXPECT_GT(limits.maxStorageBuffersInVertexStage, 0u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| // Test that calling RequestingDevice on a compat-defaulting adapter gives a device with compat | |
| // limits on default. | |
| TEST_F(RequestDeviceCompatValidationTest, CreateCompat) { | |
| wgpu::DeviceDescriptor descriptor = {}; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([](wgpu::Device device) { | |
| EXPECT_FALSE(device.HasFeature(wgpu::FeatureName::CoreFeaturesAndLimits)); | |
| // Check one of limits to be compat tier. | |
| dawn::utils::ComboLimits limits; | |
| device.GetLimits(limits.GetLinked()); | |
| EXPECT_EQ(limits.maxStorageBuffersInVertexStage, 0u); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| class RequestDeviceWithImmediateDataValidationTest : public ValidationTest { | |
| protected: | |
| void SetUp() override { | |
| ValidationTest::SetUp(); | |
| DAWN_SKIP_TEST_IF(UsesWire()); | |
| } | |
| MockCppCallback<void (*)(wgpu::RequestDeviceStatus, wgpu::Device, wgpu::StringView)> | |
| mRequestDeviceCallback; | |
| }; | |
| // Test that requesting a device where a required immediate data range byte size limit is below | |
| // the max always returns one with the max. | |
| TEST_F(RequestDeviceWithImmediateDataValidationTest, AlwaysMax) { | |
| wgpu::Limits limits = {}; | |
| wgpu::DeviceDescriptor descriptor; | |
| descriptor.requiredLimits = &limits; | |
| wgpu::Limits supportedLimits; | |
| EXPECT_EQ(adapter.GetLimits(&supportedLimits), wgpu::Status::Success); | |
| uint32_t supportedImmediateDataLimit = supportedLimits.maxImmediateSize; | |
| // DeviceNull has a maxImmediateSize of 64, larger than 16. | |
| constexpr uint32_t smallerImmediateDataLimit = 16; | |
| EXPECT_GT(supportedImmediateDataLimit, smallerImmediateDataLimit); | |
| // Test below the max. | |
| limits.maxImmediateSize = smallerImmediateDataLimit; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([&](wgpu::Device device) { | |
| wgpu::Limits deviceLimits; | |
| device.GetLimits(&deviceLimits); | |
| // Check we got the max. | |
| EXPECT_EQ(deviceLimits.maxImmediateSize, supportedImmediateDataLimit); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| // Test the max. | |
| limits.maxImmediateSize = supportedImmediateDataLimit; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([&](wgpu::Device device) { | |
| wgpu::Limits deviceLimits; | |
| device.GetLimits(&deviceLimits); | |
| // Check we got the max. | |
| EXPECT_EQ(deviceLimits.maxImmediateSize, supportedImmediateDataLimit); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| // Test above the max. | |
| limits.maxImmediateSize = supportedImmediateDataLimit + 4; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Error, IsNull(), NonEmptySizedString())) | |
| .Times(1); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| // Test even smaller | |
| limits.maxImmediateSize = smallerImmediateDataLimit / 2; | |
| EXPECT_CALL(mRequestDeviceCallback, | |
| Call(wgpu::RequestDeviceStatus::Success, NotNull(), EmptySizedString())) | |
| .WillOnce(WithArgs<1>([&](wgpu::Device device) { | |
| wgpu::Limits deviceLimits; | |
| device.GetLimits(&deviceLimits); | |
| // Check we got the max. | |
| EXPECT_EQ(deviceLimits.maxImmediateSize, supportedImmediateDataLimit); | |
| })); | |
| adapter.RequestDevice(&descriptor, wgpu::CallbackMode::AllowSpontaneous, | |
| mRequestDeviceCallback.Callback()); | |
| } | |
| } // anonymous namespace | |
| } // namespace dawn |