From 5a0f8d32a21f2aa4fd8330cbbef753e01c0673ef Mon Sep 17 00:00:00 2001 From: Jiawei Shao Date: Fri, 23 Sep 2022 00:29:46 +0000 Subject: [PATCH] Support optional query on adapter power preference This patch adds DawnAdapterPropertiesPowerPreferenceDescriptor for querying adapter power preference which is useful to distinguish different logical adapters created on same physical device but with different power preferences. Bug: dawn:1516 Test: dawn_unittests Change-Id: I12ed6e370f8b57c860520154565765f0ee894831 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/102780 Reviewed-by: Austin Eng Commit-Queue: Jiawei Shao Kokoro: Kokoro Reviewed-by: Corentin Wallez --- dawn.json | 12 +- .../templates/dawn/native/ChainUtils.cpp | 32 +- generator/templates/dawn/native/ChainUtils.h | 37 +- src/dawn/native/Adapter.cpp | 13 + src/dawn/tests/unittests/ChainUtilsTests.cpp | 318 ++++++++++++------ 5 files changed, 314 insertions(+), 98 deletions(-) diff --git a/dawn.json b/dawn.json index d8f8a34436..dfe2afe847 100644 --- a/dawn.json +++ b/dawn.json @@ -2526,7 +2526,8 @@ {"value": 1002, "name": "dawn toggles device descriptor", "tags": ["dawn", "native"]}, {"value": 1003, "name": "dawn encoder internal usage descriptor", "tags": ["dawn"]}, {"value": 1004, "name": "dawn instance descriptor", "tags": ["dawn", "native"]}, - {"value": 1005, "name": "dawn cache device descriptor", "tags": ["dawn", "native"]} + {"value": 1005, "name": "dawn cache device descriptor", "tags": ["dawn", "native"]}, + {"value": 1006, "name": "dawn adapter properties power preference", "tags": ["dawn", "native"]} ] }, "texture": { @@ -2929,5 +2930,14 @@ "members": [ {"name": "use internal usages", "type": "bool", "default": "false"} ] + }, + "dawn adapter properties power preference": { + "category": "structure", + "chained": "out", + "chain roots": ["adapter properties"], + "tags": ["dawn"], + "members": [ + {"name": "power preference", "type": "power preference", "default": "undefined"} + ] } } diff --git a/generator/templates/dawn/native/ChainUtils.cpp b/generator/templates/dawn/native/ChainUtils.cpp index 71f932e0ea..95f5e43409 100644 --- a/generator/templates/dawn/native/ChainUtils.cpp +++ b/generator/templates/dawn/native/ChainUtils.cpp @@ -25,10 +25,12 @@ namespace {{native_namespace}} { {% set namespace = metadata.namespace %} {% for value in types["s type"].values %} {% if value.valid %} - void FindInChain(const ChainedStruct* chain, const {{as_cppEnum(value.name)}}** out) { + {% set const_qualifier = "const " if types[value.name.get()].chained == "in" else "" %} + {% set chained_struct_type = "ChainedStruct" if types[value.name.get()].chained == "in" else "ChainedStructOut" %} + void FindInChain({{const_qualifier}}{{chained_struct_type}}* chain, {{const_qualifier}}{{as_cppEnum(value.name)}}** out) { for (; chain; chain = chain->nextInChain) { if (chain->sType == {{namespace}}::SType::{{as_cppEnum(value.name)}}) { - *out = static_cast(chain); + *out = static_cast<{{const_qualifier}}{{as_cppEnum(value.name)}}*>(chain); break; } } @@ -62,4 +64,30 @@ MaybeError ValidateSTypes(const ChainedStruct* chain, return {}; } +MaybeError ValidateSTypes(const ChainedStructOut* chain, + std::vector> oneOfConstraints) { + std::unordered_set<{{namespace}}::SType> allSTypes; + for (; chain; chain = chain->nextInChain) { + DAWN_INVALID_IF(allSTypes.find(chain->sType) != allSTypes.end(), + "Extension chain has duplicate sType %s.", chain->sType); + allSTypes.insert(chain->sType); + } + + for (const auto& oneOfConstraint : oneOfConstraints) { + bool satisfied = false; + for ({{namespace}}::SType oneOfSType : oneOfConstraint) { + if (allSTypes.find(oneOfSType) != allSTypes.end()) { + DAWN_INVALID_IF(satisfied, + "sType %s is part of a group of exclusive sTypes that is already present.", + oneOfSType); + satisfied = true; + allSTypes.erase(oneOfSType); + } + } + } + + DAWN_INVALID_IF(!allSTypes.empty(), "Unsupported sType %s.", *allSTypes.begin()); + return {}; +} + } // namespace {{native_namespace}} diff --git a/generator/templates/dawn/native/ChainUtils.h b/generator/templates/dawn/native/ChainUtils.h index 3377220d44..3b5a926a7a 100644 --- a/generator/templates/dawn/native/ChainUtils.h +++ b/generator/templates/dawn/native/ChainUtils.h @@ -28,7 +28,9 @@ namespace {{native_namespace}} { {% for value in types["s type"].values %} {% if value.valid %} - void FindInChain(const ChainedStruct* chain, const {{as_cppEnum(value.name)}}** out); + {% set const_qualifier = "const " if types[value.name.get()].chained == "in" else "" %} + {% set chained_struct_type = "ChainedStruct" if types[value.name.get()].chained == "in" else "ChainedStructOut" %} + void FindInChain({{const_qualifier}}{{chained_struct_type}}* chain, {{const_qualifier}}{{as_cppEnum(value.name)}}** out); {% endif %} {% endfor %} @@ -41,6 +43,8 @@ namespace {{native_namespace}} { {% set namespace = metadata.namespace %} MaybeError ValidateSTypes(const ChainedStruct* chain, std::vector> oneOfConstraints); + MaybeError ValidateSTypes(const ChainedStructOut* chain, + std::vector> oneOfConstraints); template MaybeError ValidateSingleSTypeInner(const ChainedStruct* chain, T sType) { @@ -48,6 +52,12 @@ namespace {{native_namespace}} { "Unsupported sType (%s). Expected (%s)", chain->sType, sType); return {}; } + template + MaybeError ValidateSingleSTypeInner(const ChainedStructOut* chain, T sType) { + DAWN_INVALID_IF(chain->sType != sType, + "Unsupported sType (%s). Expected (%s)", chain->sType, sType); + return {}; + } template MaybeError ValidateSingleSTypeInner(const ChainedStruct* chain, T sType, Args... sTypes) { @@ -56,6 +66,13 @@ namespace {{native_namespace}} { } return ValidateSingleSTypeInner(chain, sTypes...); } + template + MaybeError ValidateSingleSTypeInner(const ChainedStructOut* chain, T sType, Args... sTypes) { + if (chain->sType == sType) { + return {}; + } + return ValidateSingleSTypeInner(chain, sTypes...); + } // Verifies that |chain| contains a single ChainedStruct of type |sType| or no ChainedStructs // at all. @@ -68,6 +85,15 @@ namespace {{native_namespace}} { "Chain can only contain a single chained struct."); return ValidateSingleSTypeInner(chain, sType); } + template + MaybeError ValidateSingleSType(const ChainedStructOut* chain, T sType) { + if (chain == nullptr) { + return {}; + } + DAWN_INVALID_IF(chain->nextInChain != nullptr, + "Chain can only contain a single chained struct."); + return ValidateSingleSTypeInner(chain, sType); + } // Verifies that |chain| contains a single ChainedStruct with a type enumerated in the // parameter pack or no ChainedStructs at all. @@ -80,6 +106,15 @@ namespace {{native_namespace}} { "Chain can only contain a single chained struct."); return ValidateSingleSTypeInner(chain, sType, sTypes...); } + template + MaybeError ValidateSingleSType(const ChainedStructOut* chain, T sType, Args... sTypes) { + if (chain == nullptr) { + return {}; + } + DAWN_INVALID_IF(chain->nextInChain != nullptr, + "Chain can only contain a single chained struct."); + return ValidateSingleSTypeInner(chain, sType, sTypes...); + } } // namespace {{native_namespace}} diff --git a/src/dawn/native/Adapter.cpp b/src/dawn/native/Adapter.cpp index 0234e2c094..c3063866d8 100644 --- a/src/dawn/native/Adapter.cpp +++ b/src/dawn/native/Adapter.cpp @@ -86,6 +86,19 @@ bool AdapterBase::APIGetLimits(SupportedLimits* limits) const { } void AdapterBase::APIGetProperties(AdapterProperties* properties) const { + MaybeError result = ValidateSingleSType(properties->nextInChain, + wgpu::SType::DawnAdapterPropertiesPowerPreference); + if (result.IsError()) { + mInstance->ConsumedError(result.AcquireError()); + return; + } + + DawnAdapterPropertiesPowerPreference* powerPreferenceDesc = nullptr; + FindInChain(properties->nextInChain, &powerPreferenceDesc); + if (powerPreferenceDesc != nullptr) { + powerPreferenceDesc->powerPreference = wgpu::PowerPreference::Undefined; + } + properties->vendorID = mVendorId; properties->vendorName = mVendorName.c_str(); properties->architecture = mArchitectureName.c_str(); diff --git a/src/dawn/tests/unittests/ChainUtilsTests.cpp b/src/dawn/tests/unittests/ChainUtilsTests.cpp index c1bea5b9d6..45055f18bc 100644 --- a/src/dawn/tests/unittests/ChainUtilsTests.cpp +++ b/src/dawn/tests/unittests/ChainUtilsTests.cpp @@ -19,65 +19,122 @@ // Checks that we cannot find any structs in an empty chain TEST(ChainUtilsTests, FindEmptyChain) { - const dawn::native::PrimitiveDepthClipControl* info = nullptr; - dawn::native::FindInChain(nullptr, &info); + { + const dawn::native::PrimitiveDepthClipControl* info = nullptr; + const dawn::native::ChainedStruct* chained = nullptr; + dawn::native::FindInChain(chained, &info); - ASSERT_EQ(nullptr, info); + ASSERT_EQ(nullptr, info); + } + + { + dawn::native::DawnAdapterPropertiesPowerPreference* info = nullptr; + dawn::native::ChainedStructOut* chained = nullptr; + dawn::native::FindInChain(chained, &info); + + ASSERT_EQ(nullptr, info); + } } // Checks that searching a chain for a present struct returns that struct TEST(ChainUtilsTests, FindPresentInChain) { - dawn::native::PrimitiveDepthClipControl chain1; - dawn::native::ShaderModuleSPIRVDescriptor chain2; - chain1.nextInChain = &chain2; - const dawn::native::PrimitiveDepthClipControl* info1 = nullptr; - const dawn::native::ShaderModuleSPIRVDescriptor* info2 = nullptr; - dawn::native::FindInChain(&chain1, &info1); - dawn::native::FindInChain(&chain1, &info2); + { + dawn::native::PrimitiveDepthClipControl chain1; + dawn::native::ShaderModuleSPIRVDescriptor chain2; + chain1.nextInChain = &chain2; + const dawn::native::PrimitiveDepthClipControl* info1 = nullptr; + const dawn::native::ShaderModuleSPIRVDescriptor* info2 = nullptr; + dawn::native::FindInChain(&chain1, &info1); + dawn::native::FindInChain(&chain1, &info2); - ASSERT_NE(nullptr, info1); - ASSERT_NE(nullptr, info2); + ASSERT_NE(nullptr, info1); + ASSERT_NE(nullptr, info2); + } + + { + dawn::native::DawnAdapterPropertiesPowerPreference chain; + dawn::native::DawnAdapterPropertiesPowerPreference* output = nullptr; + dawn::native::FindInChain(&chain, &output); + + ASSERT_NE(nullptr, output); + } } // Checks that searching a chain for a struct that doesn't exist returns a nullptr TEST(ChainUtilsTests, FindMissingInChain) { - dawn::native::PrimitiveDepthClipControl chain1; - dawn::native::ShaderModuleSPIRVDescriptor chain2; - chain1.nextInChain = &chain2; - const dawn::native::SurfaceDescriptorFromMetalLayer* info = nullptr; - dawn::native::FindInChain(&chain1, &info); + { + dawn::native::PrimitiveDepthClipControl chain1; + dawn::native::ShaderModuleSPIRVDescriptor chain2; + chain1.nextInChain = &chain2; + const dawn::native::SurfaceDescriptorFromMetalLayer* info = nullptr; + dawn::native::FindInChain(&chain1, &info); - ASSERT_EQ(nullptr, info); + ASSERT_EQ(nullptr, info); + } + + { + dawn::native::AdapterProperties adapterProperties; + dawn::native::DawnAdapterPropertiesPowerPreference* output = nullptr; + dawn::native::FindInChain(adapterProperties.nextInChain, &output); + + ASSERT_EQ(nullptr, output); + } } // Checks that validation rejects chains with duplicate STypes TEST(ChainUtilsTests, ValidateDuplicateSTypes) { - dawn::native::PrimitiveDepthClipControl chain1; - dawn::native::ShaderModuleSPIRVDescriptor chain2; - dawn::native::PrimitiveDepthClipControl chain3; - chain1.nextInChain = &chain2; - chain2.nextInChain = &chain3; + { + dawn::native::PrimitiveDepthClipControl chain1; + dawn::native::ShaderModuleSPIRVDescriptor chain2; + dawn::native::PrimitiveDepthClipControl chain3; + chain1.nextInChain = &chain2; + chain2.nextInChain = &chain3; - dawn::native::MaybeError result = dawn::native::ValidateSTypes(&chain1, {}); - ASSERT_TRUE(result.IsError()); - result.AcquireError(); + dawn::native::MaybeError result = dawn::native::ValidateSTypes(&chain1, {}); + ASSERT_TRUE(result.IsError()); + result.AcquireError(); + } + + { + dawn::native::DawnAdapterPropertiesPowerPreference chain1; + dawn::native::DawnAdapterPropertiesPowerPreference chain2; + chain1.nextInChain = &chain2; + + dawn::native::MaybeError result = dawn::native::ValidateSTypes(&chain1, {}); + ASSERT_TRUE(result.IsError()); + result.AcquireError(); + } } // Checks that validation rejects chains that contain unspecified STypes TEST(ChainUtilsTests, ValidateUnspecifiedSTypes) { - dawn::native::PrimitiveDepthClipControl chain1; - dawn::native::ShaderModuleSPIRVDescriptor chain2; - dawn::native::ShaderModuleWGSLDescriptor chain3; - chain1.nextInChain = &chain2; - chain2.nextInChain = &chain3; + { + dawn::native::PrimitiveDepthClipControl chain1; + dawn::native::ShaderModuleSPIRVDescriptor chain2; + dawn::native::ShaderModuleWGSLDescriptor chain3; + chain1.nextInChain = &chain2; + chain2.nextInChain = &chain3; - dawn::native::MaybeError result = - dawn::native::ValidateSTypes(&chain1, { - {wgpu::SType::PrimitiveDepthClipControl}, - {wgpu::SType::ShaderModuleSPIRVDescriptor}, - }); - ASSERT_TRUE(result.IsError()); - result.AcquireError(); + dawn::native::MaybeError result = + dawn::native::ValidateSTypes(&chain1, { + {wgpu::SType::PrimitiveDepthClipControl}, + {wgpu::SType::ShaderModuleSPIRVDescriptor}, + }); + ASSERT_TRUE(result.IsError()); + result.AcquireError(); + } + + { + dawn::native::DawnAdapterPropertiesPowerPreference chain1; + dawn::native::ChainedStructOut chain2; + chain2.sType = wgpu::SType::RenderPassDescriptorMaxDrawCount; + chain1.nextInChain = &chain2; + + dawn::native::MaybeError result = dawn::native::ValidateSTypes( + &chain1, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}}); + ASSERT_TRUE(result.IsError()); + result.AcquireError(); + } } // Checks that validation rejects chains that contain multiple STypes from the same oneof @@ -98,89 +155,162 @@ TEST(ChainUtilsTests, ValidateOneOfFailure) { // Checks that validation accepts chains that match the constraints. TEST(ChainUtilsTests, ValidateSuccess) { - dawn::native::PrimitiveDepthClipControl chain1; - dawn::native::ShaderModuleSPIRVDescriptor chain2; - chain1.nextInChain = &chain2; + { + dawn::native::PrimitiveDepthClipControl chain1; + dawn::native::ShaderModuleSPIRVDescriptor chain2; + chain1.nextInChain = &chain2; - dawn::native::MaybeError result = dawn::native::ValidateSTypes( - &chain1, - { - {wgpu::SType::ShaderModuleSPIRVDescriptor, wgpu::SType::ShaderModuleWGSLDescriptor}, - {wgpu::SType::PrimitiveDepthClipControl}, - {wgpu::SType::SurfaceDescriptorFromMetalLayer}, - }); - ASSERT_TRUE(result.IsSuccess()); + dawn::native::MaybeError result = dawn::native::ValidateSTypes( + &chain1, + { + {wgpu::SType::ShaderModuleSPIRVDescriptor, wgpu::SType::ShaderModuleWGSLDescriptor}, + {wgpu::SType::PrimitiveDepthClipControl}, + {wgpu::SType::SurfaceDescriptorFromMetalLayer}, + }); + ASSERT_TRUE(result.IsSuccess()); + } + + { + dawn::native::DawnAdapterPropertiesPowerPreference chain1; + dawn::native::MaybeError result = dawn::native::ValidateSTypes( + &chain1, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}}); + ASSERT_TRUE(result.IsSuccess()); + } } // Checks that validation always passes on empty chains. TEST(ChainUtilsTests, ValidateEmptyChain) { - dawn::native::MaybeError result = - dawn::native::ValidateSTypes(nullptr, { - {wgpu::SType::ShaderModuleSPIRVDescriptor}, - {wgpu::SType::PrimitiveDepthClipControl}, - }); - ASSERT_TRUE(result.IsSuccess()); + { + const dawn::native::ChainedStruct* chain = nullptr; + dawn::native::MaybeError result = + dawn::native::ValidateSTypes(chain, { + {wgpu::SType::ShaderModuleSPIRVDescriptor}, + {wgpu::SType::PrimitiveDepthClipControl}, + }); + ASSERT_TRUE(result.IsSuccess()); - result = dawn::native::ValidateSTypes(nullptr, {}); - ASSERT_TRUE(result.IsSuccess()); + result = dawn::native::ValidateSTypes(chain, {}); + ASSERT_TRUE(result.IsSuccess()); + } + + { + dawn::native::ChainedStructOut* chain = nullptr; + dawn::native::MaybeError result = dawn::native::ValidateSTypes( + chain, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}}); + ASSERT_TRUE(result.IsSuccess()); + + result = dawn::native::ValidateSTypes(chain, {}); + ASSERT_TRUE(result.IsSuccess()); + } } // Checks that singleton validation always passes on empty chains. TEST(ChainUtilsTests, ValidateSingleEmptyChain) { - dawn::native::MaybeError result = - dawn::native::ValidateSingleSType(nullptr, wgpu::SType::ShaderModuleSPIRVDescriptor); - ASSERT_TRUE(result.IsSuccess()); + { + const dawn::native::ChainedStruct* chain = nullptr; + dawn::native::MaybeError result = + dawn::native::ValidateSingleSType(chain, wgpu::SType::ShaderModuleSPIRVDescriptor); + ASSERT_TRUE(result.IsSuccess()); - result = dawn::native::ValidateSingleSType(nullptr, wgpu::SType::ShaderModuleSPIRVDescriptor, - wgpu::SType::PrimitiveDepthClipControl); - ASSERT_TRUE(result.IsSuccess()); + result = dawn::native::ValidateSingleSType(chain, wgpu::SType::ShaderModuleSPIRVDescriptor, + wgpu::SType::PrimitiveDepthClipControl); + ASSERT_TRUE(result.IsSuccess()); + } + + { + dawn::native::ChainedStructOut* chain = nullptr; + dawn::native::MaybeError result = dawn::native::ValidateSingleSType( + chain, wgpu::SType::DawnAdapterPropertiesPowerPreference); + ASSERT_TRUE(result.IsSuccess()); + + result = dawn::native::ValidateSingleSType( + chain, wgpu::SType::DawnAdapterPropertiesPowerPreference, + wgpu::SType::PrimitiveDepthClipControl); + ASSERT_TRUE(result.IsSuccess()); + } } // Checks that singleton validation always fails on chains with multiple children. TEST(ChainUtilsTests, ValidateSingleMultiChain) { - dawn::native::PrimitiveDepthClipControl chain1; - dawn::native::ShaderModuleSPIRVDescriptor chain2; - chain1.nextInChain = &chain2; + { + dawn::native::PrimitiveDepthClipControl chain1; + dawn::native::ShaderModuleSPIRVDescriptor chain2; + chain1.nextInChain = &chain2; - dawn::native::MaybeError result = - dawn::native::ValidateSingleSType(&chain1, wgpu::SType::PrimitiveDepthClipControl); - ASSERT_TRUE(result.IsError()); - result.AcquireError(); + dawn::native::MaybeError result = + dawn::native::ValidateSingleSType(&chain1, wgpu::SType::PrimitiveDepthClipControl); + ASSERT_TRUE(result.IsError()); + result.AcquireError(); - result = dawn::native::ValidateSingleSType(&chain1, wgpu::SType::PrimitiveDepthClipControl, - wgpu::SType::ShaderModuleSPIRVDescriptor); - ASSERT_TRUE(result.IsError()); - result.AcquireError(); + result = dawn::native::ValidateSingleSType(&chain1, wgpu::SType::PrimitiveDepthClipControl, + wgpu::SType::ShaderModuleSPIRVDescriptor); + ASSERT_TRUE(result.IsError()); + result.AcquireError(); + } + + { + dawn::native::DawnAdapterPropertiesPowerPreference chain1; + dawn::native::DawnAdapterPropertiesPowerPreference chain2; + chain1.nextInChain = &chain2; + + dawn::native::MaybeError result = dawn::native::ValidateSingleSType( + &chain1, wgpu::SType::DawnAdapterPropertiesPowerPreference); + ASSERT_TRUE(result.IsError()); + result.AcquireError(); + } } -// Checks that singleton validation passes when the oneof constraint is met. +// Checks that singleton validation passes when the one of constraint is met. TEST(ChainUtilsTests, ValidateSingleSatisfied) { - dawn::native::ShaderModuleWGSLDescriptor chain1; + { + dawn::native::ShaderModuleWGSLDescriptor chain1; - dawn::native::MaybeError result = - dawn::native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor); - ASSERT_TRUE(result.IsSuccess()); + dawn::native::MaybeError result = + dawn::native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor); + ASSERT_TRUE(result.IsSuccess()); - result = dawn::native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleSPIRVDescriptor, - wgpu::SType::ShaderModuleWGSLDescriptor); - ASSERT_TRUE(result.IsSuccess()); + result = + dawn::native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleSPIRVDescriptor, + wgpu::SType::ShaderModuleWGSLDescriptor); + ASSERT_TRUE(result.IsSuccess()); - result = dawn::native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor, - wgpu::SType::ShaderModuleSPIRVDescriptor); - ASSERT_TRUE(result.IsSuccess()); + result = dawn::native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor, + wgpu::SType::ShaderModuleSPIRVDescriptor); + ASSERT_TRUE(result.IsSuccess()); + } + + { + dawn::native::DawnAdapterPropertiesPowerPreference chain1; + dawn::native::MaybeError result = dawn::native::ValidateSingleSType( + &chain1, wgpu::SType::DawnAdapterPropertiesPowerPreference); + ASSERT_TRUE(result.IsSuccess()); + } } // Checks that singleton validation passes when the oneof constraint is not met. TEST(ChainUtilsTests, ValidateSingleUnsatisfied) { - dawn::native::PrimitiveDepthClipControl chain1; + { + dawn::native::PrimitiveDepthClipControl chain1; - dawn::native::MaybeError result = - dawn::native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor); - ASSERT_TRUE(result.IsError()); - result.AcquireError(); + dawn::native::MaybeError result = + dawn::native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor); + ASSERT_TRUE(result.IsError()); + result.AcquireError(); - result = dawn::native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleSPIRVDescriptor, - wgpu::SType::ShaderModuleWGSLDescriptor); - ASSERT_TRUE(result.IsError()); - result.AcquireError(); + result = + dawn::native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleSPIRVDescriptor, + wgpu::SType::ShaderModuleWGSLDescriptor); + ASSERT_TRUE(result.IsError()); + result.AcquireError(); + } + + { + dawn::native::ChainedStructOut chain1; + chain1.sType = wgpu::SType::ShaderModuleWGSLDescriptor; + + dawn::native::MaybeError result = dawn::native::ValidateSingleSType( + &chain1, wgpu::SType::DawnAdapterPropertiesPowerPreference); + ASSERT_TRUE(result.IsError()); + result.AcquireError(); + } }