blob: 019bb635bb35295e0843312f16b8d3712606dc48 [file] [log] [blame] [edit]
// Copyright 2023 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 <algorithm>
#include <vector>
#include "dawn/tests/unittests/validation/ValidationTest.h"
#include "dawn/utils/WGPUHelpers.h"
#include "dawn/utils/WireHelper.h"
namespace dawn {
namespace {
class WGSLFeatureValidationTest : public ValidationTest {
protected:
struct InstanceSpec {
bool useTestingFeatures = true;
bool allowUnsafeAPIs = false;
bool exposeExperimental = false;
std::vector<const char*> blocklist = {};
};
// Override the default SetUp to do nothing since the tests will call SetUp(InstanceSpec)
// explicitly each time.
void SetUp() override {}
void SetUp(InstanceSpec spec) {
// The blocklist that will be shared between both the native and wire descriptors.
wgpu::DawnWGSLBlocklist blocklist;
blocklist.blocklistedFeatureCount = spec.blocklist.size();
blocklist.blocklistedFeatures = spec.blocklist.data();
// Build the native instance descriptor.
std::vector<const char*> enabledToggles;
if (spec.useTestingFeatures) {
enabledToggles.push_back("expose_wgsl_testing_features");
}
if (spec.allowUnsafeAPIs) {
enabledToggles.push_back("allow_unsafe_apis");
}
if (spec.exposeExperimental) {
enabledToggles.push_back("expose_wgsl_experimental_features");
}
wgpu::DawnTogglesDescriptor togglesDesc;
togglesDesc.nextInChain = &blocklist;
togglesDesc.enabledToggleCount = enabledToggles.size();
togglesDesc.enabledToggles = enabledToggles.data();
wgpu::InstanceDescriptor nativeDesc;
nativeDesc.nextInChain = &togglesDesc;
// Build the wire instance descriptor.
wgpu::DawnWireWGSLControl wgslControl;
wgslControl.nextInChain = &blocklist;
wgslControl.enableExperimental = spec.allowUnsafeAPIs || spec.exposeExperimental;
wgslControl.enableUnsafe = spec.allowUnsafeAPIs;
wgslControl.enableTesting = spec.useTestingFeatures;
wgpu::InstanceDescriptor wireDesc;
wireDesc.nextInChain = &wgslControl;
ValidationTest::SetUp(&nativeDesc, &wireDesc);
}
};
wgpu::WGSLLanguageFeatureName kNonExistentFeature = {};
// Check HasFeature for an Instance that doesn't have unsafe APIs.
TEST_F(WGSLFeatureValidationTest, HasFeatureDefaultInstance) {
SetUp({});
// Shipped features are present.
ASSERT_TRUE(
instance.HasWGSLLanguageFeature(wgpu::WGSLLanguageFeatureName::ChromiumTestingShipped));
ASSERT_TRUE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingShippedWithKillswitch));
// Experimental and unimplemented features are not present.
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingExperimental));
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingUnsafeExperimental));
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingUnimplemented));
// Non-existent features are not present.
ASSERT_FALSE(instance.HasWGSLLanguageFeature(kNonExistentFeature));
}
// Check HasFeature for an Instance that has unsafe APIs.
TEST_F(WGSLFeatureValidationTest, HasFeatureExposeExperimental) {
SetUp({.exposeExperimental = true});
// Shipped and experimental features are present.
ASSERT_TRUE(
instance.HasWGSLLanguageFeature(wgpu::WGSLLanguageFeatureName::ChromiumTestingShipped));
ASSERT_TRUE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingShippedWithKillswitch));
ASSERT_TRUE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingExperimental));
// Unsafe and unimplemented features are not present.
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingUnsafeExperimental));
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingUnimplemented));
// Non-existent features are not present.
ASSERT_FALSE(instance.HasWGSLLanguageFeature(kNonExistentFeature));
}
// Check HasFeature for an Instance that has unsafe APIs.
TEST_F(WGSLFeatureValidationTest, HasFeatureAllowUnsafeInstance) {
SetUp({.allowUnsafeAPIs = true});
// Shipped and experimental features are present.
ASSERT_TRUE(
instance.HasWGSLLanguageFeature(wgpu::WGSLLanguageFeatureName::ChromiumTestingShipped));
ASSERT_TRUE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingShippedWithKillswitch));
ASSERT_TRUE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingExperimental));
ASSERT_TRUE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingUnsafeExperimental));
// Unimplemented features are not present.
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingUnimplemented));
// Non-existent features are not present.
ASSERT_FALSE(instance.HasWGSLLanguageFeature(kNonExistentFeature));
}
// Check HasFeature for an Instance that doesn't have the expose_wgsl_testing_features toggle.
TEST_F(WGSLFeatureValidationTest, HasFeatureWithoutExposeWGSLTestingFeatures) {
SetUp({.useTestingFeatures = false});
// None of the testing features are present.
ASSERT_FALSE(
instance.HasWGSLLanguageFeature(wgpu::WGSLLanguageFeatureName::ChromiumTestingShipped));
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingShippedWithKillswitch));
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingExperimental));
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingUnsafeExperimental));
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingUnimplemented));
}
// Tests for the behavior of getting WGSL language features.
TEST_F(WGSLFeatureValidationTest, GetFeatures) {
SetUp({});
wgpu::SupportedWGSLLanguageFeatures supportedFeatures = {};
instance.GetWGSLLanguageFeatures(&supportedFeatures);
ASSERT_NE(0u, supportedFeatures.featureCount);
const wgpu::WGSLLanguageFeatureName* features = supportedFeatures.features;
// Exactly featureCount features should be written, and all return true in HasWGSLFeature.
for (size_t i = 0; i < supportedFeatures.featureCount; i++) {
ASSERT_TRUE(instance.HasWGSLLanguageFeature(features[i]));
}
// Test the presence / absence of some known testing features.
const wgpu::WGSLLanguageFeatureName* begin = features;
const wgpu::WGSLLanguageFeatureName* end = features + supportedFeatures.featureCount;
ASSERT_NE(std::find(begin, end, wgpu::WGSLLanguageFeatureName::ChromiumTestingShipped), end);
ASSERT_NE(
std::find(begin, end, wgpu::WGSLLanguageFeatureName::ChromiumTestingShippedWithKillswitch),
end);
ASSERT_EQ(std::find(begin, end, wgpu::WGSLLanguageFeatureName::ChromiumTestingUnimplemented),
end);
ASSERT_EQ(
std::find(begin, end, wgpu::WGSLLanguageFeatureName::ChromiumTestingUnsafeExperimental),
end);
ASSERT_EQ(std::find(begin, end, wgpu::WGSLLanguageFeatureName::ChromiumTestingExperimental),
end);
}
// Check that the enabled / disabled features are used to validate the WGSL shaders.
TEST_F(WGSLFeatureValidationTest, UsingFeatureInShaderModule) {
SetUp({});
utils::CreateShaderModule(device, R"(
requires chromium_testing_shipped;
)");
utils::CreateShaderModule(device, R"(
requires chromium_testing_shipped_with_killswitch;
)");
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, R"(
requires chromium_testing_unimplemented;
)"));
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, R"(
requires chromium_testing_unsafe_experimental;
)"));
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, R"(
requires chromium_testing_experimental;
)"));
}
// Test using DawnWGSLBlocklist to block features with a killswitch by name.
TEST_F(WGSLFeatureValidationTest, BlockListOfKillswitchedFeatures) {
SetUp({.allowUnsafeAPIs = true, .blocklist = {"chromium_testing_shipped_with_killswitch"}});
// The blocklisted feature is not present.
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingShippedWithKillswitch));
// The others are.
ASSERT_TRUE(
instance.HasWGSLLanguageFeature(wgpu::WGSLLanguageFeatureName::ChromiumTestingShipped));
ASSERT_TRUE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingExperimental));
ASSERT_TRUE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingUnsafeExperimental));
// Using the blocklisted extension fails.
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, R"(
requires chromium_testing_shipped_with_killswitch;
)"));
}
// Test that DawnWGSLBlocklist can block any feature name (even without a killswitch).
TEST_F(WGSLFeatureValidationTest, BlockListOfAnyFeature) {
SetUp({.allowUnsafeAPIs = true,
.blocklist = {"chromium_testing_shipped", "chromium_testing_experimental",
"chromium_testing_unsafe_experimental"}});
// All blocklisted features aren't present.
ASSERT_FALSE(
instance.HasWGSLLanguageFeature(wgpu::WGSLLanguageFeatureName::ChromiumTestingShipped));
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingExperimental));
ASSERT_FALSE(instance.HasWGSLLanguageFeature(
wgpu::WGSLLanguageFeatureName::ChromiumTestingUnsafeExperimental));
}
// Test that DawnWGSLBlocklist can contain garbage names without causing problems.
TEST_F(WGSLFeatureValidationTest, BlockListGarbageName) {
SetUp({.blocklist = {"LE_GARBAGE"}});
ASSERT_NE(instance, nullptr);
}
} // anonymous namespace
} // namespace dawn