Splits ChainUtils.h into a ChainUtilsImpl.h for further extensibility.
- For templating specialization to resolve in the correct order,
extensions need to be included before type aliasing.
Bug: dawn:1955
Change-Id: Ide745548ed4cd84fea67f276eb550e4638180403
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/147261
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
diff --git a/generator/templates/dawn/native/ChainUtils.cpp b/generator/templates/dawn/native/ChainUtils.cpp
index 1f2e6bf..8273a55 100644
--- a/generator/templates/dawn/native/ChainUtils.cpp
+++ b/generator/templates/dawn/native/ChainUtils.cpp
@@ -77,6 +77,36 @@
return {};
}
+// Returns true iff the chain's SType matches the extension, false otherwise. If the SType was
+// not already matched, sets the unpacked result accordingly. Otherwise, stores the duplicated
+// SType in 'duplicate'.
+template <typename Root, typename Unpacked, typename Ext>
+bool UnpackExtension(Unpacked& unpacked, const ChainedStruct* chain, bool& duplicate) {
+ ASSERT(chain != nullptr);
+ if (chain->sType == STypeFor<Ext>) {
+ auto& member = std::get<Ext>(unpacked);
+ if (member != nullptr) {
+ duplicate = true;
+ } else {
+ member = reinterpret_cast<Ext>(chain);
+ }
+ return true;
+ }
+ return false;
+}
+
+// Tries to match all possible extensions, returning true iff one of the allowed extensions were
+// matched, false otherwise. If the SType was not already matched, sets the unpacked result
+// accordingly. Otherwise, stores the diplicated SType in 'duplicate'.
+template <typename Root, typename Unpacked, typename AdditionalExts>
+struct AdditionalExtensionUnpacker;
+template <typename Root, typename Unpacked, typename... Exts>
+struct AdditionalExtensionUnpacker<Root, Unpacked, detail::AdditionalExtensionsList<Exts...>> {
+ static bool Unpack(Unpacked& unpacked, const ChainedStruct* chain, bool& duplicate) {
+ return ((UnpackExtension<Root, Unpacked, Exts>(unpacked, chain, duplicate)) || ...);
+ }
+};
+
//
// Unpacked chain helpers.
//
@@ -87,42 +117,42 @@
const ChainedStruct* next = chain->nextInChain;
{{unpackedChain}} result;
- //* Branching generation block to avoid warnings when the struct is not currently
- //* extendable:
- //* -Wunreachable-code-loop-increment:
- //* error: loop will run at most once (loop increment never executed)
- {% if len(type.extensions) == 0 %}
- if (next != nullptr) {
+ for (; next != nullptr; next = next->nextInChain) {
+ bool duplicate = false;
+ switch (next->sType) {
+ {% for extension in type.extensions %}
+ case STypeFor<{{as_cppType(extension.name)}}>: {
+ auto& member = std::get<const {{as_cppType(extension.name)}}*>(result);
+ if (member != nullptr) {
+ duplicate = true;
+ } else {
+ member = static_cast<const {{as_cppType(extension.name)}}*>(next);
+ }
+ break;
+ }
+ {% endfor %}
+ default: {
+ using Unpacker =
+ AdditionalExtensionUnpacker<
+ {{as_cppType(type.name)}},
+ {{unpackedChain}},
+ detail::AdditionalExtensions<{{as_cppType(type.name)}}>::List>;
+ if (!Unpacker::Unpack(result, next, duplicate)) {
+ return DAWN_VALIDATION_ERROR(
+ "Unexpected chained struct of type %s found on %s chain.",
+ next->sType, "{{as_cppType(type.name)}}"
+ );
+ }
+ break;
+ }
+ }
+ if (duplicate) {
return DAWN_VALIDATION_ERROR(
- "Unexpected chained struct of type %s found on %s chain.",
+ "Duplicate chained struct of type %s found on %s chain.",
next->sType, "{{as_cppType(type.name)}}"
);
}
- {% else %}
- for (; next != nullptr; next = next->nextInChain) {
- switch (next->sType) {
- {% for extension in type.extensions %}
- case STypeFor<{{as_cppType(extension.name)}}>: {
- auto& member = std::get<const {{as_cppType(extension.name)}}*>(result);
- if (member != nullptr) {
- return DAWN_VALIDATION_ERROR(
- "Duplicate chained struct of type %s found on %s chain.",
- next->sType, "{{as_cppType(type.name)}}"
- );
- } else {
- member = static_cast<const {{as_cppType(extension.name)}}*>(next);
- }
- break;
- }
- {% endfor %}
- default:
- return DAWN_VALIDATION_ERROR(
- "Unexpected chained struct of type %s found on %s chain.",
- next->sType, "{{as_cppType(type.name)}}"
- );
- }
- }
- {% endif %}
+ }
return result;
}
diff --git a/generator/templates/dawn/native/ChainUtils.h b/generator/templates/dawn/native/ChainUtils.h
index d4a479e..71295be 100644
--- a/generator/templates/dawn/native/ChainUtils.h
+++ b/generator/templates/dawn/native/ChainUtils.h
@@ -31,17 +31,51 @@
namespace {{native_namespace}} {
+namespace detail {
+
+ // SType for implementation details. Kept inside the detail namespace for extensibility.
template <typename T>
- inline {{namespace}}::SType STypeFor;
+ inline {{namespace}}::SType STypeForImpl;
// Specialize STypeFor to map from native struct types to their SType.
{% for value in types["s type"].values %}
{% if value.valid and value.name.get() in types %}
template <>
- constexpr inline {{namespace}}::SType STypeFor<{{as_cppEnum(value.name)}}> = {{namespace}}::SType::{{as_cppEnum(value.name)}};
+ constexpr inline {{namespace}}::SType STypeForImpl<{{as_cppEnum(value.name)}}> = {{namespace}}::SType::{{as_cppEnum(value.name)}};
{% endif %}
{% endfor %}
+ //
+ // Unpacked chain types structs and helpers.
+ // Note that unpacked types are tuples to enable further templating extensions based on
+ // typing via something like std::get<const Extension*> in templated functions.
+ //
+
+ // Typelist type used to further add extensions to chain roots when they are not in the json.
+ template <typename... Exts>
+ struct AdditionalExtensionsList;
+
+ // Root specializations for adding additional extensions.
+ template <typename Root>
+ struct AdditionalExtensions {
+ using List = AdditionalExtensionsList<>;
+ };
+
+ // Template structs to get the typing for the unpacked chains.
+ template <typename...>
+ struct UnpackedChain;
+ template <typename... Additionals, typename... Ts>
+ struct UnpackedChain<AdditionalExtensionsList<Additionals...>, Ts...> {
+ using Type = std::tuple<Ts..., Additionals...>;
+ };
+
+} // namespace detail
+
+ template <typename T>
+ constexpr inline wgpu::SType STypeFor = detail::STypeForImpl<T>;
+ template <typename T>
+ constexpr inline wgpu::SType STypeFor<const T*> = detail::STypeForImpl<T>;
+
template <typename T>
void FindInChain(const ChainedStruct* chain, const T** out) {
for (; chain; chain = chain->nextInChain) {
@@ -142,25 +176,27 @@
return ValidateSingleSTypeInner(chain, sType, sTypes...);
}
- //
- // Unpacked chain types structs and helpers.
- // Note that unpacked types are tuples to enable further templating extensions based on
- // typing via something like std::get<const Extension*> in templated functions.
- //
+} // namespace {{native_namespace}}
+
+// Include specializations before declaring types for ordering purposes.
+#include "{{native_dir}}/ChainUtilsImpl.h"
+
+namespace {{native_namespace}} {
+
{% for type in by_category["structure"] %}
{% if type.extensible == "in" %}
{% set unpackedChain = "Unpacked" + as_cppType(type.name) + "Chain" %}
- using {{unpackedChain}} = std::tuple<
+ using {{unpackedChain}} = detail::UnpackedChain<
+ detail::AdditionalExtensions<{{as_cppType(type.name)}}>::List{{ "," if len(type.extensions) != 0 else ""}}
{% for extension in type.extensions %}
const {{as_cppType(extension.name)}}*{{ "," if not loop.last else "" }}
{% endfor %}
- >;
+ >::Type;
ResultOrError<{{unpackedChain}}> ValidateAndUnpackChain(const {{as_cppType(type.name)}}* chain);
{% endif %}
{% endfor %}
-
} // namespace {{native_namespace}}
#endif // {{DIR}}_CHAIN_UTILS_H_
diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn
index c3ae875..0fdba1a 100644
--- a/src/dawn/native/BUILD.gn
+++ b/src/dawn/native/BUILD.gn
@@ -228,6 +228,7 @@
"CallbackTaskManager.cpp",
"CallbackTaskManager.h",
"ChainUtils.h",
+ "ChainUtilsImpl.h",
"CommandAllocator.cpp",
"CommandAllocator.h",
"CommandBuffer.cpp",
diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt
index 149f604..3be7880 100644
--- a/src/dawn/native/CMakeLists.txt
+++ b/src/dawn/native/CMakeLists.txt
@@ -77,6 +77,7 @@
"CallbackTaskManager.cpp"
"CallbackTaskManager.h"
"ChainUtils.h"
+ "ChainUtilsImpl.h"
"CommandAllocator.cpp"
"CommandAllocator.h"
"CommandBuffer.cpp"
diff --git a/src/dawn/native/ChainUtils.h b/src/dawn/native/ChainUtils.h
index fda6c72..78bd924 100644
--- a/src/dawn/native/ChainUtils.h
+++ b/src/dawn/native/ChainUtils.h
@@ -17,29 +17,4 @@
#include "dawn/native/ChainUtils_autogen.h"
-namespace dawn::native {
-
-struct DawnInstanceDescriptor;
-
-namespace d3d {
-struct RequestAdapterOptionsLUID;
-}
-
-namespace opengl {
-struct RequestAdapterOptionsGetGLProc;
-}
-
-template <>
-inline wgpu::SType STypeFor<DawnInstanceDescriptor> = wgpu::SType(WGPUSType_DawnInstanceDescriptor);
-
-template <>
-inline wgpu::SType STypeFor<d3d::RequestAdapterOptionsLUID> =
- wgpu::SType(WGPUSType_RequestAdapterOptionsLUID);
-
-template <>
-inline wgpu::SType STypeFor<opengl::RequestAdapterOptionsGetGLProc> =
- wgpu::SType(WGPUSType_RequestAdapterOptionsGetGLProc);
-
-} // namespace dawn::native
-
#endif // SRC_DAWN_NATIVE_CHAINUTILS_H_
diff --git a/src/dawn/native/ChainUtilsImpl.h b/src/dawn/native/ChainUtilsImpl.h
new file mode 100644
index 0000000..68d6b43
--- /dev/null
+++ b/src/dawn/native/ChainUtilsImpl.h
@@ -0,0 +1,58 @@
+// Copyright 2023 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NATIVE_CHAINUTILSIMPL_H_
+#define SRC_DAWN_NATIVE_CHAINUTILSIMPL_H_
+
+namespace dawn::native {
+
+struct DawnInstanceDescriptor;
+
+namespace d3d {
+struct RequestAdapterOptionsLUID;
+}
+
+namespace opengl {
+struct RequestAdapterOptionsGetGLProc;
+}
+
+namespace detail {
+
+template <>
+constexpr inline wgpu::SType STypeForImpl<DawnInstanceDescriptor> =
+ wgpu::SType(WGPUSType_DawnInstanceDescriptor);
+
+template <>
+struct AdditionalExtensions<InstanceDescriptor> {
+ using List = AdditionalExtensionsList<const DawnInstanceDescriptor*>;
+};
+
+template <>
+constexpr inline wgpu::SType STypeForImpl<d3d::RequestAdapterOptionsLUID> =
+ wgpu::SType(WGPUSType_RequestAdapterOptionsLUID);
+
+template <>
+constexpr inline wgpu::SType STypeForImpl<opengl::RequestAdapterOptionsGetGLProc> =
+ wgpu::SType(WGPUSType_RequestAdapterOptionsGetGLProc);
+
+template <>
+struct AdditionalExtensions<RequestAdapterOptions> {
+ using List = AdditionalExtensionsList<const d3d::RequestAdapterOptionsLUID*,
+ const opengl::RequestAdapterOptionsGetGLProc*>;
+};
+
+} // namespace detail
+} // namespace dawn::native
+
+#endif // SRC_DAWN_NATIVE_CHAINUTILSIMPL_H_
diff --git a/src/dawn/tests/unittests/ChainUtilsTests.cpp b/src/dawn/tests/unittests/ChainUtilsTests.cpp
index 3b73c6a..5a68092 100644
--- a/src/dawn/tests/unittests/ChainUtilsTests.cpp
+++ b/src/dawn/tests/unittests/ChainUtilsTests.cpp
@@ -12,28 +12,31 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "dawn/native/ChainUtils.h"
#include "dawn/native/dawn_platform.h"
-namespace dawn {
+namespace dawn::native {
namespace {
+using ::testing::HasSubstr;
+
// Checks that we cannot find any structs in an empty chain
TEST(ChainUtilsTests, FindEmptyChain) {
{
- const native::PrimitiveDepthClipControl* info = nullptr;
- const native::ChainedStruct* chained = nullptr;
- native::FindInChain(chained, &info);
+ const PrimitiveDepthClipControl* info = nullptr;
+ const ChainedStruct* chained = nullptr;
+ FindInChain(chained, &info);
ASSERT_EQ(nullptr, info);
}
{
- native::DawnAdapterPropertiesPowerPreference* info = nullptr;
- native::ChainedStructOut* chained = nullptr;
- native::FindInChain(chained, &info);
+ DawnAdapterPropertiesPowerPreference* info = nullptr;
+ ChainedStructOut* chained = nullptr;
+ FindInChain(chained, &info);
ASSERT_EQ(nullptr, info);
}
@@ -42,22 +45,22 @@
// Checks that searching a chain for a present struct returns that struct
TEST(ChainUtilsTests, FindPresentInChain) {
{
- native::PrimitiveDepthClipControl chain1;
- native::ShaderModuleSPIRVDescriptor chain2;
+ PrimitiveDepthClipControl chain1;
+ ShaderModuleSPIRVDescriptor chain2;
chain1.nextInChain = &chain2;
- const native::PrimitiveDepthClipControl* info1 = nullptr;
- const native::ShaderModuleSPIRVDescriptor* info2 = nullptr;
- native::FindInChain(&chain1, &info1);
- native::FindInChain(&chain1, &info2);
+ const PrimitiveDepthClipControl* info1 = nullptr;
+ const ShaderModuleSPIRVDescriptor* info2 = nullptr;
+ FindInChain(&chain1, &info1);
+ FindInChain(&chain1, &info2);
ASSERT_NE(nullptr, info1);
ASSERT_NE(nullptr, info2);
}
{
- native::DawnAdapterPropertiesPowerPreference chain;
- native::DawnAdapterPropertiesPowerPreference* output = nullptr;
- native::FindInChain(&chain, &output);
+ DawnAdapterPropertiesPowerPreference chain;
+ DawnAdapterPropertiesPowerPreference* output = nullptr;
+ FindInChain(&chain, &output);
ASSERT_NE(nullptr, output);
}
@@ -66,19 +69,19 @@
// Checks that searching a chain for a struct that doesn't exist returns a nullptr
TEST(ChainUtilsTests, FindMissingInChain) {
{
- native::PrimitiveDepthClipControl chain1;
- native::ShaderModuleSPIRVDescriptor chain2;
+ PrimitiveDepthClipControl chain1;
+ ShaderModuleSPIRVDescriptor chain2;
chain1.nextInChain = &chain2;
- const native::SurfaceDescriptorFromMetalLayer* info = nullptr;
- native::FindInChain(&chain1, &info);
+ const SurfaceDescriptorFromMetalLayer* info = nullptr;
+ FindInChain(&chain1, &info);
ASSERT_EQ(nullptr, info);
}
{
- native::AdapterProperties adapterProperties;
- native::DawnAdapterPropertiesPowerPreference* output = nullptr;
- native::FindInChain(adapterProperties.nextInChain, &output);
+ AdapterProperties adapterProperties;
+ DawnAdapterPropertiesPowerPreference* output = nullptr;
+ FindInChain(adapterProperties.nextInChain, &output);
ASSERT_EQ(nullptr, output);
}
@@ -87,23 +90,23 @@
// Checks that validation rejects chains with duplicate STypes
TEST(ChainUtilsTests, ValidateDuplicateSTypes) {
{
- native::PrimitiveDepthClipControl chain1;
- native::ShaderModuleSPIRVDescriptor chain2;
- native::PrimitiveDepthClipControl chain3;
+ PrimitiveDepthClipControl chain1;
+ ShaderModuleSPIRVDescriptor chain2;
+ PrimitiveDepthClipControl chain3;
chain1.nextInChain = &chain2;
chain2.nextInChain = &chain3;
- native::MaybeError result = native::ValidateSTypes(&chain1, {});
+ MaybeError result = ValidateSTypes(&chain1, {});
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
{
- native::DawnAdapterPropertiesPowerPreference chain1;
- native::DawnAdapterPropertiesPowerPreference chain2;
+ DawnAdapterPropertiesPowerPreference chain1;
+ DawnAdapterPropertiesPowerPreference chain2;
chain1.nextInChain = &chain2;
- native::MaybeError result = native::ValidateSTypes(&chain1, {});
+ MaybeError result = ValidateSTypes(&chain1, {});
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
@@ -112,29 +115,28 @@
// Checks that validation rejects chains that contain unspecified STypes
TEST(ChainUtilsTests, ValidateUnspecifiedSTypes) {
{
- native::PrimitiveDepthClipControl chain1;
- native::ShaderModuleSPIRVDescriptor chain2;
- native::ShaderModuleWGSLDescriptor chain3;
+ PrimitiveDepthClipControl chain1;
+ ShaderModuleSPIRVDescriptor chain2;
+ ShaderModuleWGSLDescriptor chain3;
chain1.nextInChain = &chain2;
chain2.nextInChain = &chain3;
- native::MaybeError result =
- native::ValidateSTypes(&chain1, {
- {wgpu::SType::PrimitiveDepthClipControl},
- {wgpu::SType::ShaderModuleSPIRVDescriptor},
- });
+ MaybeError result = ValidateSTypes(&chain1, {
+ {wgpu::SType::PrimitiveDepthClipControl},
+ {wgpu::SType::ShaderModuleSPIRVDescriptor},
+ });
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
{
- native::DawnAdapterPropertiesPowerPreference chain1;
- native::ChainedStructOut chain2;
+ DawnAdapterPropertiesPowerPreference chain1;
+ ChainedStructOut chain2;
chain2.sType = wgpu::SType::RenderPassDescriptorMaxDrawCount;
chain1.nextInChain = &chain2;
- native::MaybeError result =
- native::ValidateSTypes(&chain1, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}});
+ MaybeError result =
+ ValidateSTypes(&chain1, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}});
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
@@ -143,15 +145,14 @@
// Checks that validation rejects chains that contain multiple STypes from the same oneof
// constraint.
TEST(ChainUtilsTests, ValidateOneOfFailure) {
- native::PrimitiveDepthClipControl chain1;
- native::ShaderModuleSPIRVDescriptor chain2;
- native::ShaderModuleWGSLDescriptor chain3;
+ PrimitiveDepthClipControl chain1;
+ ShaderModuleSPIRVDescriptor chain2;
+ ShaderModuleWGSLDescriptor chain3;
chain1.nextInChain = &chain2;
chain2.nextInChain = &chain3;
- native::MaybeError result = native::ValidateSTypes(
- &chain1,
- {{wgpu::SType::ShaderModuleSPIRVDescriptor, wgpu::SType::ShaderModuleWGSLDescriptor}});
+ MaybeError result = ValidateSTypes(&chain1, {{wgpu::SType::ShaderModuleSPIRVDescriptor,
+ wgpu::SType::ShaderModuleWGSLDescriptor}});
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
@@ -159,11 +160,11 @@
// Checks that validation accepts chains that match the constraints.
TEST(ChainUtilsTests, ValidateSuccess) {
{
- native::PrimitiveDepthClipControl chain1;
- native::ShaderModuleSPIRVDescriptor chain2;
+ PrimitiveDepthClipControl chain1;
+ ShaderModuleSPIRVDescriptor chain2;
chain1.nextInChain = &chain2;
- native::MaybeError result = native::ValidateSTypes(
+ MaybeError result = ValidateSTypes(
&chain1,
{
{wgpu::SType::ShaderModuleSPIRVDescriptor, wgpu::SType::ShaderModuleWGSLDescriptor},
@@ -174,9 +175,9 @@
}
{
- native::DawnAdapterPropertiesPowerPreference chain1;
- native::MaybeError result =
- native::ValidateSTypes(&chain1, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}});
+ DawnAdapterPropertiesPowerPreference chain1;
+ MaybeError result =
+ ValidateSTypes(&chain1, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}});
ASSERT_TRUE(result.IsSuccess());
}
}
@@ -184,25 +185,24 @@
// Checks that validation always passes on empty chains.
TEST(ChainUtilsTests, ValidateEmptyChain) {
{
- const native::ChainedStruct* chain = nullptr;
- native::MaybeError result =
- native::ValidateSTypes(chain, {
- {wgpu::SType::ShaderModuleSPIRVDescriptor},
- {wgpu::SType::PrimitiveDepthClipControl},
- });
+ const ChainedStruct* chain = nullptr;
+ MaybeError result = ValidateSTypes(chain, {
+ {wgpu::SType::ShaderModuleSPIRVDescriptor},
+ {wgpu::SType::PrimitiveDepthClipControl},
+ });
ASSERT_TRUE(result.IsSuccess());
- result = native::ValidateSTypes(chain, {});
+ result = ValidateSTypes(chain, {});
ASSERT_TRUE(result.IsSuccess());
}
{
- native::ChainedStructOut* chain = nullptr;
- native::MaybeError result =
- native::ValidateSTypes(chain, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}});
+ ChainedStructOut* chain = nullptr;
+ MaybeError result =
+ ValidateSTypes(chain, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}});
ASSERT_TRUE(result.IsSuccess());
- result = native::ValidateSTypes(chain, {});
+ result = ValidateSTypes(chain, {});
ASSERT_TRUE(result.IsSuccess());
}
}
@@ -210,25 +210,23 @@
// Checks that singleton validation always passes on empty chains.
TEST(ChainUtilsTests, ValidateSingleEmptyChain) {
{
- const native::ChainedStruct* chain = nullptr;
- native::MaybeError result =
- native::ValidateSingleSType(chain, wgpu::SType::ShaderModuleSPIRVDescriptor);
+ const ChainedStruct* chain = nullptr;
+ MaybeError result = ValidateSingleSType(chain, wgpu::SType::ShaderModuleSPIRVDescriptor);
ASSERT_TRUE(result.IsSuccess());
- result = native::ValidateSingleSType(chain, wgpu::SType::ShaderModuleSPIRVDescriptor,
- wgpu::SType::PrimitiveDepthClipControl);
+ result = ValidateSingleSType(chain, wgpu::SType::ShaderModuleSPIRVDescriptor,
+ wgpu::SType::PrimitiveDepthClipControl);
ASSERT_TRUE(result.IsSuccess());
}
{
- native::ChainedStructOut* chain = nullptr;
- native::MaybeError result =
- native::ValidateSingleSType(chain, wgpu::SType::DawnAdapterPropertiesPowerPreference);
+ ChainedStructOut* chain = nullptr;
+ MaybeError result =
+ ValidateSingleSType(chain, wgpu::SType::DawnAdapterPropertiesPowerPreference);
ASSERT_TRUE(result.IsSuccess());
- result =
- native::ValidateSingleSType(chain, wgpu::SType::DawnAdapterPropertiesPowerPreference,
- wgpu::SType::PrimitiveDepthClipControl);
+ result = ValidateSingleSType(chain, wgpu::SType::DawnAdapterPropertiesPowerPreference,
+ wgpu::SType::PrimitiveDepthClipControl);
ASSERT_TRUE(result.IsSuccess());
}
}
@@ -236,28 +234,27 @@
// Checks that singleton validation always fails on chains with multiple children.
TEST(ChainUtilsTests, ValidateSingleMultiChain) {
{
- native::PrimitiveDepthClipControl chain1;
- native::ShaderModuleSPIRVDescriptor chain2;
+ PrimitiveDepthClipControl chain1;
+ ShaderModuleSPIRVDescriptor chain2;
chain1.nextInChain = &chain2;
- native::MaybeError result =
- native::ValidateSingleSType(&chain1, wgpu::SType::PrimitiveDepthClipControl);
+ MaybeError result = ValidateSingleSType(&chain1, wgpu::SType::PrimitiveDepthClipControl);
ASSERT_TRUE(result.IsError());
result.AcquireError();
- result = native::ValidateSingleSType(&chain1, wgpu::SType::PrimitiveDepthClipControl,
- wgpu::SType::ShaderModuleSPIRVDescriptor);
+ result = ValidateSingleSType(&chain1, wgpu::SType::PrimitiveDepthClipControl,
+ wgpu::SType::ShaderModuleSPIRVDescriptor);
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
{
- native::DawnAdapterPropertiesPowerPreference chain1;
- native::DawnAdapterPropertiesPowerPreference chain2;
+ DawnAdapterPropertiesPowerPreference chain1;
+ DawnAdapterPropertiesPowerPreference chain2;
chain1.nextInChain = &chain2;
- native::MaybeError result =
- native::ValidateSingleSType(&chain1, wgpu::SType::DawnAdapterPropertiesPowerPreference);
+ MaybeError result =
+ ValidateSingleSType(&chain1, wgpu::SType::DawnAdapterPropertiesPowerPreference);
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
@@ -266,25 +263,24 @@
// Checks that singleton validation passes when the one of constraint is met.
TEST(ChainUtilsTests, ValidateSingleSatisfied) {
{
- native::ShaderModuleWGSLDescriptor chain1;
+ ShaderModuleWGSLDescriptor chain1;
- native::MaybeError result =
- native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor);
+ MaybeError result = ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor);
ASSERT_TRUE(result.IsSuccess());
- result = native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleSPIRVDescriptor,
- wgpu::SType::ShaderModuleWGSLDescriptor);
+ result = ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleSPIRVDescriptor,
+ wgpu::SType::ShaderModuleWGSLDescriptor);
ASSERT_TRUE(result.IsSuccess());
- result = native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor,
- wgpu::SType::ShaderModuleSPIRVDescriptor);
+ result = ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor,
+ wgpu::SType::ShaderModuleSPIRVDescriptor);
ASSERT_TRUE(result.IsSuccess());
}
{
- native::DawnAdapterPropertiesPowerPreference chain1;
- native::MaybeError result =
- native::ValidateSingleSType(&chain1, wgpu::SType::DawnAdapterPropertiesPowerPreference);
+ DawnAdapterPropertiesPowerPreference chain1;
+ MaybeError result =
+ ValidateSingleSType(&chain1, wgpu::SType::DawnAdapterPropertiesPowerPreference);
ASSERT_TRUE(result.IsSuccess());
}
}
@@ -292,29 +288,121 @@
// Checks that singleton validation passes when the oneof constraint is not met.
TEST(ChainUtilsTests, ValidateSingleUnsatisfied) {
{
- native::PrimitiveDepthClipControl chain1;
+ PrimitiveDepthClipControl chain1;
- native::MaybeError result =
- native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor);
+ MaybeError result = ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor);
ASSERT_TRUE(result.IsError());
result.AcquireError();
- result = native::ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleSPIRVDescriptor,
- wgpu::SType::ShaderModuleWGSLDescriptor);
+ result = ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleSPIRVDescriptor,
+ wgpu::SType::ShaderModuleWGSLDescriptor);
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
{
- native::ChainedStructOut chain1;
+ ChainedStructOut chain1;
chain1.sType = wgpu::SType::ShaderModuleWGSLDescriptor;
- native::MaybeError result =
- native::ValidateSingleSType(&chain1, wgpu::SType::DawnAdapterPropertiesPowerPreference);
+ MaybeError result =
+ ValidateSingleSType(&chain1, wgpu::SType::DawnAdapterPropertiesPowerPreference);
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
}
+// Empty chain on roots that have and don't have valid extensions should not fail validation and all
+// values should be nullptr.
+TEST(ChainUtilsTests, ValidateAndUnpackEmpty) {
+ {
+ // TextureViewDescriptor (as of when this test was written) does not have any valid chains
+ // in the JSON nor via additional extensions.
+ TextureViewDescriptor desc;
+ auto unpacked = ValidateAndUnpackChain(&desc).AcquireSuccess();
+ static_assert(std::tuple_size_v<decltype(unpacked)> == 0);
+ std::apply(
+ [](const auto*... args) {
+ (([&](const auto* arg) { EXPECT_EQ(args, nullptr); }(args)), ...);
+ },
+ unpacked);
+ }
+ {
+ // InstanceDescriptor has at least 1 valid chain extension.
+ InstanceDescriptor desc;
+ auto unpacked = ValidateAndUnpackChain(&desc).AcquireSuccess();
+ std::apply(
+ [](const auto*... args) {
+ (([&](const auto* arg) { EXPECT_EQ(args, nullptr); }(args)), ...);
+ },
+ unpacked);
+ }
+}
+
+// Invalid chain extensions should cause an error.
+TEST(ChainUtilsTests, ValidateAndUnpackUnexpected) {
+ {
+ // TextureViewDescriptor (as of when this test was written) does not have any valid chains
+ // in the JSON nor via additional extensions.
+ TextureViewDescriptor desc;
+ ChainedStruct chain;
+ desc.nextInChain = &chain;
+ EXPECT_THAT(ValidateAndUnpackChain(&desc).AcquireError()->GetFormattedMessage(),
+ HasSubstr("Unexpected"));
+ }
+ {
+ // InstanceDescriptor has at least 1 valid chain extension.
+ InstanceDescriptor desc;
+ ChainedStruct chain;
+ desc.nextInChain = &chain;
+ EXPECT_THAT(ValidateAndUnpackChain(&desc).AcquireError()->GetFormattedMessage(),
+ HasSubstr("Unexpected"));
+ }
+}
+
+// Nominal unpacking valid descriptors should return the expected descriptors in the unpacked type.
+TEST(ChainUtilsTests, ValidateAndUnpack) {
+ // DawnTogglesDescriptor is a valid extension for InstanceDescriptor.
+ InstanceDescriptor desc;
+ DawnTogglesDescriptor chain;
+ desc.nextInChain = &chain;
+ auto unpacked = ValidateAndUnpackChain(&desc).AcquireSuccess();
+ EXPECT_EQ(std::get<const DawnTogglesDescriptor*>(unpacked), &chain);
+}
+
+// Duplicate valid extensions should cause an error.
+TEST(ChainUtilsTests, ValidateAndUnpackDuplicate) {
+ // DawnTogglesDescriptor is a valid extension for InstanceDescriptor.
+ InstanceDescriptor desc;
+ DawnTogglesDescriptor chain1;
+ DawnTogglesDescriptor chain2;
+ desc.nextInChain = &chain1;
+ chain1.nextInChain = &chain2;
+ EXPECT_THAT(ValidateAndUnpackChain(&desc).AcquireError()->GetFormattedMessage(),
+ HasSubstr("Duplicate"));
+}
+
+// Additional extensions added via template specialization and not specified in the JSON should work
+// properly.
+TEST(ChainUtilsTests, ValidateAndUnpackAdditionalExtensions) {
+ // DawnInstanceDescriptor is an extension on InstanceDescriptor added in ChainUtilsImpl.h.
+ InstanceDescriptor desc;
+ DawnInstanceDescriptor chain;
+ desc.nextInChain = &chain;
+ auto unpacked = ValidateAndUnpackChain(&desc).AcquireSuccess();
+ EXPECT_EQ(std::get<const DawnInstanceDescriptor*>(unpacked), &chain);
+}
+
+// Duplicate additional extensions added via template specialization should cause an error.
+TEST(ChainUtilsTests, ValidateAndUnpackDuplicateAdditionalExtensions) {
+ // DawnInstanceDescriptor is an extension on InstanceDescriptor added in ChainUtilsImpl.h.
+ InstanceDescriptor desc;
+ DawnInstanceDescriptor chain1;
+ DawnInstanceDescriptor chain2;
+ desc.nextInChain = &chain1;
+ chain1.nextInChain = &chain2;
+ EXPECT_THAT(ValidateAndUnpackChain(&desc).AcquireError()->GetFormattedMessage(),
+ HasSubstr("Duplicate"));
+}
+
} // anonymous namespace
-} // namespace dawn
+} // namespace dawn::native