Add support for first and either sampling parameter
This adds support for `@interpolate(flat, first)` and
`@interpolate(first, either)`. If no sampling parameter
is provided it's assumed to be 'first'. 'first' is not
allowed in compat mode.
Bug: 340278447
Change-Id: Ic18ffc6680470f485e6c0da220f05f01cf0fb786
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/195234
Commit-Queue: Gregg Tavares <gman@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/dawn/native/BlitBufferToDepthStencil.cpp b/src/dawn/native/BlitBufferToDepthStencil.cpp
index 9ee91f7..c6bf28a 100644
--- a/src/dawn/native/BlitBufferToDepthStencil.cpp
+++ b/src/dawn/native/BlitBufferToDepthStencil.cpp
@@ -101,7 +101,7 @@
@group(0) @binding(1) var<uniform> params : Params;
struct VertexOutputs {
- @location(0) @interpolate(flat) stencil_val : u32,
+ @location(0) @interpolate(flat, either) stencil_val : u32,
@builtin(position) position : vec4f,
};
diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp
index c0c3672..2c0fcba 100644
--- a/src/dawn/native/ShaderModule.cpp
+++ b/src/dawn/native/ShaderModule.cpp
@@ -307,6 +307,10 @@
return InterpolationSampling::Centroid;
case tint::inspector::InterpolationSampling::kSample:
return InterpolationSampling::Sample;
+ case tint::inspector::InterpolationSampling::kFirst:
+ return InterpolationSampling::First;
+ case tint::inspector::InterpolationSampling::kEither:
+ return InterpolationSampling::Either;
case tint::inspector::InterpolationSampling::kUnknown:
return DAWN_VALIDATION_ERROR(
"Attempted to convert 'Unknown' interpolation sampling type from Tint");
diff --git a/src/dawn/native/ShaderModule.h b/src/dawn/native/ShaderModule.h
index d703e5c..6dff012 100644
--- a/src/dawn/native/ShaderModule.h
+++ b/src/dawn/native/ShaderModule.h
@@ -92,6 +92,8 @@
Center,
Centroid,
Sample,
+ First,
+ Either,
};
enum class PixelLocalMemberType {
diff --git a/src/dawn/native/webgpu_absl_format.cpp b/src/dawn/native/webgpu_absl_format.cpp
index 2165c40..f8226f9 100644
--- a/src/dawn/native/webgpu_absl_format.cpp
+++ b/src/dawn/native/webgpu_absl_format.cpp
@@ -647,6 +647,12 @@
case InterpolationSampling::Sample:
s->Append("Sample");
break;
+ case InterpolationSampling::First:
+ s->Append("First");
+ break;
+ case InterpolationSampling::Either:
+ s->Append("Either");
+ break;
}
return {true};
}
diff --git a/src/dawn/tests/end2end/FirstIndexOffsetTests.cpp b/src/dawn/tests/end2end/FirstIndexOffsetTests.cpp
index b186235..c710aad 100644
--- a/src/dawn/tests/end2end/FirstIndexOffsetTests.cpp
+++ b/src/dawn/tests/end2end/FirstIndexOffsetTests.cpp
@@ -117,6 +117,10 @@
CheckIndex checkIndex,
uint32_t firstVertex,
uint32_t firstInstance) {
+ // Compatibility mode does not support @interpolate(flat, first).
+ // It only supports @interpolate(flat, either).
+ DAWN_TEST_UNSUPPORTED_IF(IsCompatibilityMode());
+
using wgpu::operator&;
std::stringstream vertexInputs;
diff --git a/src/dawn/tests/end2end/ShaderTests.cpp b/src/dawn/tests/end2end/ShaderTests.cpp
index 87986da..05974b5 100644
--- a/src/dawn/tests/end2end/ShaderTests.cpp
+++ b/src/dawn/tests/end2end/ShaderTests.cpp
@@ -1220,10 +1220,10 @@
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
struct ShaderIO {
@location(1) var1: f32,
- @location(3) @interpolate(flat) var3: u32,
- @location(5) @interpolate(flat) var5: i32,
+ @location(3) @interpolate(flat, either) var3: u32,
+ @location(5) @interpolate(flat, either) var5: i32,
@location(7) var7: f32,
- @location(9) @interpolate(flat) var9: u32,
+ @location(9) @interpolate(flat, either) var9: u32,
@builtin(position) pos: vec4f,
}
@@ -1247,7 +1247,7 @@
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
struct ShaderIO {
- @location(3) @interpolate(flat) var3: u32,
+ @location(3) @interpolate(flat, either) var3: u32,
@location(7) var7: f32,
}
diff --git a/src/dawn/tests/unittests/validation/CompatValidationTests.cpp b/src/dawn/tests/unittests/validation/CompatValidationTests.cpp
index fec272f..48a1cb2 100644
--- a/src/dawn/tests/unittests/validation/CompatValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/CompatValidationTests.cpp
@@ -236,8 +236,7 @@
TEST_F(CompatValidationTest, CanNotUseShaderWithUnsupportedInterpolateTypeOrSampling) {
static const char* interpolateParams[] = {
"perspective", // should pass
- "linear",
- "perspective, sample",
+ "linear", "perspective, sample", "flat", "flat, first",
};
for (auto interpolateParam : interpolateParams) {
auto wgsl = absl::StrFormat(R"(
diff --git a/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp b/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
index 68e4a3b..abba2a3 100644
--- a/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
@@ -2028,7 +2028,8 @@
std::string interfaceDeclaration;
{
std::ostringstream sstream;
- sstream << "struct A { @location(0) @interpolate(flat) a: " << kTypes[i] << ",\n";
+ sstream << "struct A { @location(0) @interpolate(flat, either) a: " << kTypes[i]
+ << ",\n";
interfaceDeclaration = sstream.str();
}
@@ -2084,22 +2085,25 @@
Center,
Centroid,
Sample,
+ First,
+ Either,
Count,
};
constexpr std::array<const char*, static_cast<size_t>(InterpolationType::Count)>
kInterpolationTypeString = {{"", "perspective", "linear", "flat"}};
constexpr std::array<const char*, static_cast<size_t>(InterpolationSampling::Count)>
- kInterpolationSamplingString = {{"", "center", "centroid", "sample"}};
+ kInterpolationSamplingString = {{"", "center", "centroid", "sample", "first", "either"}};
struct InterpolationAttribute {
InterpolationType interpolationType;
InterpolationSampling interpolationSampling;
};
- // Interpolation sampling is not used with flat interpolation.
- constexpr std::array<InterpolationAttribute, 10> validInterpolationAttributes = {{
+ constexpr std::array<InterpolationAttribute, 12> validInterpolationAttributes = {{
{InterpolationType::None, InterpolationSampling::None},
{InterpolationType::Flat, InterpolationSampling::None},
+ {InterpolationType::Flat, InterpolationSampling::First},
+ {InterpolationType::Flat, InterpolationSampling::Either},
{InterpolationType::Linear, InterpolationSampling::None},
{InterpolationType::Linear, InterpolationSampling::Center},
{InterpolationType::Linear, InterpolationSampling::Centroid},
@@ -2176,6 +2180,9 @@
break;
case InterpolationType::Flat:
+ if (appliedAttribute.interpolationSampling == InterpolationSampling::None) {
+ appliedAttribute.interpolationSampling = InterpolationSampling::First;
+ }
break;
default:
DAWN_UNREACHABLE();
diff --git a/src/tint/cmd/common/helper.cc b/src/tint/cmd/common/helper.cc
index 0a92cc4..ffe4dc9 100644
--- a/src/tint/cmd/common/helper.cc
+++ b/src/tint/cmd/common/helper.cc
@@ -555,6 +555,10 @@
return "centroid";
case tint::inspector::InterpolationSampling::kSample:
return "sample";
+ case tint::inspector::InterpolationSampling::kFirst:
+ return "first";
+ case tint::inspector::InterpolationSampling::kEither:
+ return "either";
}
return "unknown";
}
diff --git a/src/tint/cmd/fuzz/wgsl/dictionary.txt b/src/tint/cmd/fuzz/wgsl/dictionary.txt
index 1f893aa..7f7d75b 100644
--- a/src/tint/cmd/fuzz/wgsl/dictionary.txt
+++ b/src/tint/cmd/fuzz/wgsl/dictionary.txt
@@ -199,6 +199,7 @@
"dpdyCoarse"
"dpdyFine"
"dual_source_blending"
+"either"
"elements"
"else"
"enable"
@@ -212,6 +213,7 @@
"faceForward"
"fallthrough"
"false"
+"first"
"firstLeadingBit"
"firstTrailingBit"
"flat"
diff --git a/src/tint/lang/core/core.def b/src/tint/lang/core/core.def
index dce777d..aa7bc09 100644
--- a/src/tint/lang/core/core.def
+++ b/src/tint/lang/core/core.def
@@ -77,6 +77,8 @@
center
centroid
sample
+ first
+ either
}
enum builtin_type {
diff --git a/src/tint/lang/core/interpolation_sampling.cc b/src/tint/lang/core/interpolation_sampling.cc
index 7f6930c..ba37004 100644
--- a/src/tint/lang/core/interpolation_sampling.cc
+++ b/src/tint/lang/core/interpolation_sampling.cc
@@ -51,6 +51,12 @@
if (str == "centroid") {
return InterpolationSampling::kCentroid;
}
+ if (str == "either") {
+ return InterpolationSampling::kEither;
+ }
+ if (str == "first") {
+ return InterpolationSampling::kFirst;
+ }
if (str == "sample") {
return InterpolationSampling::kSample;
}
@@ -65,6 +71,10 @@
return "center";
case InterpolationSampling::kCentroid:
return "centroid";
+ case InterpolationSampling::kEither:
+ return "either";
+ case InterpolationSampling::kFirst:
+ return "first";
case InterpolationSampling::kSample:
return "sample";
}
diff --git a/src/tint/lang/core/interpolation_sampling.h b/src/tint/lang/core/interpolation_sampling.h
index ca7e075..014c207 100644
--- a/src/tint/lang/core/interpolation_sampling.h
+++ b/src/tint/lang/core/interpolation_sampling.h
@@ -49,6 +49,8 @@
kUndefined,
kCenter,
kCentroid,
+ kEither,
+ kFirst,
kSample,
};
@@ -71,9 +73,7 @@
InterpolationSampling ParseInterpolationSampling(std::string_view str);
constexpr std::string_view kInterpolationSamplingStrings[] = {
- "center",
- "centroid",
- "sample",
+ "center", "centroid", "either", "first", "sample",
};
} // namespace tint::core
diff --git a/src/tint/lang/core/interpolation_sampling_bench.cc b/src/tint/lang/core/interpolation_sampling_bench.cc
index c3da1ea..460a150 100644
--- a/src/tint/lang/core/interpolation_sampling_bench.cc
+++ b/src/tint/lang/core/interpolation_sampling_bench.cc
@@ -44,9 +44,11 @@
void InterpolationSamplingParser(::benchmark::State& state) {
const char* kStrings[] = {
- "ccnter", "c3r", "centeV", "center", "1enter", "cnqqer", "centll77",
- "qqenrppHid", "cntov", "cenGoid", "centroid", "ceviiroid", "ceWWtro8d", "cxxtMoid",
- "saXggl", "Xmle", "sam3le", "sample", "sEmple", "amTTlPP", "ddamxxl",
+ "ccnter", "c3r", "centeV", "center", "1enter", "cnqqer", "centll77",
+ "qqenrppHid", "cntov", "cenGoid", "centroid", "ceviiroid", "ceWWtro8d", "cxxtMoid",
+ "eiXgge", "Xter", "eit3er", "either", "eEther", "itTTePP", "dditxxe",
+ "f44rst", "fiVVSSt", "22RRt", "first", "fFst", "firt", "ROOHVt",
+ "saypl", "snnm77lrre", "004mple", "sample", "spoo", "amzze", "1implpp",
};
for (auto _ : state) {
for (auto* str : kStrings) {
diff --git a/src/tint/lang/core/interpolation_sampling_test.cc b/src/tint/lang/core/interpolation_sampling_test.cc
index 6d658b2..52d0168 100644
--- a/src/tint/lang/core/interpolation_sampling_test.cc
+++ b/src/tint/lang/core/interpolation_sampling_test.cc
@@ -58,8 +58,8 @@
}
static constexpr Case kValidCases[] = {
- {"center", InterpolationSampling::kCenter},
- {"centroid", InterpolationSampling::kCentroid},
+ {"center", InterpolationSampling::kCenter}, {"centroid", InterpolationSampling::kCentroid},
+ {"either", InterpolationSampling::kEither}, {"first", InterpolationSampling::kFirst},
{"sample", InterpolationSampling::kSample},
};
@@ -70,9 +70,15 @@
{"1entroid", InterpolationSampling::kUndefined},
{"enJrqqid", InterpolationSampling::kUndefined},
{"llen77roid", InterpolationSampling::kUndefined},
- {"sapppHHe", InterpolationSampling::kUndefined},
- {"cam", InterpolationSampling::kUndefined},
- {"sbGpl", InterpolationSampling::kUndefined},
+ {"eipphHHr", InterpolationSampling::kUndefined},
+ {"cit", InterpolationSampling::kUndefined},
+ {"ebGhe", InterpolationSampling::kUndefined},
+ {"fivist", InterpolationSampling::kUndefined},
+ {"fi8WWt", InterpolationSampling::kUndefined},
+ {"Mxxrs", InterpolationSampling::kUndefined},
+ {"saXggl", InterpolationSampling::kUndefined},
+ {"Xmle", InterpolationSampling::kUndefined},
+ {"sam3le", InterpolationSampling::kUndefined},
};
using InterpolationSamplingParseTest = testing::TestWithParam<Case>;
diff --git a/src/tint/lang/core/ir/binary/decode.cc b/src/tint/lang/core/ir/binary/decode.cc
index 8f1006f..96e4154 100644
--- a/src/tint/lang/core/ir/binary/decode.cc
+++ b/src/tint/lang/core/ir/binary/decode.cc
@@ -1315,6 +1315,10 @@
return core::InterpolationSampling::kCentroid;
case pb::InterpolationSampling::sample:
return core::InterpolationSampling::kSample;
+ case pb::InterpolationSampling::first:
+ return core::InterpolationSampling::kFirst;
+ case pb::InterpolationSampling::either:
+ return core::InterpolationSampling::kEither;
case pb::InterpolationSampling::InterpolationSampling_INT_MIN_SENTINEL_DO_NOT_USE_:
case pb::InterpolationSampling::InterpolationSampling_INT_MAX_SENTINEL_DO_NOT_USE_:
diff --git a/src/tint/lang/core/ir/binary/encode.cc b/src/tint/lang/core/ir/binary/encode.cc
index 25583b0..b1dc1e4 100644
--- a/src/tint/lang/core/ir/binary/encode.cc
+++ b/src/tint/lang/core/ir/binary/encode.cc
@@ -847,6 +847,10 @@
return pb::InterpolationSampling::centroid;
case core::InterpolationSampling::kSample:
return pb::InterpolationSampling::sample;
+ case core::InterpolationSampling::kFirst:
+ return pb::InterpolationSampling::first;
+ case core::InterpolationSampling::kEither:
+ return pb::InterpolationSampling::either;
case core::InterpolationSampling::kUndefined:
break;
}
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
index 434850a..9e5b52f 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -2150,6 +2150,8 @@
break;
case core::InterpolationSampling::kSample:
case core::InterpolationSampling::kCenter:
+ case core::InterpolationSampling::kFirst:
+ case core::InterpolationSampling::kEither:
case core::InterpolationSampling::kUndefined:
break;
}
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
index 97c61da..93c9b1c 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
@@ -3576,6 +3576,8 @@
modifiers += "sample ";
break;
case core::InterpolationSampling::kCenter:
+ case core::InterpolationSampling::kFirst:
+ case core::InterpolationSampling::kEither:
case core::InterpolationSampling::kUndefined:
break;
}
diff --git a/src/tint/lang/hlsl/writer/printer/printer.cc b/src/tint/lang/hlsl/writer/printer/printer.cc
index 485986a..f45410d 100644
--- a/src/tint/lang/hlsl/writer/printer/printer.cc
+++ b/src/tint/lang/hlsl/writer/printer/printer.cc
@@ -1502,6 +1502,8 @@
modifiers += "sample ";
break;
case core::InterpolationSampling::kCenter:
+ case core::InterpolationSampling::kFirst:
+ case core::InterpolationSampling::kEither:
case core::InterpolationSampling::kUndefined:
break;
}
diff --git a/src/tint/lang/msl/writer/common/printer_support.cc b/src/tint/lang/msl/writer/common/printer_support.cc
index 2f9bfa0..d3dbba0 100644
--- a/src/tint/lang/msl/writer/common/printer_support.cc
+++ b/src/tint/lang/msl/writer/common/printer_support.cc
@@ -101,6 +101,9 @@
attr = "center_";
}
break;
+ case core::InterpolationSampling::kFirst:
+ case core::InterpolationSampling::kEither:
+ break;
}
switch (type) {
case core::InterpolationType::kPerspective:
diff --git a/src/tint/lang/spirv/writer/ast_printer/builder.cc b/src/tint/lang/spirv/writer/ast_printer/builder.cc
index 1d925a2..a0d6f98 100644
--- a/src/tint/lang/spirv/writer/ast_printer/builder.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/builder.cc
@@ -4095,6 +4095,8 @@
module_.PushAnnot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationSample)});
break;
case core::InterpolationSampling::kCenter:
+ case core::InterpolationSampling::kFirst:
+ case core::InterpolationSampling::kEither:
case core::InterpolationSampling::kUndefined:
break;
}
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index a827c98..272c251 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -2040,6 +2040,8 @@
module_.PushAnnot(spv::Op::OpDecorate, {id, U32Operand(SpvDecorationSample)});
break;
case core::InterpolationSampling::kCenter:
+ case core::InterpolationSampling::kFirst:
+ case core::InterpolationSampling::kEither:
case core::InterpolationSampling::kUndefined:
break;
}
diff --git a/src/tint/lang/wgsl/inspector/entry_point.h b/src/tint/lang/wgsl/inspector/entry_point.h
index 3946e63..50b380b 100644
--- a/src/tint/lang/wgsl/inspector/entry_point.h
+++ b/src/tint/lang/wgsl/inspector/entry_point.h
@@ -70,7 +70,15 @@
enum class InterpolationType : uint8_t { kPerspective, kLinear, kFlat, kUnknown };
/// Type of interpolation sampling of a stage variable.
-enum class InterpolationSampling : uint8_t { kNone, kCenter, kCentroid, kSample, kUnknown };
+enum class InterpolationSampling : uint8_t {
+ kNone,
+ kCenter,
+ kCentroid,
+ kSample,
+ kFirst,
+ kEither,
+ kUnknown
+};
/// Reflection data about an entry point input or output.
struct StageVariable {
diff --git a/src/tint/lang/wgsl/inspector/inspector.cc b/src/tint/lang/wgsl/inspector/inspector.cc
index 1dea16a..e7bd852 100644
--- a/src/tint/lang/wgsl/inspector/inspector.cc
+++ b/src/tint/lang/wgsl/inspector/inspector.cc
@@ -662,7 +662,7 @@
stage_variable.attributes.color = color;
std::tie(stage_variable.interpolation_type, stage_variable.interpolation_sampling) =
- CalculateInterpolationData(type, attributes);
+ CalculateInterpolationData(attributes);
variables.push_back(stage_variable);
}
@@ -888,12 +888,8 @@
}
std::tuple<InterpolationType, InterpolationSampling> Inspector::CalculateInterpolationData(
- const core::type::Type* type,
VectorRef<const ast::Attribute*> attributes) const {
auto* interpolation_attribute = ast::GetAttribute<ast::InterpolateAttribute>(attributes);
- if (type->is_integer_scalar_or_vector()) {
- return {InterpolationType::kFlat, InterpolationSampling::kNone};
- }
if (!interpolation_attribute) {
return {InterpolationType::kPerspective, InterpolationSampling::kCenter};
@@ -912,9 +908,12 @@
->Value();
}
- if (ast_interpolation_type != core::InterpolationType::kFlat &&
- ast_sampling_type == core::InterpolationSampling::kUndefined) {
- ast_sampling_type = core::InterpolationSampling::kCenter;
+ if (ast_sampling_type == core::InterpolationSampling::kUndefined) {
+ if (ast_interpolation_type == core::InterpolationType::kFlat) {
+ ast_sampling_type = core::InterpolationSampling::kFirst;
+ } else {
+ ast_sampling_type = core::InterpolationSampling::kCenter;
+ }
}
auto interpolation_type = InterpolationType::kUnknown;
@@ -946,6 +945,12 @@
case core::InterpolationSampling::kSample:
sampling_type = InterpolationSampling::kSample;
break;
+ case core::InterpolationSampling::kFirst:
+ sampling_type = InterpolationSampling::kFirst;
+ break;
+ case core::InterpolationSampling::kEither:
+ sampling_type = InterpolationSampling::kEither;
+ break;
}
return {interpolation_type, sampling_type};
diff --git a/src/tint/lang/wgsl/inspector/inspector.h b/src/tint/lang/wgsl/inspector/inspector.h
index bcadfa3..6e4dca8 100644
--- a/src/tint/lang/wgsl/inspector/inspector.h
+++ b/src/tint/lang/wgsl/inspector/inspector.h
@@ -262,11 +262,9 @@
/// Constructs |sampler_targets_| if it hasn't already been instantiated.
void GenerateSamplerTargets();
- /// @param type the type of the parameter or structure member
/// @param attributes attributes associated with the parameter or structure member
/// @returns the interpolation type and sampling modes for the value
std::tuple<InterpolationType, InterpolationSampling> CalculateInterpolationData(
- const core::type::Type* type,
VectorRef<const ast::Attribute*> attributes) const;
/// @param func the root function of the callgraph to consider for the computation.
diff --git a/src/tint/lang/wgsl/inspector/inspector_test.cc b/src/tint/lang/wgsl/inspector/inspector_test.cc
index ca4c4cb..9ba40fc 100644
--- a/src/tint/lang/wgsl/inspector/inspector_test.cc
+++ b/src/tint/lang/wgsl/inspector/inspector_test.cc
@@ -595,7 +595,7 @@
EXPECT_EQ("in_var4", result[0].input_variables[2].variable_name);
EXPECT_EQ(std::nullopt, result[0].input_variables[2].attributes.location);
EXPECT_EQ(2u, result[0].input_variables[2].attributes.color);
- EXPECT_EQ(InterpolationType::kFlat, result[0].input_variables[2].interpolation_type);
+ EXPECT_EQ(InterpolationType::kPerspective, result[0].input_variables[2].interpolation_type);
EXPECT_EQ(ComponentType::kU32, result[0].input_variables[2].component_type);
ASSERT_EQ(1u, result[0].output_variables.size());
@@ -1727,7 +1727,13 @@
InterpolationType::kLinear, InterpolationSampling::kCenter},
InspectorGetEntryPointInterpolateTestParams{
core::InterpolationType::kFlat, core::InterpolationSampling::kUndefined,
- InterpolationType::kFlat, InterpolationSampling::kNone}));
+ InterpolationType::kFlat, InterpolationSampling::kFirst},
+ InspectorGetEntryPointInterpolateTestParams{
+ core::InterpolationType::kFlat, core::InterpolationSampling::kFirst,
+ InterpolationType::kFlat, InterpolationSampling::kFirst},
+ InspectorGetEntryPointInterpolateTestParams{
+ core::InterpolationType::kFlat, core::InterpolationSampling::kEither,
+ InterpolationType::kFlat, InterpolationSampling::kEither}));
TEST_F(InspectorGetOverrideDefaultValuesTest, Bool) {
GlobalConst("C", Expr(true));
diff --git a/src/tint/lang/wgsl/reader/parser/variable_attribute_test.cc b/src/tint/lang/wgsl/reader/parser/variable_attribute_test.cc
index bc930e7..025399f 100644
--- a/src/tint/lang/wgsl/reader/parser/variable_attribute_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/variable_attribute_test.cc
@@ -325,6 +325,38 @@
EXPECT_EQ(interp->sampling, nullptr);
}
+TEST_F(WGSLParserTest, Attribute_Interpolate_Flat_First) {
+ auto p = parser("interpolate(flat, first)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr);
+ auto* var_attr = attr.value->As<ast::Attribute>();
+ ASSERT_NE(var_attr, nullptr);
+ ASSERT_FALSE(p->has_error());
+ ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
+
+ auto* interp = var_attr->As<ast::InterpolateAttribute>();
+ ast::CheckIdentifier(interp->type, "flat");
+ ast::CheckIdentifier(interp->sampling, "first");
+}
+
+TEST_F(WGSLParserTest, Attribute_Interpolate_Either) {
+ auto p = parser("interpolate(flat, either)");
+ auto attr = p->attribute();
+ EXPECT_TRUE(attr.matched);
+ EXPECT_FALSE(attr.errored);
+ ASSERT_NE(attr.value, nullptr);
+ auto* var_attr = attr.value->As<ast::Attribute>();
+ ASSERT_NE(var_attr, nullptr);
+ ASSERT_FALSE(p->has_error());
+ ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
+
+ auto* interp = var_attr->As<ast::InterpolateAttribute>();
+ ast::CheckIdentifier(interp->type, "flat");
+ ast::CheckIdentifier(interp->sampling, "either");
+}
+
TEST_F(WGSLParserTest, Attribute_Interpolate_Single_TrailingComma) {
auto p = parser("interpolate(flat,)");
auto attr = p->attribute();
diff --git a/src/tint/lang/wgsl/resolver/attribute_validation_test.cc b/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
index d5eceef..ef6cac9 100644
--- a/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
@@ -2533,7 +2533,9 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
- R"(12:34 error: flat interpolation attribute must not have a sampling parameter)");
+ params.type == core::InterpolationType::kFlat
+ ? R"(12:34 error: flat interpolation can only use 'first' and 'either' sampling parameters)"
+ : R"(12:34 error: 'first' and 'either' sampling parameters can only be used with flat interpolation)");
}
}
@@ -2563,7 +2565,9 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
- R"(12:34 error: flat interpolation attribute must not have a sampling parameter)");
+ params.type == core::InterpolationType::kFlat
+ ? R"(12:34 error: flat interpolation can only use 'first' and 'either' sampling parameters)"
+ : R"(12:34 error: 'first' and 'either' sampling parameters can only be used with flat interpolation)");
}
}
@@ -2593,7 +2597,9 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
- R"(12:34 error: flat interpolation attribute must not have a sampling parameter)");
+ params.type == core::InterpolationType::kFlat
+ ? R"(12:34 error: flat interpolation can only use 'first' and 'either' sampling parameters)"
+ : R"(12:34 error: 'first' and 'either' sampling parameters can only be used with flat interpolation)");
}
}
@@ -2606,15 +2612,22 @@
Params{core::InterpolationType::kPerspective, core::InterpolationSampling::kCenter, true},
Params{core::InterpolationType::kPerspective, core::InterpolationSampling::kCentroid, true},
Params{core::InterpolationType::kPerspective, core::InterpolationSampling::kSample, true},
+ Params{core::InterpolationType::kPerspective, core::InterpolationSampling::kFirst, false},
+ Params{core::InterpolationType::kPerspective, core::InterpolationSampling::kEither, false},
+
Params{core::InterpolationType::kLinear, core::InterpolationSampling::kUndefined, true},
Params{core::InterpolationType::kLinear, core::InterpolationSampling::kCenter, true},
Params{core::InterpolationType::kLinear, core::InterpolationSampling::kCentroid, true},
Params{core::InterpolationType::kLinear, core::InterpolationSampling::kSample, true},
- // flat interpolation must not have a sampling type
+ Params{core::InterpolationType::kLinear, core::InterpolationSampling::kFirst, false},
+ Params{core::InterpolationType::kLinear, core::InterpolationSampling::kEither, false},
+
Params{core::InterpolationType::kFlat, core::InterpolationSampling::kUndefined, true},
Params{core::InterpolationType::kFlat, core::InterpolationSampling::kCenter, false},
Params{core::InterpolationType::kFlat, core::InterpolationSampling::kCentroid, false},
- Params{core::InterpolationType::kFlat, core::InterpolationSampling::kSample, false}));
+ Params{core::InterpolationType::kFlat, core::InterpolationSampling::kSample, false},
+ Params{core::InterpolationType::kFlat, core::InterpolationSampling::kFirst, true},
+ Params{core::InterpolationType::kFlat, core::InterpolationSampling::kEither, true}));
TEST_F(InterpolateTest, FragmentInput_Integer_MissingFlatInterpolation) {
Func("main", Vector{Param(Source{{12, 34}}, "a", ty.i32(), Vector{Location(0_a)})}, ty.void_(),
diff --git a/src/tint/lang/wgsl/resolver/compatibility_mode_test.cc b/src/tint/lang/wgsl/resolver/compatibility_mode_test.cc
index 28f52e9..c24821c 100644
--- a/src/tint/lang/wgsl/resolver/compatibility_mode_test.cc
+++ b/src/tint/lang/wgsl/resolver/compatibility_mode_test.cc
@@ -320,6 +320,98 @@
R"(12:34 error: use of '@interpolate(..., sample)' is not allowed in compatibility mode)");
}
+TEST_F(ResolverCompatibilityModeTest, FirstInterpolation_Parameter) {
+ // @fragment
+ // fn main(@location(1) @interpolate(flat, first) value : f32) {
+ // }
+
+ Func("main",
+ Vector{Param("value", ty.f32(),
+ Vector{
+ Location(1_i),
+ Interpolate(Source{{12, 34}}, core::InterpolationType::kFlat,
+ core::InterpolationSampling::kFirst),
+ })},
+ 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: flat interpolation must use 'either' sampling parameter in compatibility mode)");
+}
+
+TEST_F(ResolverCompatibilityModeTest, FirstInterpolation_StructMember) {
+ // struct S {
+ // @location(1) @interpolate(flat, first) value : f32,
+ // }
+
+ Structure("S", Vector{
+ Member("value", ty.f32(),
+ Vector{
+ Location(1_i),
+ Interpolate(Source{{12, 34}}, core::InterpolationType::kFlat,
+ core::InterpolationSampling::kFirst),
+ }),
+ });
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: flat interpolation must use 'either' sampling parameter in compatibility mode)");
+}
+
+TEST_F(ResolverCompatibilityModeTest, FlatNoneInterpolation_Parameter) {
+ // @fragment
+ // fn main(@location(1) @interpolate(flat) value : f32) {
+ // }
+
+ Func("main",
+ Vector{Param("value", ty.f32(),
+ Vector{
+ Location(1_i),
+ Interpolate(Source{{12, 34}}, core::InterpolationType::kFlat,
+ core::InterpolationSampling::kUndefined),
+ })},
+ 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: flat interpolation must use 'either' sampling parameter in compatibility mode)");
+}
+
+TEST_F(ResolverCompatibilityModeTest, FlatNoneInterpolation_StructMember) {
+ // struct S {
+ // @location(1) @interpolate(flat) value : f32,
+ // }
+
+ Structure("S", Vector{
+ Member("value", ty.f32(),
+ Vector{
+ Location(1_i),
+ Interpolate(Source{{12, 34}}, core::InterpolationType::kFlat,
+ core::InterpolationSampling::kUndefined),
+ }),
+ });
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: flat interpolation must use 'either' sampling parameter in compatibility mode)");
+}
+
class ResolverCompatibilityModeTest_TextureLoad : public ResolverCompatibilityModeTest {
protected:
void add_call_param(std::string name, ast::Type type, ExpressionList* call_params) {
diff --git a/src/tint/lang/wgsl/resolver/unresolved_identifier_test.cc b/src/tint/lang/wgsl/resolver/unresolved_identifier_test.cc
index c87cd04..2d9a687 100644
--- a/src/tint/lang/wgsl/resolver/unresolved_identifier_test.cc
+++ b/src/tint/lang/wgsl/resolver/unresolved_identifier_test.cc
@@ -100,7 +100,7 @@
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), R"(12:34 error: unresolved interpolation sampling 'centre'
12:34 note: Did you mean 'center'?
-Possible values: 'center', 'centroid', 'sample')");
+Possible values: 'center', 'centroid', 'either', 'first', 'sample')");
}
TEST_F(ResolverUnresolvedIdentifierSuggestions, InterpolationType) {
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index c5def01..3837147 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -1153,27 +1153,53 @@
return false;
}
- if (attr->sampling && i_type->Value() == core::InterpolationType::kFlat) {
- AddError(attr->source) << "flat interpolation attribute must not have a sampling parameter";
- return false;
- }
+ if (attr->sampling) {
+ auto s_type = sem_.AsInterpolationSampling(sem_.Get(attr->sampling))->Value();
+ bool is_first_or_either = s_type == core::InterpolationSampling::kFirst ||
+ s_type == core::InterpolationSampling::kEither;
- if (mode_ == wgsl::ValidationMode::kCompat) {
- if (i_type->Value() == core::InterpolationType::kLinear) {
- AddError(attr->source)
- << "use of '@interpolate(linear)' is not allowed in compatibility mode";
- return false;
- }
+ if (i_type->Value() == core::InterpolationType::kFlat) {
+ if (!is_first_or_either) {
+ AddError(attr->source)
+ << "flat interpolation can only use 'first' and 'either' sampling parameters";
+ return false;
+ }
+ if (mode_ == wgsl::ValidationMode::kCompat &&
+ s_type == core::InterpolationSampling::kFirst) {
+ AddError(attr->source) << "flat interpolation must use 'either' sampling parameter "
+ "in compatibility mode";
+ return false;
+ }
+ } else {
+ if (is_first_or_either) {
+ AddError(attr->source) << "'first' and 'either' sampling parameters can only be "
+ "used with flat interpolation";
+ return false;
+ }
- if (attr->sampling) {
- auto s_type = sem_.AsInterpolationSampling(sem_.Get(attr->sampling));
- if (s_type->Value() == core::InterpolationSampling::kSample) {
+ if (mode_ == wgsl::ValidationMode::kCompat &&
+ s_type == core::InterpolationSampling::kSample) {
AddError(attr->source)
<< "use of '@interpolate(..., sample)' is not allowed in compatibility mode";
return false;
}
}
+ } else {
+ if (mode_ == wgsl::ValidationMode::kCompat &&
+ i_type->Value() == core::InterpolationType::kFlat) {
+ AddError(attr->source)
+ << "flat interpolation must use 'either' sampling parameter in compatibility mode";
+ return false;
+ }
}
+
+ if (mode_ == wgsl::ValidationMode::kCompat &&
+ i_type->Value() == core::InterpolationType::kLinear) {
+ AddError(attr->source)
+ << "use of '@interpolate(linear)' is not allowed in compatibility mode";
+ return false;
+ }
+
return true;
}
diff --git a/src/tint/utils/protos/ir/ir.proto b/src/tint/utils/protos/ir/ir.proto
index a974bad..b50a5a2 100644
--- a/src/tint/utils/protos/ir/ir.proto
+++ b/src/tint/utils/protos/ir/ir.proto
@@ -487,6 +487,8 @@
center = 0;
centroid = 1;
sample = 2;
+ first = 3;
+ either = 4;
}
enum BuiltinValue {