blob: 47d3ca92a09459d8e76d0b7eee98f20d151532b7 [file] [log] [blame]
// 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include "dawn/native/ChainUtils.h"
#include "dawn/native/dawn_platform.h"
namespace dawn::native {
namespace {
using ::testing::HasSubstr;
// Checks that we cannot find any structs in an empty chain
TEST(ChainUtilsTests, FindEmptyChain) {
{
const PrimitiveDepthClipControl* info = nullptr;
const ChainedStruct* chained = nullptr;
FindInChain(chained, &info);
ASSERT_EQ(nullptr, info);
}
{
DawnAdapterPropertiesPowerPreference* info = nullptr;
ChainedStructOut* chained = nullptr;
FindInChain(chained, &info);
ASSERT_EQ(nullptr, info);
}
}
// Checks that searching a chain for a present struct returns that struct
TEST(ChainUtilsTests, FindPresentInChain) {
{
PrimitiveDepthClipControl chain1;
ShaderModuleSPIRVDescriptor chain2;
chain1.nextInChain = &chain2;
const PrimitiveDepthClipControl* info1 = nullptr;
const ShaderModuleSPIRVDescriptor* info2 = nullptr;
FindInChain(&chain1, &info1);
FindInChain(&chain1, &info2);
ASSERT_NE(nullptr, info1);
ASSERT_NE(nullptr, info2);
}
{
DawnAdapterPropertiesPowerPreference chain;
DawnAdapterPropertiesPowerPreference* output = nullptr;
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) {
{
PrimitiveDepthClipControl chain1;
ShaderModuleSPIRVDescriptor chain2;
chain1.nextInChain = &chain2;
const SurfaceDescriptorFromMetalLayer* info = nullptr;
FindInChain(&chain1, &info);
ASSERT_EQ(nullptr, info);
}
{
AdapterProperties adapterProperties;
DawnAdapterPropertiesPowerPreference* output = nullptr;
FindInChain(adapterProperties.nextInChain, &output);
ASSERT_EQ(nullptr, output);
}
}
// Checks that validation rejects chains with duplicate STypes
TEST(ChainUtilsTests, ValidateDuplicateSTypes) {
{
PrimitiveDepthClipControl chain1;
ShaderModuleSPIRVDescriptor chain2;
PrimitiveDepthClipControl chain3;
chain1.nextInChain = &chain2;
chain2.nextInChain = &chain3;
MaybeError result = ValidateSTypes(&chain1, {});
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
{
DawnAdapterPropertiesPowerPreference chain1;
DawnAdapterPropertiesPowerPreference chain2;
chain1.nextInChain = &chain2;
MaybeError result = ValidateSTypes(&chain1, {});
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
}
// Checks that validation rejects chains that contain unspecified STypes
TEST(ChainUtilsTests, ValidateUnspecifiedSTypes) {
{
PrimitiveDepthClipControl chain1;
ShaderModuleSPIRVDescriptor chain2;
ShaderModuleWGSLDescriptor chain3;
chain1.nextInChain = &chain2;
chain2.nextInChain = &chain3;
MaybeError result = ValidateSTypes(&chain1, {
{wgpu::SType::PrimitiveDepthClipControl},
{wgpu::SType::ShaderModuleSPIRVDescriptor},
});
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
{
DawnAdapterPropertiesPowerPreference chain1;
ChainedStructOut chain2;
chain2.sType = wgpu::SType::RenderPassDescriptorMaxDrawCount;
chain1.nextInChain = &chain2;
MaybeError result =
ValidateSTypes(&chain1, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}});
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
}
// Checks that validation rejects chains that contain multiple STypes from the same oneof
// constraint.
TEST(ChainUtilsTests, ValidateOneOfFailure) {
PrimitiveDepthClipControl chain1;
ShaderModuleSPIRVDescriptor chain2;
ShaderModuleWGSLDescriptor chain3;
chain1.nextInChain = &chain2;
chain2.nextInChain = &chain3;
MaybeError result = ValidateSTypes(&chain1, {{wgpu::SType::ShaderModuleSPIRVDescriptor,
wgpu::SType::ShaderModuleWGSLDescriptor}});
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
// Checks that validation accepts chains that match the constraints.
TEST(ChainUtilsTests, ValidateSuccess) {
{
PrimitiveDepthClipControl chain1;
ShaderModuleSPIRVDescriptor chain2;
chain1.nextInChain = &chain2;
MaybeError result = ValidateSTypes(
&chain1,
{
{wgpu::SType::ShaderModuleSPIRVDescriptor, wgpu::SType::ShaderModuleWGSLDescriptor},
{wgpu::SType::PrimitiveDepthClipControl},
{wgpu::SType::SurfaceDescriptorFromMetalLayer},
});
ASSERT_TRUE(result.IsSuccess());
}
{
DawnAdapterPropertiesPowerPreference chain1;
MaybeError result =
ValidateSTypes(&chain1, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}});
ASSERT_TRUE(result.IsSuccess());
}
}
// Checks that validation always passes on empty chains.
TEST(ChainUtilsTests, ValidateEmptyChain) {
{
const ChainedStruct* chain = nullptr;
MaybeError result = ValidateSTypes(chain, {
{wgpu::SType::ShaderModuleSPIRVDescriptor},
{wgpu::SType::PrimitiveDepthClipControl},
});
ASSERT_TRUE(result.IsSuccess());
result = ValidateSTypes(chain, {});
ASSERT_TRUE(result.IsSuccess());
}
{
ChainedStructOut* chain = nullptr;
MaybeError result =
ValidateSTypes(chain, {{wgpu::SType::DawnAdapterPropertiesPowerPreference}});
ASSERT_TRUE(result.IsSuccess());
result = ValidateSTypes(chain, {});
ASSERT_TRUE(result.IsSuccess());
}
}
// Checks that singleton validation always passes on empty chains.
TEST(ChainUtilsTests, ValidateSingleEmptyChain) {
{
const ChainedStruct* chain = nullptr;
MaybeError result = ValidateSingleSType(chain, wgpu::SType::ShaderModuleSPIRVDescriptor);
ASSERT_TRUE(result.IsSuccess());
result = ValidateSingleSType(chain, wgpu::SType::ShaderModuleSPIRVDescriptor,
wgpu::SType::PrimitiveDepthClipControl);
ASSERT_TRUE(result.IsSuccess());
}
{
ChainedStructOut* chain = nullptr;
MaybeError result =
ValidateSingleSType(chain, wgpu::SType::DawnAdapterPropertiesPowerPreference);
ASSERT_TRUE(result.IsSuccess());
result = 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) {
{
PrimitiveDepthClipControl chain1;
ShaderModuleSPIRVDescriptor chain2;
chain1.nextInChain = &chain2;
MaybeError result = ValidateSingleSType(&chain1, wgpu::SType::PrimitiveDepthClipControl);
ASSERT_TRUE(result.IsError());
result.AcquireError();
result = ValidateSingleSType(&chain1, wgpu::SType::PrimitiveDepthClipControl,
wgpu::SType::ShaderModuleSPIRVDescriptor);
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
{
DawnAdapterPropertiesPowerPreference chain1;
DawnAdapterPropertiesPowerPreference chain2;
chain1.nextInChain = &chain2;
MaybeError result =
ValidateSingleSType(&chain1, wgpu::SType::DawnAdapterPropertiesPowerPreference);
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
}
// Checks that singleton validation passes when the one of constraint is met.
TEST(ChainUtilsTests, ValidateSingleSatisfied) {
{
ShaderModuleWGSLDescriptor chain1;
MaybeError result = ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor);
ASSERT_TRUE(result.IsSuccess());
result = ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleSPIRVDescriptor,
wgpu::SType::ShaderModuleWGSLDescriptor);
ASSERT_TRUE(result.IsSuccess());
result = ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor,
wgpu::SType::ShaderModuleSPIRVDescriptor);
ASSERT_TRUE(result.IsSuccess());
}
{
DawnAdapterPropertiesPowerPreference chain1;
MaybeError result =
ValidateSingleSType(&chain1, wgpu::SType::DawnAdapterPropertiesPowerPreference);
ASSERT_TRUE(result.IsSuccess());
}
}
// Checks that singleton validation passes when the oneof constraint is not met.
TEST(ChainUtilsTests, ValidateSingleUnsatisfied) {
{
PrimitiveDepthClipControl chain1;
MaybeError result = ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleWGSLDescriptor);
ASSERT_TRUE(result.IsError());
result.AcquireError();
result = ValidateSingleSType(&chain1, wgpu::SType::ShaderModuleSPIRVDescriptor,
wgpu::SType::ShaderModuleWGSLDescriptor);
ASSERT_TRUE(result.IsError());
result.AcquireError();
}
{
ChainedStructOut chain1;
chain1.sType = wgpu::SType::ShaderModuleWGSLDescriptor;
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 = ValidateAndUnpack(&desc).AcquireSuccess();
static_assert(std::tuple_size_v<decltype(unpacked)::TupleType> == 0);
EXPECT_TRUE(unpacked.Empty());
}
{
// InstanceDescriptor has at least 1 valid chain extension.
InstanceDescriptor desc;
auto unpacked = ValidateAndUnpack(&desc).AcquireSuccess();
EXPECT_TRUE(unpacked.Empty());
}
{
// SharedTextureMemoryProperties (as of when this test was written) does not have any valid
// chains in the JSON nor via additional extensions.
SharedTextureMemoryProperties properties;
auto unpacked = ValidateAndUnpack(&properties).AcquireSuccess();
static_assert(std::tuple_size_v<decltype(unpacked)::TupleType> == 0);
EXPECT_TRUE(unpacked.Empty());
}
{
// SharedFenceExportInfo has at least 1 valid chain extension.
SharedFenceExportInfo properties;
auto unpacked = ValidateAndUnpack(&properties).AcquireSuccess();
EXPECT_TRUE(unpacked.Empty());
}
}
// Invalid chain extensions 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(ValidateAndUnpack(&desc).AcquireError()->GetFormattedMessage(),
HasSubstr("Unexpected"));
}
{
// InstanceDescriptor has at least 1 valid chain extension.
InstanceDescriptor desc;
ChainedStruct chain;
desc.nextInChain = &chain;
EXPECT_THAT(ValidateAndUnpack(&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 = ValidateAndUnpack(&desc).AcquireSuccess();
auto ext = unpacked.Get<DawnTogglesDescriptor>();
EXPECT_EQ(ext, &chain);
// For ChainedStructs, the resulting pointer from Get should be a const type.
static_assert(std::is_const_v<std::remove_reference_t<decltype(*ext)>>);
}
// Nominal unpacking valid descriptors should return the expected descriptors in the unpacked type.
TEST(ChainUtilsTests, ValidateAndUnpackOut) {
// DawnAdapterPropertiesPowerPreference is a valid extension for AdapterProperties.
AdapterProperties properties;
DawnAdapterPropertiesPowerPreference chain;
properties.nextInChain = &chain;
auto unpacked = ValidateAndUnpack(&properties).AcquireSuccess();
auto ext = unpacked.Get<DawnAdapterPropertiesPowerPreference>();
EXPECT_EQ(ext, &chain);
// For ChainedStructOuts, the resulting pointer from Get should not be a const type.
static_assert(!std::is_const_v<std::remove_reference_t<decltype(*ext)>>);
}
// Duplicate valid extensions 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(ValidateAndUnpack(&desc).AcquireError()->GetFormattedMessage(),
HasSubstr("Duplicate"));
}
// Duplicate valid extensions cause an error.
TEST(ChainUtilsTests, ValidateAndUnpackOutDuplicate) {
// DawnAdapterPropertiesPowerPreference is a valid extension for AdapterProperties.
AdapterProperties properties;
DawnAdapterPropertiesPowerPreference chain1;
DawnAdapterPropertiesPowerPreference chain2;
properties.nextInChain = &chain1;
chain1.nextInChain = &chain2;
EXPECT_THAT(ValidateAndUnpack(&properties).AcquireError()->GetFormattedMessage(),
HasSubstr("Duplicate"));
}
// Additional extensions added via template specialization and not specified in the JSON unpack
// properly.
TEST(ChainUtilsTests, ValidateAndUnpackAdditionalExtensions) {
// DawnInstanceDescriptor is an extension on InstanceDescriptor added in ChainUtilsImpl.inl.
InstanceDescriptor desc;
DawnInstanceDescriptor chain;
desc.nextInChain = &chain;
auto unpacked = ValidateAndUnpack(&desc).AcquireSuccess();
EXPECT_EQ(unpacked.Get<DawnInstanceDescriptor>(), &chain);
}
// Duplicate additional extensions added via template specialization should cause an error.
TEST(ChainUtilsTests, ValidateAndUnpackDuplicateAdditionalExtensions) {
// DawnInstanceDescriptor is an extension on InstanceDescriptor added in ChainUtilsImpl.inl.
InstanceDescriptor desc;
DawnInstanceDescriptor chain1;
DawnInstanceDescriptor chain2;
desc.nextInChain = &chain1;
chain1.nextInChain = &chain2;
EXPECT_THAT(ValidateAndUnpack(&desc).AcquireError()->GetFormattedMessage(),
HasSubstr("Duplicate"));
}
using B1 = Branch<ShaderModuleWGSLDescriptor>;
using B2 = Branch<ShaderModuleSPIRVDescriptor>;
using B2Ext = Branch<ShaderModuleSPIRVDescriptor, DawnShaderModuleSPIRVOptionsDescriptor>;
// Validates exacly 1 branch and ensures that there are no other extensions.
TEST(ChainUtilsTests, ValidateBranchesOneValidBranch) {
ShaderModuleDescriptor desc;
// Either allowed branches should validate successfully and return the expected enum.
{
ShaderModuleWGSLDescriptor chain;
desc.nextInChain = &chain;
auto unpacked = ValidateAndUnpack(&desc).AcquireSuccess();
EXPECT_EQ((unpacked.ValidateBranches<B1, B2>().AcquireSuccess()),
wgpu::SType::ShaderModuleWGSLDescriptor);
}
{
ShaderModuleSPIRVDescriptor chain;
desc.nextInChain = &chain;
auto unpacked = ValidateAndUnpack(&desc).AcquireSuccess();
EXPECT_EQ((unpacked.ValidateBranches<B1, B2>().AcquireSuccess()),
wgpu::SType::ShaderModuleSPIRVDescriptor);
// Extensions are optional so validation should still pass when the extension is not
// provided.
EXPECT_EQ((unpacked.ValidateBranches<B1, B2Ext>().AcquireSuccess()),
wgpu::SType::ShaderModuleSPIRVDescriptor);
}
}
// An allowed chain that is not one of the branches causes an error.
TEST(ChainUtilsTests, ValidateBranchesInvalidBranch) {
ShaderModuleDescriptor desc;
DawnShaderModuleSPIRVOptionsDescriptor chain;
desc.nextInChain = &chain;
auto unpacked = ValidateAndUnpack(&desc).AcquireSuccess();
EXPECT_NE((unpacked.ValidateBranches<B1, B2>().AcquireError()), nullptr);
EXPECT_NE((unpacked.ValidateBranches<B1, B2Ext>().AcquireError()), nullptr);
}
// Additional chains should cause an error when branches don't allow extensions.
TEST(ChainUtilsTests, ValidateBranchesInvalidExtension) {
ShaderModuleDescriptor desc;
{
ShaderModuleWGSLDescriptor chain1;
DawnShaderModuleSPIRVOptionsDescriptor chain2;
desc.nextInChain = &chain1;
chain1.nextInChain = &chain2;
auto unpacked = ValidateAndUnpack(&desc).AcquireSuccess();
EXPECT_NE((unpacked.ValidateBranches<B1, B2>().AcquireError()), nullptr);
EXPECT_NE((unpacked.ValidateBranches<B1, B2Ext>().AcquireError()), nullptr);
}
{
ShaderModuleSPIRVDescriptor chain1;
DawnShaderModuleSPIRVOptionsDescriptor chain2;
desc.nextInChain = &chain1;
chain1.nextInChain = &chain2;
auto unpacked = ValidateAndUnpack(&desc).AcquireSuccess();
EXPECT_NE((unpacked.ValidateBranches<B1, B2>().AcquireError()), nullptr);
}
}
// Branches that allow extensions pass successfully.
TEST(ChainUtilsTests, ValidateBranchesAllowedExtensions) {
ShaderModuleDescriptor desc;
ShaderModuleSPIRVDescriptor chain1;
DawnShaderModuleSPIRVOptionsDescriptor chain2;
desc.nextInChain = &chain1;
chain1.nextInChain = &chain2;
auto unpacked = ValidateAndUnpack(&desc).AcquireSuccess();
EXPECT_EQ((unpacked.ValidateBranches<B1, B2Ext>().AcquireSuccess()),
wgpu::SType::ShaderModuleSPIRVDescriptor);
}
// Unrealistic branching for ChainedStructOut testing. Note that this setup does not make sense.
using BOut1 = Branch<SharedFenceVkSemaphoreOpaqueFDExportInfo>;
using BOut2 = Branch<SharedFenceVkSemaphoreSyncFDExportInfo>;
using BOut2Ext =
Branch<SharedFenceVkSemaphoreSyncFDExportInfo, SharedFenceVkSemaphoreZirconHandleExportInfo>;
// Validates exacly 1 branch and ensures that there are no other extensions.
TEST(ChainUtilsTests, ValidateBranchesOneValidBranchOut) {
SharedFenceExportInfo info;
// Either allowed branches should validate successfully and return the expected enum.
{
SharedFenceVkSemaphoreOpaqueFDExportInfo chain;
info.nextInChain = &chain;
auto unpacked = ValidateAndUnpack(&info).AcquireSuccess();
EXPECT_EQ((unpacked.ValidateBranches<BOut1, BOut2>().AcquireSuccess()),
wgpu::SType::SharedFenceVkSemaphoreOpaqueFDExportInfo);
}
{
SharedFenceVkSemaphoreSyncFDExportInfo chain;
info.nextInChain = &chain;
auto unpacked = ValidateAndUnpack(&info).AcquireSuccess();
EXPECT_EQ((unpacked.ValidateBranches<BOut1, BOut2>().AcquireSuccess()),
wgpu::SType::SharedFenceVkSemaphoreSyncFDExportInfo);
// Extensions are optional so validation should still pass when the extension is not
// provided.
EXPECT_EQ((unpacked.ValidateBranches<BOut1, BOut2Ext>().AcquireSuccess()),
wgpu::SType::SharedFenceVkSemaphoreSyncFDExportInfo);
}
}
// An allowed chain that is not one of the branches causes an error.
TEST(ChainUtilsTests, ValidateBranchesInvalidBranchOut) {
SharedFenceExportInfo info;
SharedFenceDXGISharedHandleExportInfo chain;
info.nextInChain = &chain;
auto unpacked = ValidateAndUnpack(&info).AcquireSuccess();
EXPECT_NE((unpacked.ValidateBranches<BOut1, BOut2>().AcquireError()), nullptr);
EXPECT_NE((unpacked.ValidateBranches<BOut1, BOut2Ext>().AcquireError()), nullptr);
}
// Additional chains should cause an error when branches don't allow extensions.
TEST(ChainUtilsTests, ValidateBranchesInvalidExtensionOut) {
SharedFenceExportInfo info;
{
SharedFenceVkSemaphoreOpaqueFDExportInfo chain1;
SharedFenceVkSemaphoreZirconHandleExportInfo chain2;
info.nextInChain = &chain1;
chain1.nextInChain = &chain2;
auto unpacked = ValidateAndUnpack(&info).AcquireSuccess();
EXPECT_NE((unpacked.ValidateBranches<BOut1, BOut2>().AcquireError()), nullptr);
EXPECT_NE((unpacked.ValidateBranches<BOut1, BOut2Ext>().AcquireError()), nullptr);
}
{
SharedFenceVkSemaphoreSyncFDExportInfo chain1;
SharedFenceVkSemaphoreZirconHandleExportInfo chain2;
info.nextInChain = &chain1;
chain1.nextInChain = &chain2;
auto unpacked = ValidateAndUnpack(&info).AcquireSuccess();
EXPECT_NE((unpacked.ValidateBranches<BOut1, BOut2>().AcquireError()), nullptr);
}
}
// Branches that allow extensions pass successfully.
TEST(ChainUtilsTests, ValidateBranchesAllowedExtensionsOut) {
SharedFenceExportInfo info;
SharedFenceVkSemaphoreSyncFDExportInfo chain1;
SharedFenceVkSemaphoreZirconHandleExportInfo chain2;
info.nextInChain = &chain1;
chain1.nextInChain = &chain2;
auto unpacked = ValidateAndUnpack(&info).AcquireSuccess();
EXPECT_EQ((unpacked.ValidateBranches<BOut1, BOut2Ext>().AcquireSuccess()),
wgpu::SType::SharedFenceVkSemaphoreSyncFDExportInfo);
}
// Valid subsets should pass successfully, while invalid ones should error.
TEST(ChainUtilsTests, ValidateSubset) {
DeviceDescriptor desc;
DawnTogglesDescriptor chain1;
DawnCacheDeviceDescriptor chain2;
// With none set, subset for anything should work.
{
auto unpacked = ValidateAndUnpack(&desc).AcquireSuccess();
EXPECT_TRUE(unpacked.ValidateSubset<DawnTogglesDescriptor>().IsSuccess());
EXPECT_TRUE(unpacked.ValidateSubset<DawnCacheDeviceDescriptor>().IsSuccess());
EXPECT_TRUE((unpacked.ValidateSubset<DawnTogglesDescriptor, DawnCacheDeviceDescriptor>()
.IsSuccess()));
}
// With one set, subset with that allow that one should pass. Otherwise it should fail.
{
desc.nextInChain = &chain1;
auto unpacked = ValidateAndUnpack(&desc).AcquireSuccess();
EXPECT_TRUE(unpacked.ValidateSubset<DawnTogglesDescriptor>().IsSuccess());
EXPECT_NE(unpacked.ValidateSubset<DawnCacheDeviceDescriptor>().AcquireError(), nullptr);
EXPECT_TRUE((unpacked.ValidateSubset<DawnTogglesDescriptor, DawnCacheDeviceDescriptor>()
.IsSuccess()));
}
// With both set, single subsets should all fail.
{
chain1.nextInChain = &chain2;
auto unpacked = ValidateAndUnpack(&desc).AcquireSuccess();
EXPECT_NE(unpacked.ValidateSubset<DawnTogglesDescriptor>().AcquireError(), nullptr);
EXPECT_NE(unpacked.ValidateSubset<DawnCacheDeviceDescriptor>().AcquireError(), nullptr);
EXPECT_TRUE((unpacked.ValidateSubset<DawnTogglesDescriptor, DawnCacheDeviceDescriptor>()
.IsSuccess()));
}
}
// Valid subsets should pass successfully, while invalid ones should error.
TEST(ChainUtilsTests, ValidateSubsetOut) {
SharedFenceExportInfo info;
SharedFenceVkSemaphoreOpaqueFDExportInfo chain1;
SharedFenceVkSemaphoreZirconHandleExportInfo chain2;
// With none set, subset for anything should work.
{
auto unpacked = ValidateAndUnpack(&info).AcquireSuccess();
EXPECT_TRUE(
unpacked.ValidateSubset<SharedFenceVkSemaphoreOpaqueFDExportInfo>().IsSuccess());
EXPECT_TRUE(
unpacked.ValidateSubset<SharedFenceVkSemaphoreZirconHandleExportInfo>().IsSuccess());
EXPECT_TRUE((unpacked
.ValidateSubset<SharedFenceVkSemaphoreOpaqueFDExportInfo,
SharedFenceVkSemaphoreZirconHandleExportInfo>()
.IsSuccess()));
}
// With one set, subset with that allow that one should pass. Otherwise it should fail.
{
info.nextInChain = &chain1;
auto unpacked = ValidateAndUnpack(&info).AcquireSuccess();
EXPECT_TRUE(
unpacked.ValidateSubset<SharedFenceVkSemaphoreOpaqueFDExportInfo>().IsSuccess());
EXPECT_NE(
unpacked.ValidateSubset<SharedFenceVkSemaphoreZirconHandleExportInfo>().AcquireError(),
nullptr);
EXPECT_TRUE((unpacked
.ValidateSubset<SharedFenceVkSemaphoreOpaqueFDExportInfo,
SharedFenceVkSemaphoreZirconHandleExportInfo>()
.IsSuccess()));
}
// With both set, single subsets should all fail.
{
chain1.nextInChain = &chain2;
auto unpacked = ValidateAndUnpack(&info).AcquireSuccess();
EXPECT_NE(
unpacked.ValidateSubset<SharedFenceVkSemaphoreOpaqueFDExportInfo>().AcquireError(),
nullptr);
EXPECT_NE(
unpacked.ValidateSubset<SharedFenceVkSemaphoreZirconHandleExportInfo>().AcquireError(),
nullptr);
EXPECT_TRUE((unpacked
.ValidateSubset<SharedFenceVkSemaphoreOpaqueFDExportInfo,
SharedFenceVkSemaphoreZirconHandleExportInfo>()
.IsSuccess()));
}
}
} // anonymous namespace
} // namespace dawn::native