[compat] Move sample_{index,mask} validation to Tint
Add a `validation_mode` enum to the WGSL reader options, and pass it
down to the WGSL validator. Set the validation mode to `kCompat` from
Dawn if compatibility mode is enabled on the device.
Remove the pipeline-time validation code from Dawn and update the unit
tests accordingly.
Fixed: 340200030
Fixed: 343033152
Change-Id: I56fe738c971b354c8cb4b14aedf13cd838e37f16
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/190782
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/dawn/native/RenderPipeline.cpp b/src/dawn/native/RenderPipeline.cpp
index 79e3c84..89ad6ac 100644
--- a/src/dawn/native/RenderPipeline.cpp
+++ b/src/dawn/native/RenderPipeline.cpp
@@ -723,16 +723,6 @@
}
if (device->IsCompatibilityMode()) {
- DAWN_INVALID_IF(
- fragmentMetadata.usesSampleMaskOutput,
- "sample_mask is not supported in compatibility mode in the fragment stage (%s, %s)",
- descriptor->module, &entryPoint);
-
- DAWN_INVALID_IF(
- fragmentMetadata.usesSampleIndex,
- "sample_index is not supported in compatibility mode in the fragment stage (%s, %s)",
- descriptor->module, &entryPoint);
-
// Check that all the color target states match.
ColorAttachmentIndex firstColorTargetIndex{};
const ColorTargetState* firstColorTargetState = nullptr;
diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp
index 6ba5f1f..719b7b2 100644
--- a/src/dawn/native/ShaderModule.cpp
+++ b/src/dawn/native/ShaderModule.cpp
@@ -348,9 +348,11 @@
ResultOrError<tint::Program> ParseWGSL(const tint::Source::File* file,
const tint::wgsl::AllowedFeatures& allowedFeatures,
+ const tint::wgsl::ValidationMode mode,
const std::vector<tint::wgsl::Extension>& internalExtensions,
OwnedCompilationMessages* outMessages) {
tint::wgsl::reader::Options options;
+ options.mode = mode;
options.allowed_features = allowedFeatures;
options.allowed_features.extensions.insert(internalExtensions.begin(),
internalExtensions.end());
@@ -774,7 +776,6 @@
totalInterStageShaderComponents += 1;
}
metadata->usesSampleMaskOutput = entryPoint.output_sample_mask_used;
- metadata->usesSampleIndex = entryPoint.sample_index_used;
if (entryPoint.sample_index_used) {
totalInterStageShaderComponents += 1;
}
@@ -1153,8 +1154,10 @@
}
tint::Program program;
+ auto validationMode = device->IsCompatibilityMode() ? tint::wgsl::ValidationMode::kCompat
+ : tint::wgsl::ValidationMode::kFull;
DAWN_TRY_ASSIGN(program, ParseWGSL(tintFile.get(), device->GetWGSLAllowedFeatures(),
- internalExtensions, outMessages));
+ validationMode, internalExtensions, outMessages));
parseResult->tintProgram = AcquireRef(new TintProgram(std::move(program), std::move(tintFile)));
diff --git a/src/dawn/native/ShaderModule.h b/src/dawn/native/ShaderModule.h
index 18ffe10..e6a8913 100644
--- a/src/dawn/native/ShaderModule.h
+++ b/src/dawn/native/ShaderModule.h
@@ -275,7 +275,6 @@
bool usesInstanceIndex = false;
bool usesNumWorkgroups = false;
bool usesSampleMaskOutput = false;
- bool usesSampleIndex = false;
bool usesVertexIndex = false;
};
diff --git a/src/dawn/tests/end2end/MaxLimitTests.cpp b/src/dawn/tests/end2end/MaxLimitTests.cpp
index 352b55b..6bbbef8 100644
--- a/src/dawn/tests/end2end/MaxLimitTests.cpp
+++ b/src/dawn/tests/end2end/MaxLimitTests.cpp
@@ -876,8 +876,9 @@
};
void DoTest(const MaxInterStageLimitTestsSpec& spec) {
- // Compat mode does not support sample index.
- DAWN_TEST_UNSUPPORTED_IF(IsCompatibilityMode() && spec.hasSampleIndex);
+ // Compat mode does not support sample index or sample mask.
+ DAWN_TEST_UNSUPPORTED_IF(IsCompatibilityMode() &&
+ (spec.hasSampleIndex || spec.hasSampleMask));
wgpu::RenderPipeline pipeline = CreateRenderPipeline(spec);
EXPECT_NE(nullptr, pipeline.Get());
diff --git a/src/dawn/tests/unittests/validation/CompatValidationTests.cpp b/src/dawn/tests/unittests/validation/CompatValidationTests.cpp
index af71bfc..3313b26 100644
--- a/src/dawn/tests/unittests/validation/CompatValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/CompatValidationTests.cpp
@@ -213,100 +213,24 @@
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&testDescriptor));
}
-TEST_F(CompatValidationTest, CanNotUseFragmentShaderWithSampleMask) {
- wgpu::ShaderModule moduleSampleMaskOutput = utils::CreateShaderModule(device, R"(
- @vertex fn vs() -> @builtin(position) vec4f {
- return vec4f(1);
- }
+TEST_F(CompatValidationTest, CanNotUseSampleMask) {
+ auto wgsl = R"(
struct Output {
@builtin(sample_mask) mask_out: u32,
@location(0) color : vec4f,
}
- @fragment fn fsWithoutSampleMaskUsage() -> @location(0) vec4f {
- return vec4f(1.0, 1.0, 1.0, 1.0);
- }
- @fragment fn fsWithSampleMaskUsage() -> Output {
- var o: Output;
- // We need to make sure this sample_mask isn't optimized out even its value equals "no op".
- o.mask_out = 0xFFFFFFFFu;
- o.color = vec4f(1.0, 1.0, 1.0, 1.0);
- return o;
- }
- )");
-
- // Check we can use a fragment shader that doesn't use sample_mask from
- // the same module as one that does.
- {
- utils::ComboRenderPipelineDescriptor descriptor;
- descriptor.vertex.module = moduleSampleMaskOutput;
- descriptor.cFragment.module = moduleSampleMaskOutput;
- descriptor.cFragment.entryPoint = "fsWithoutSampleMaskUsage";
- descriptor.multisample.count = 4;
- descriptor.multisample.alphaToCoverageEnabled = false;
-
- device.CreateRenderPipeline(&descriptor);
- }
-
- // Check we can not use a fragment shader that uses sample_mask.
- {
- utils::ComboRenderPipelineDescriptor descriptor;
- descriptor.vertex.module = moduleSampleMaskOutput;
- descriptor.cFragment.module = moduleSampleMaskOutput;
- descriptor.cFragment.entryPoint = "fsWithSampleMaskUsage";
- descriptor.multisample.count = 4;
- descriptor.multisample.alphaToCoverageEnabled = false;
-
- ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor),
- testing::HasSubstr("sample_mask"));
- }
+ )";
+ ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, wgsl), //
+ testing::HasSubstr("sample_mask"));
}
-TEST_F(CompatValidationTest, CanNotUseFragmentShaderWithSampleIndex) {
- wgpu::ShaderModule moduleSampleMaskOutput = utils::CreateShaderModule(device, R"(
- @vertex fn vs() -> @builtin(position) vec4f {
- return vec4f(1);
+TEST_F(CompatValidationTest, CanNotUseSampleIndex) {
+ auto wgsl = R"(
+ @fragment fn fsWithSampleIndexUsage(@builtin(sample_index) sNdx: u32) {
}
- struct Output {
- @location(0) color : vec4f,
- }
- @fragment fn fsWithoutSampleIndexUsage() -> @location(0) vec4f {
- return vec4f(1.0, 1.0, 1.0, 1.0);
- }
- @fragment fn fsWithSampleIndexUsage(@builtin(sample_index) sNdx: u32) -> Output {
- var o: Output;
- _ = sNdx;
- o.color = vec4f(1.0, 1.0, 1.0, 1.0);
- return o;
- }
- )");
-
- // Check we can use a fragment shader that doesn't use sample_index from
- // the same module as one that does.
- {
- utils::ComboRenderPipelineDescriptor descriptor;
- descriptor.vertex.module = moduleSampleMaskOutput;
- descriptor.vertex.entryPoint = "vs";
- descriptor.cFragment.module = moduleSampleMaskOutput;
- descriptor.cFragment.entryPoint = "fsWithoutSampleIndexUsage";
- descriptor.multisample.count = 4;
- descriptor.multisample.alphaToCoverageEnabled = false;
-
- device.CreateRenderPipeline(&descriptor);
- }
-
- // Check we can not use a fragment shader that uses sample_index.
- {
- utils::ComboRenderPipelineDescriptor descriptor;
- descriptor.vertex.module = moduleSampleMaskOutput;
- descriptor.vertex.entryPoint = "vs";
- descriptor.cFragment.module = moduleSampleMaskOutput;
- descriptor.cFragment.entryPoint = "fsWithSampleIndexUsage";
- descriptor.multisample.count = 4;
- descriptor.multisample.alphaToCoverageEnabled = false;
-
- ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor),
- testing::HasSubstr("sample_index"));
- }
+ )";
+ ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, wgsl),
+ testing::HasSubstr("sample_index"));
}
TEST_F(CompatValidationTest, CanNotUseShaderWithUnsupportedInterpolateTypeOrSampling) {
diff --git a/src/tint/lang/wgsl/common/BUILD.bazel b/src/tint/lang/wgsl/common/BUILD.bazel
index 8fee191..9612768 100644
--- a/src/tint/lang/wgsl/common/BUILD.bazel
+++ b/src/tint/lang/wgsl/common/BUILD.bazel
@@ -43,6 +43,7 @@
],
hdrs = [
"allowed_features.h",
+ "validation_mode.h",
],
deps = [
"//src/tint/lang/wgsl",
diff --git a/src/tint/lang/wgsl/common/BUILD.cmake b/src/tint/lang/wgsl/common/BUILD.cmake
index 370d725..da8e8ac 100644
--- a/src/tint/lang/wgsl/common/BUILD.cmake
+++ b/src/tint/lang/wgsl/common/BUILD.cmake
@@ -41,6 +41,7 @@
tint_add_target(tint_lang_wgsl_common lib
lang/wgsl/common/allowed_features.h
lang/wgsl/common/common.cc
+ lang/wgsl/common/validation_mode.h
)
tint_target_add_dependencies(tint_lang_wgsl_common lib
diff --git a/src/tint/lang/wgsl/common/BUILD.gn b/src/tint/lang/wgsl/common/BUILD.gn
index 7ae73aa4..74a1576 100644
--- a/src/tint/lang/wgsl/common/BUILD.gn
+++ b/src/tint/lang/wgsl/common/BUILD.gn
@@ -46,6 +46,7 @@
sources = [
"allowed_features.h",
"common.cc",
+ "validation_mode.h",
]
deps = [
"${tint_src_dir}/lang/wgsl",
diff --git a/src/tint/lang/wgsl/common/validation_mode.h b/src/tint/lang/wgsl/common/validation_mode.h
new file mode 100644
index 0000000..b08b6ae
--- /dev/null
+++ b/src/tint/lang/wgsl/common/validation_mode.h
@@ -0,0 +1,45 @@
+// Copyright 2024 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.
+
+#ifndef SRC_TINT_LANG_WGSL_COMMON_VALIDATION_MODE_H_
+#define SRC_TINT_LANG_WGSL_COMMON_VALIDATION_MODE_H_
+
+#include <cstdint>
+
+namespace tint::wgsl {
+
+/// The validation mode to use for WGSL validation.
+enum class ValidationMode : uint8_t {
+ // Validate against the full WebGPU standard.
+ kFull,
+ // Validate against WebGPU's "compatibility mode".
+ kCompat,
+};
+
+} // namespace tint::wgsl
+
+#endif // SRC_TINT_LANG_WGSL_COMMON_VALIDATION_MODE_H_
diff --git a/src/tint/lang/wgsl/reader/options.h b/src/tint/lang/wgsl/reader/options.h
index bf2208f..04399cf 100644
--- a/src/tint/lang/wgsl/reader/options.h
+++ b/src/tint/lang/wgsl/reader/options.h
@@ -29,6 +29,7 @@
#define SRC_TINT_LANG_WGSL_READER_OPTIONS_H_
#include "src/tint/lang/wgsl/common/allowed_features.h"
+#include "src/tint/lang/wgsl/common/validation_mode.h"
#include "src/tint/utils/reflection/reflection.h"
namespace tint::wgsl::reader {
@@ -38,8 +39,11 @@
/// The extensions and language features that are allowed to be used.
AllowedFeatures allowed_features{};
+ /// The validation mode to use.
+ ValidationMode mode = ValidationMode::kFull;
+
/// Reflect the fields of this class so that it can be used by tint::ForeachField().
- TINT_REFLECT(Options, allowed_features);
+ TINT_REFLECT(Options, allowed_features, mode);
};
} // namespace tint::wgsl::reader
diff --git a/src/tint/lang/wgsl/reader/reader.cc b/src/tint/lang/wgsl/reader/reader.cc
index 86bacef..a51fa32 100644
--- a/src/tint/lang/wgsl/reader/reader.cc
+++ b/src/tint/lang/wgsl/reader/reader.cc
@@ -46,7 +46,7 @@
}
Parser parser(file);
parser.Parse();
- return resolver::Resolve(parser.builder(), options.allowed_features);
+ return resolver::Resolve(parser.builder(), options.allowed_features, options.mode);
}
Result<core::ir::Module> WgslToIR(const Source::File* file, const Options& options) {
diff --git a/src/tint/lang/wgsl/resolver/BUILD.bazel b/src/tint/lang/wgsl/resolver/BUILD.bazel
index e5ea130..2d3103f 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.bazel
+++ b/src/tint/lang/wgsl/resolver/BUILD.bazel
@@ -108,6 +108,7 @@
"builtins_validation_test.cc",
"call_test.cc",
"call_validation_test.cc",
+ "compatibility_mode_test.cc",
"compound_assignment_validation_test.cc",
"compound_statement_test.cc",
"const_assert_test.cc",
diff --git a/src/tint/lang/wgsl/resolver/BUILD.cmake b/src/tint/lang/wgsl/resolver/BUILD.cmake
index 326af91..ec81eb9 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.cmake
+++ b/src/tint/lang/wgsl/resolver/BUILD.cmake
@@ -106,6 +106,7 @@
lang/wgsl/resolver/builtins_validation_test.cc
lang/wgsl/resolver/call_test.cc
lang/wgsl/resolver/call_validation_test.cc
+ lang/wgsl/resolver/compatibility_mode_test.cc
lang/wgsl/resolver/compound_assignment_validation_test.cc
lang/wgsl/resolver/compound_statement_test.cc
lang/wgsl/resolver/const_assert_test.cc
diff --git a/src/tint/lang/wgsl/resolver/BUILD.gn b/src/tint/lang/wgsl/resolver/BUILD.gn
index 6fb89d0..4062da5 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.gn
+++ b/src/tint/lang/wgsl/resolver/BUILD.gn
@@ -108,6 +108,7 @@
"builtins_validation_test.cc",
"call_test.cc",
"call_validation_test.cc",
+ "compatibility_mode_test.cc",
"compound_assignment_validation_test.cc",
"compound_statement_test.cc",
"const_assert_test.cc",
diff --git a/src/tint/lang/wgsl/resolver/compatibility_mode_test.cc b/src/tint/lang/wgsl/resolver/compatibility_mode_test.cc
new file mode 100644
index 0000000..49b96a6
--- /dev/null
+++ b/src/tint/lang/wgsl/resolver/compatibility_mode_test.cc
@@ -0,0 +1,183 @@
+// Copyright 2024 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 "src/tint/lang/wgsl/common/validation_mode.h"
+#include "src/tint/lang/wgsl/resolver/resolver.h"
+#include "src/tint/lang/wgsl/resolver/resolver_helper_test.h"
+
+#include "gmock/gmock.h"
+
+namespace tint::resolver {
+namespace {
+
+using namespace tint::core::fluent_types; // NOLINT
+using namespace tint::core::number_suffixes; // NOLINT
+
+class ResolverCompatibilityModeTest : public ResolverTest {
+ protected:
+ ResolverCompatibilityModeTest() {
+ resolver_ = std::make_unique<Resolver>(this, wgsl::AllowedFeatures::Everything(),
+ wgsl::ValidationMode::kCompat);
+ }
+};
+
+TEST_F(ResolverCompatibilityModeTest, SampleMask_Parameter) {
+ // @fragment
+ // fn main(@builtin(sample_mask) mask : u32) {
+ // }
+
+ Func("main",
+ Vector{Param("mask", ty.i32(),
+ Vector{
+ create<ast::BuiltinAttribute>({}, Expr(Source{{12, 34}}, "sample_mask")),
+ })},
+ ty.void_(), Empty,
+ Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ Vector{
+ Builtin(core::BuiltinValue::kPosition),
+ });
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: use of '@builtin(sample_mask)' is not allowed in compatibility mode)");
+}
+
+TEST_F(ResolverCompatibilityModeTest, SampleMask_ReturnValue) {
+ // @fragment
+ // fn main() -> @builtin(sample_mask) u32 {
+ // return 0;
+ // }
+
+ Func("main", Empty, ty.u32(),
+ Vector{
+ Return(0_u),
+ },
+ Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ Vector{
+ create<ast::BuiltinAttribute>({}, Expr(Source{{12, 34}}, "sample_mask")),
+ });
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: use of '@builtin(sample_mask)' is not allowed in compatibility mode)");
+}
+
+TEST_F(ResolverCompatibilityModeTest, SampleMask_StructMember) {
+ // struct S {
+ // @builtin(sample_mask) mask : u32,
+ // }
+
+ Structure(
+ "S",
+ Vector{
+ Member("mask", ty.u32(),
+ Vector{
+ create<ast::BuiltinAttribute>({}, Expr(Source{{12, 34}}, "sample_mask")),
+ }),
+ });
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: use of '@builtin(sample_mask)' is not allowed in compatibility mode)");
+}
+
+TEST_F(ResolverCompatibilityModeTest, SampleIndex_Parameter) {
+ // @fragment
+ // fn main(@builtin(sample_index) mask : u32) {
+ // }
+
+ Func("main",
+ Vector{Param("mask", ty.i32(),
+ Vector{
+ create<ast::BuiltinAttribute>({}, Expr(Source{{12, 34}}, "sample_index")),
+ })},
+ ty.void_(), Empty,
+ Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ Vector{
+ Builtin(core::BuiltinValue::kPosition),
+ });
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: use of '@builtin(sample_index)' is not allowed in compatibility mode)");
+}
+
+TEST_F(ResolverCompatibilityModeTest, SampleIndex_ReturnValue) {
+ // @fragment
+ // fn main() -> @builtin(sample_index) u32 {
+ // return 0;
+ // }
+
+ Func("main", Empty, ty.u32(),
+ Vector{
+ Return(0_u),
+ },
+ Vector{
+ Stage(ast::PipelineStage::kFragment),
+ },
+ Vector{
+ create<ast::BuiltinAttribute>({}, Expr(Source{{12, 34}}, "sample_index")),
+ });
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: use of '@builtin(sample_index)' is not allowed in compatibility mode)");
+}
+
+TEST_F(ResolverCompatibilityModeTest, SampleIndex_StructMember) {
+ // struct S {
+ // @builtin(sample_index) mask : u32,
+ // }
+
+ Structure(
+ "S",
+ Vector{
+ Member("mask", ty.u32(),
+ Vector{
+ create<ast::BuiltinAttribute>({}, Expr(Source{{12, 34}}, "sample_index")),
+ }),
+ });
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: use of '@builtin(sample_index)' is not allowed in compatibility mode)");
+}
+
+} // namespace
+} // namespace tint::resolver
diff --git a/src/tint/lang/wgsl/resolver/resolve.cc b/src/tint/lang/wgsl/resolver/resolve.cc
index 3765013..d9db3e8 100644
--- a/src/tint/lang/wgsl/resolver/resolve.cc
+++ b/src/tint/lang/wgsl/resolver/resolve.cc
@@ -33,8 +33,10 @@
namespace tint::resolver {
-Program Resolve(ProgramBuilder& builder, const wgsl::AllowedFeatures& allowed_features) {
- Resolver resolver(&builder, std::move(allowed_features));
+Program Resolve(ProgramBuilder& builder,
+ const wgsl::AllowedFeatures& allowed_features,
+ wgsl::ValidationMode mode) {
+ Resolver resolver(&builder, std::move(allowed_features), mode);
resolver.Resolve();
return Program(std::move(builder));
}
diff --git a/src/tint/lang/wgsl/resolver/resolve.h b/src/tint/lang/wgsl/resolver/resolve.h
index 3e73d80..7c958e1 100644
--- a/src/tint/lang/wgsl/resolver/resolve.h
+++ b/src/tint/lang/wgsl/resolver/resolve.h
@@ -29,6 +29,7 @@
#define SRC_TINT_LANG_WGSL_RESOLVER_RESOLVE_H_
#include "src/tint/lang/wgsl/common/allowed_features.h"
+#include "src/tint/lang/wgsl/common/validation_mode.h"
namespace tint {
class Program;
@@ -39,10 +40,11 @@
/// Performs semantic analysis and validation on the program builder @p builder
/// @param allowed_features the extensions and features that are allowed to be used
+/// @param mode the validation mode to uses
/// @returns the resolved Program. Program.Diagnostics() may contain validation errors.
-Program Resolve(
- ProgramBuilder& builder,
- const wgsl::AllowedFeatures& allowed_features = wgsl::AllowedFeatures::Everything());
+Program Resolve(ProgramBuilder& builder,
+ const wgsl::AllowedFeatures& allowed_features = wgsl::AllowedFeatures::Everything(),
+ wgsl::ValidationMode mode = wgsl::ValidationMode::kFull);
} // namespace tint::resolver
diff --git a/src/tint/lang/wgsl/resolver/resolver.cc b/src/tint/lang/wgsl/resolver/resolver.cc
index 8215747..7951c47 100644
--- a/src/tint/lang/wgsl/resolver/resolver.cc
+++ b/src/tint/lang/wgsl/resolver/resolver.cc
@@ -132,7 +132,9 @@
} // namespace
-Resolver::Resolver(ProgramBuilder* builder, const wgsl::AllowedFeatures& allowed_features)
+Resolver::Resolver(ProgramBuilder* builder,
+ const wgsl::AllowedFeatures& allowed_features,
+ wgsl::ValidationMode mode)
: b(*builder),
diagnostics_(builder->Diagnostics()),
const_eval_(builder->constants, diagnostics_),
@@ -142,6 +144,7 @@
sem_,
enabled_extensions_,
allowed_features_,
+ mode,
atomic_composite_info_,
valid_type_storage_layouts_),
allowed_features_(allowed_features) {}
diff --git a/src/tint/lang/wgsl/resolver/resolver.h b/src/tint/lang/wgsl/resolver/resolver.h
index 80394c2..e57b6ad 100644
--- a/src/tint/lang/wgsl/resolver/resolver.h
+++ b/src/tint/lang/wgsl/resolver/resolver.h
@@ -42,6 +42,7 @@
#include "src/tint/lang/core/intrinsic/table.h"
#include "src/tint/lang/core/type/input_attachment.h"
#include "src/tint/lang/wgsl/common/allowed_features.h"
+#include "src/tint/lang/wgsl/common/validation_mode.h"
#include "src/tint/lang/wgsl/intrinsic/dialect.h"
#include "src/tint/lang/wgsl/program/program_builder.h"
#include "src/tint/lang/wgsl/resolver/dependency_graph.h"
@@ -100,7 +101,10 @@
/// Constructor
/// @param builder the program builder
/// @param allowed_features the extensions and features that are allowed to be used
- explicit Resolver(ProgramBuilder* builder, const wgsl::AllowedFeatures& allowed_features);
+ /// @param mode the validation mode to use
+ Resolver(ProgramBuilder* builder,
+ const wgsl::AllowedFeatures& allowed_features,
+ wgsl::ValidationMode mode = wgsl::ValidationMode::kFull);
/// Destructor
~Resolver();
diff --git a/src/tint/lang/wgsl/resolver/resolver_helper_test.h b/src/tint/lang/wgsl/resolver/resolver_helper_test.h
index 96326a5..19f239c 100644
--- a/src/tint/lang/wgsl/resolver/resolver_helper_test.h
+++ b/src/tint/lang/wgsl/resolver/resolver_helper_test.h
@@ -132,7 +132,7 @@
/// declared in WGSL.
std::string FriendlyName(const core::type::Type* type) { return type->FriendlyName(); }
- private:
+ protected:
std::unique_ptr<Resolver> resolver_;
};
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index 75abdac..2f9951d 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -162,6 +162,7 @@
SemHelper& sem,
const wgsl::Extensions& enabled_extensions,
const wgsl::AllowedFeatures& allowed_features,
+ const wgsl::ValidationMode mode,
const Hashmap<const core::type::Type*, const Source*, 8>& atomic_composite_info,
Hashset<TypeAndAddressSpace, 8>& valid_type_storage_layouts)
: symbols_(builder->Symbols()),
@@ -169,6 +170,7 @@
sem_(sem),
enabled_extensions_(enabled_extensions),
allowed_features_(allowed_features),
+ mode_(mode),
atomic_composite_info_(atomic_composite_info),
valid_type_storage_layouts_(valid_type_storage_layouts) {
// Set default severities for filterable diagnostic rules.
@@ -1026,6 +1028,12 @@
}
break;
case core::BuiltinValue::kSampleMask:
+ if (mode_ == wgsl::ValidationMode::kCompat) {
+ AddError(attr->builtin->source) << "use of " << style::Attribute("@builtin")
+ << style::Code("(", style::Enum(builtin), ")")
+ << " is not allowed in compatibility mode";
+ return false;
+ }
if (stage != ast::PipelineStage::kNone && !(stage == ast::PipelineStage::kFragment)) {
is_stage_mismatch = true;
}
@@ -1035,6 +1043,12 @@
}
break;
case core::BuiltinValue::kSampleIndex:
+ if (mode_ == wgsl::ValidationMode::kCompat) {
+ AddError(attr->builtin->source) << "use of " << style::Attribute("@builtin")
+ << style::Code("(", style::Enum(builtin), ")")
+ << " is not allowed in compatibility mode";
+ return false;
+ }
if (stage != ast::PipelineStage::kNone &&
!(stage == ast::PipelineStage::kFragment && is_input)) {
is_stage_mismatch = true;
diff --git a/src/tint/lang/wgsl/resolver/validator.h b/src/tint/lang/wgsl/resolver/validator.h
index eff9ce6..6d624a6 100644
--- a/src/tint/lang/wgsl/resolver/validator.h
+++ b/src/tint/lang/wgsl/resolver/validator.h
@@ -37,6 +37,7 @@
#include "src/tint/lang/wgsl/ast/input_attachment_index_attribute.h"
#include "src/tint/lang/wgsl/ast/pipeline_stage.h"
#include "src/tint/lang/wgsl/common/allowed_features.h"
+#include "src/tint/lang/wgsl/common/validation_mode.h"
#include "src/tint/lang/wgsl/program/program_builder.h"
#include "src/tint/lang/wgsl/resolver/sem_helper.h"
#include "src/tint/utils/containers/hashmap.h"
@@ -118,12 +119,14 @@
/// @param helper the SEM helper to validate with
/// @param enabled_extensions all the extensions declared in current module
/// @param allowed_features the allowed extensions and features
+ /// @param mode the validation mode to use
/// @param atomic_composite_info atomic composite info of the module
/// @param valid_type_storage_layouts a set of validated type layouts by address space
Validator(ProgramBuilder* builder,
SemHelper& helper,
const wgsl::Extensions& enabled_extensions,
const wgsl::AllowedFeatures& allowed_features,
+ wgsl::ValidationMode mode,
const Hashmap<const core::type::Type*, const Source*, 8>& atomic_composite_info,
Hashset<TypeAndAddressSpace, 8>& valid_type_storage_layouts);
~Validator();
@@ -626,6 +629,7 @@
DiagnosticFilterStack diagnostic_filters_;
const wgsl::Extensions& enabled_extensions_;
const wgsl::AllowedFeatures& allowed_features_;
+ const wgsl::ValidationMode mode_;
const Hashmap<const core::type::Type*, const Source*, 8>& atomic_composite_info_;
Hashset<TypeAndAddressSpace, 8>& valid_type_storage_layouts_;
};