writer/spirv: Implement interpolate attributes

Add the SampleRateShading capability if the sampling type is `sample`.

Bug: tint:746
Change-Id: I20fb25913f5c0919b6d16a9d0e9fc8b1551ff7ea
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/56247
Kokoro: Kokoro <noreply+kokoro@google.com>
Auto-Submit: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 4af004a..1c2b34e 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -842,6 +842,8 @@
       push_annot(spv::Op::OpDecorate,
                  {Operand::Int(var_id), Operand::Int(SpvDecorationLocation),
                   Operand::Int(location->value())});
+    } else if (auto* interpolate = deco->As<ast::InterpolateDecoration>()) {
+      AddInterpolationDecorations(var_id, interpolate);
     } else if (auto* binding = deco->As<ast::BindingDecoration>()) {
       push_annot(spv::Op::OpDecorate,
                  {Operand::Int(var_id), Operand::Int(SpvDecorationBinding),
@@ -3986,6 +3988,37 @@
   return SpvBuiltInMax;
 }
 
+void Builder::AddInterpolationDecorations(
+    uint32_t id,
+    ast::InterpolateDecoration* interpolate) {
+  switch (interpolate->type()) {
+    case ast::InterpolationType::kLinear:
+      push_annot(spv::Op::OpDecorate,
+                 {Operand::Int(id), Operand::Int(SpvDecorationNoPerspective)});
+      break;
+    case ast::InterpolationType::kFlat:
+      push_annot(spv::Op::OpDecorate,
+                 {Operand::Int(id), Operand::Int(SpvDecorationFlat)});
+      break;
+    case ast::InterpolationType::kPerspective:
+      break;
+  }
+  switch (interpolate->sampling()) {
+    case ast::InterpolationSampling::kCentroid:
+      push_annot(spv::Op::OpDecorate,
+                 {Operand::Int(id), Operand::Int(SpvDecorationCentroid)});
+      break;
+    case ast::InterpolationSampling::kSample:
+      push_capability(SpvCapabilitySampleRateShading);
+      push_annot(spv::Op::OpDecorate,
+                 {Operand::Int(id), Operand::Int(SpvDecorationSample)});
+      break;
+    case ast::InterpolationSampling::kCenter:
+    case ast::InterpolationSampling::kNone:
+      break;
+  }
+}
+
 SpvImageFormat Builder::convert_image_format_to_spv(
     const ast::ImageFormat format) {
   switch (format) {
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 7c9a6ac..ee1e306 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -27,6 +27,7 @@
 #include "src/ast/continue_statement.h"
 #include "src/ast/discard_statement.h"
 #include "src/ast/if_statement.h"
+#include "src/ast/interpolate_decoration.h"
 #include "src/ast/loop_statement.h"
 #include "src/ast/return_statement.h"
 #include "src/ast/switch_statement.h"
@@ -208,6 +209,13 @@
   /// @returns the SPIR-V builtin or SpvBuiltInMax on error.
   SpvBuiltIn ConvertBuiltin(ast::Builtin builtin, ast::StorageClass storage);
 
+  /// Converts an interpolate attribute to SPIR-V decorations and pushes a
+  /// capability if needed.
+  /// @param id the id to decorate
+  /// @param interpolate the interpolation attribute to convert
+  void AddInterpolationDecorations(uint32_t id,
+                                   ast::InterpolateDecoration* interpolate);
+
   /// Generates a label for the given id. Emits an error and returns false if
   /// we're currently outside a function.
   /// @param id the id to use for the label
diff --git a/test/shader_io/interpolate_input_parameters.wgsl.expected.spvasm b/test/shader_io/interpolate_input_parameters.wgsl.expected.spvasm
index ca6d27f..5b0348f 100644
--- a/test/shader_io/interpolate_input_parameters.wgsl.expected.spvasm
+++ b/test/shader_io/interpolate_input_parameters.wgsl.expected.spvasm
@@ -1,24 +1,51 @@
-SKIP: FAILED
-
-
-[[location(0), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : f32;
-
-[[location(1), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_1 : f32;
-
-[[location(2), interpolate(perspective, center), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_2 : f32;
-
-[[location(3), interpolate(perspective, centroid), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_3 : f32;
-
-[[location(4), interpolate(perspective, sample), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_4 : f32;
-
-[[location(5), interpolate(linear, center), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_5 : f32;
-
-[[location(6), interpolate(linear, centroid), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_6 : f32;
-
-[[location(7), interpolate(linear, sample), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_7 : f32;
-
-[[stage(fragment)]]
-fn main() {
-}
-
-Failed to generate: unknown decoration
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+               OpCapability Shader
+               OpCapability SampleRateShading
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpName %tint_symbol "tint_symbol"
+               OpName %tint_symbol_1 "tint_symbol_1"
+               OpName %tint_symbol_2 "tint_symbol_2"
+               OpName %tint_symbol_3 "tint_symbol_3"
+               OpName %tint_symbol_4 "tint_symbol_4"
+               OpName %tint_symbol_5 "tint_symbol_5"
+               OpName %tint_symbol_6 "tint_symbol_6"
+               OpName %tint_symbol_7 "tint_symbol_7"
+               OpName %main "main"
+               OpDecorate %tint_symbol Location 0
+               OpDecorate %tint_symbol_1 Location 1
+               OpDecorate %tint_symbol_1 Flat
+               OpDecorate %tint_symbol_2 Location 2
+               OpDecorate %tint_symbol_3 Location 3
+               OpDecorate %tint_symbol_3 Centroid
+               OpDecorate %tint_symbol_4 Location 4
+               OpDecorate %tint_symbol_4 Sample
+               OpDecorate %tint_symbol_5 Location 5
+               OpDecorate %tint_symbol_5 NoPerspective
+               OpDecorate %tint_symbol_6 Location 6
+               OpDecorate %tint_symbol_6 NoPerspective
+               OpDecorate %tint_symbol_6 Centroid
+               OpDecorate %tint_symbol_7 Location 7
+               OpDecorate %tint_symbol_7 NoPerspective
+               OpDecorate %tint_symbol_7 Sample
+      %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+%tint_symbol = OpVariable %_ptr_Input_float Input
+%tint_symbol_1 = OpVariable %_ptr_Input_float Input
+%tint_symbol_2 = OpVariable %_ptr_Input_float Input
+%tint_symbol_3 = OpVariable %_ptr_Input_float Input
+%tint_symbol_4 = OpVariable %_ptr_Input_float Input
+%tint_symbol_5 = OpVariable %_ptr_Input_float Input
+%tint_symbol_6 = OpVariable %_ptr_Input_float Input
+%tint_symbol_7 = OpVariable %_ptr_Input_float Input
+       %void = OpTypeVoid
+         %11 = OpTypeFunction %void
+       %main = OpFunction %void None %11
+         %14 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/shader_io/interpolate_input_struct.wgsl.expected.spvasm b/test/shader_io/interpolate_input_struct.wgsl.expected.spvasm
index 619801a..5b0348f 100644
--- a/test/shader_io/interpolate_input_struct.wgsl.expected.spvasm
+++ b/test/shader_io/interpolate_input_struct.wgsl.expected.spvasm
@@ -1,35 +1,51 @@
-SKIP: FAILED
-
-
-struct In {
-  none : f32;
-  flat : f32;
-  perspective_center : f32;
-  perspective_centroid : f32;
-  perspective_sample : f32;
-  linear_center : f32;
-  linear_centroid : f32;
-  linear_sample : f32;
-};
-
-[[location(0), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : f32;
-
-[[location(1), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_1 : f32;
-
-[[location(2), interpolate(perspective, center), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_2 : f32;
-
-[[location(3), interpolate(perspective, centroid), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_3 : f32;
-
-[[location(4), interpolate(perspective, sample), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_4 : f32;
-
-[[location(5), interpolate(linear, center), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_5 : f32;
-
-[[location(6), interpolate(linear, centroid), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_6 : f32;
-
-[[location(7), interpolate(linear, sample), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_7 : f32;
-
-[[stage(fragment)]]
-fn main() {
-}
-
-Failed to generate: unknown decoration
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+               OpCapability Shader
+               OpCapability SampleRateShading
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main"
+               OpExecutionMode %main OriginUpperLeft
+               OpName %tint_symbol "tint_symbol"
+               OpName %tint_symbol_1 "tint_symbol_1"
+               OpName %tint_symbol_2 "tint_symbol_2"
+               OpName %tint_symbol_3 "tint_symbol_3"
+               OpName %tint_symbol_4 "tint_symbol_4"
+               OpName %tint_symbol_5 "tint_symbol_5"
+               OpName %tint_symbol_6 "tint_symbol_6"
+               OpName %tint_symbol_7 "tint_symbol_7"
+               OpName %main "main"
+               OpDecorate %tint_symbol Location 0
+               OpDecorate %tint_symbol_1 Location 1
+               OpDecorate %tint_symbol_1 Flat
+               OpDecorate %tint_symbol_2 Location 2
+               OpDecorate %tint_symbol_3 Location 3
+               OpDecorate %tint_symbol_3 Centroid
+               OpDecorate %tint_symbol_4 Location 4
+               OpDecorate %tint_symbol_4 Sample
+               OpDecorate %tint_symbol_5 Location 5
+               OpDecorate %tint_symbol_5 NoPerspective
+               OpDecorate %tint_symbol_6 Location 6
+               OpDecorate %tint_symbol_6 NoPerspective
+               OpDecorate %tint_symbol_6 Centroid
+               OpDecorate %tint_symbol_7 Location 7
+               OpDecorate %tint_symbol_7 NoPerspective
+               OpDecorate %tint_symbol_7 Sample
+      %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+%tint_symbol = OpVariable %_ptr_Input_float Input
+%tint_symbol_1 = OpVariable %_ptr_Input_float Input
+%tint_symbol_2 = OpVariable %_ptr_Input_float Input
+%tint_symbol_3 = OpVariable %_ptr_Input_float Input
+%tint_symbol_4 = OpVariable %_ptr_Input_float Input
+%tint_symbol_5 = OpVariable %_ptr_Input_float Input
+%tint_symbol_6 = OpVariable %_ptr_Input_float Input
+%tint_symbol_7 = OpVariable %_ptr_Input_float Input
+       %void = OpTypeVoid
+         %11 = OpTypeFunction %void
+       %main = OpFunction %void None %11
+         %14 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/test/shader_io/interpolate_return_struct.wgsl.expected.spvasm b/test/shader_io/interpolate_return_struct.wgsl.expected.spvasm
index fb6b3c6..ccf9580 100644
--- a/test/shader_io/interpolate_return_struct.wgsl.expected.spvasm
+++ b/test/shader_io/interpolate_return_struct.wgsl.expected.spvasm
@@ -1,55 +1,110 @@
-SKIP: FAILED
-
-
-[[builtin(pointsize), internal(disable_validation__ignore_storage_class)]] var<out> tint_pointsize : f32;
-
-struct Out {
-  pos : vec4<f32>;
-  none : f32;
-  flat : f32;
-  perspective_center : f32;
-  perspective_centroid : f32;
-  perspective_sample : f32;
-  linear_center : f32;
-  linear_centroid : f32;
-  linear_sample : f32;
-};
-
-[[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_1 : vec4<f32>;
-
-[[location(0), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_2 : f32;
-
-[[location(1), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_3 : f32;
-
-[[location(2), interpolate(perspective, center), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_4 : f32;
-
-[[location(3), interpolate(perspective, centroid), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_5 : f32;
-
-[[location(4), interpolate(perspective, sample), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_6 : f32;
-
-[[location(5), interpolate(linear, center), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_7 : f32;
-
-[[location(6), interpolate(linear, centroid), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_8 : f32;
-
-[[location(7), interpolate(linear, sample), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_9 : f32;
-
-fn tint_symbol_10(tint_symbol : Out) {
-  tint_symbol_1 = tint_symbol.pos;
-  tint_symbol_2 = tint_symbol.none;
-  tint_symbol_3 = tint_symbol.flat;
-  tint_symbol_4 = tint_symbol.perspective_center;
-  tint_symbol_5 = tint_symbol.perspective_centroid;
-  tint_symbol_6 = tint_symbol.perspective_sample;
-  tint_symbol_7 = tint_symbol.linear_center;
-  tint_symbol_8 = tint_symbol.linear_centroid;
-  tint_symbol_9 = tint_symbol.linear_sample;
-}
-
-[[stage(vertex)]]
-fn main() {
-  tint_pointsize = 1.0;
-  tint_symbol_10(Out());
-  return;
-}
-
-Failed to generate: unknown decoration
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 38
+; Schema: 0
+               OpCapability Shader
+               OpCapability SampleRateShading
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %tint_pointsize %tint_symbol_1 %tint_symbol_2 %tint_symbol_3 %tint_symbol_4 %tint_symbol_5 %tint_symbol_6 %tint_symbol_7 %tint_symbol_8 %tint_symbol_9
+               OpName %tint_pointsize "tint_pointsize"
+               OpName %tint_symbol_1 "tint_symbol_1"
+               OpName %tint_symbol_2 "tint_symbol_2"
+               OpName %tint_symbol_3 "tint_symbol_3"
+               OpName %tint_symbol_4 "tint_symbol_4"
+               OpName %tint_symbol_5 "tint_symbol_5"
+               OpName %tint_symbol_6 "tint_symbol_6"
+               OpName %tint_symbol_7 "tint_symbol_7"
+               OpName %tint_symbol_8 "tint_symbol_8"
+               OpName %tint_symbol_9 "tint_symbol_9"
+               OpName %Out "Out"
+               OpMemberName %Out 0 "pos"
+               OpMemberName %Out 1 "none"
+               OpMemberName %Out 2 "flat"
+               OpMemberName %Out 3 "perspective_center"
+               OpMemberName %Out 4 "perspective_centroid"
+               OpMemberName %Out 5 "perspective_sample"
+               OpMemberName %Out 6 "linear_center"
+               OpMemberName %Out 7 "linear_centroid"
+               OpMemberName %Out 8 "linear_sample"
+               OpName %tint_symbol_10 "tint_symbol_10"
+               OpName %tint_symbol "tint_symbol"
+               OpName %main "main"
+               OpDecorate %tint_pointsize BuiltIn PointSize
+               OpDecorate %tint_symbol_1 BuiltIn Position
+               OpDecorate %tint_symbol_2 Location 0
+               OpDecorate %tint_symbol_3 Location 1
+               OpDecorate %tint_symbol_3 Flat
+               OpDecorate %tint_symbol_4 Location 2
+               OpDecorate %tint_symbol_5 Location 3
+               OpDecorate %tint_symbol_5 Centroid
+               OpDecorate %tint_symbol_6 Location 4
+               OpDecorate %tint_symbol_6 Sample
+               OpDecorate %tint_symbol_7 Location 5
+               OpDecorate %tint_symbol_7 NoPerspective
+               OpDecorate %tint_symbol_8 Location 6
+               OpDecorate %tint_symbol_8 NoPerspective
+               OpDecorate %tint_symbol_8 Centroid
+               OpDecorate %tint_symbol_9 Location 7
+               OpDecorate %tint_symbol_9 NoPerspective
+               OpDecorate %tint_symbol_9 Sample
+               OpMemberDecorate %Out 0 Offset 0
+               OpMemberDecorate %Out 1 Offset 16
+               OpMemberDecorate %Out 2 Offset 20
+               OpMemberDecorate %Out 3 Offset 24
+               OpMemberDecorate %Out 4 Offset 28
+               OpMemberDecorate %Out 5 Offset 32
+               OpMemberDecorate %Out 6 Offset 36
+               OpMemberDecorate %Out 7 Offset 40
+               OpMemberDecorate %Out 8 Offset 44
+      %float = OpTypeFloat 32
+%_ptr_Output_float = OpTypePointer Output %float
+          %4 = OpConstantNull %float
+%tint_pointsize = OpVariable %_ptr_Output_float Output %4
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+          %8 = OpConstantNull %v4float
+%tint_symbol_1 = OpVariable %_ptr_Output_v4float Output %8
+%tint_symbol_2 = OpVariable %_ptr_Output_float Output %4
+%tint_symbol_3 = OpVariable %_ptr_Output_float Output %4
+%tint_symbol_4 = OpVariable %_ptr_Output_float Output %4
+%tint_symbol_5 = OpVariable %_ptr_Output_float Output %4
+%tint_symbol_6 = OpVariable %_ptr_Output_float Output %4
+%tint_symbol_7 = OpVariable %_ptr_Output_float Output %4
+%tint_symbol_8 = OpVariable %_ptr_Output_float Output %4
+%tint_symbol_9 = OpVariable %_ptr_Output_float Output %4
+       %void = OpTypeVoid
+        %Out = OpTypeStruct %v4float %float %float %float %float %float %float %float %float
+         %17 = OpTypeFunction %void %Out
+         %32 = OpTypeFunction %void
+    %float_1 = OpConstant %float 1
+         %37 = OpConstantNull %Out
+%tint_symbol_10 = OpFunction %void None %17
+%tint_symbol = OpFunctionParameter %Out
+         %22 = OpLabel
+         %23 = OpCompositeExtract %v4float %tint_symbol 0
+               OpStore %tint_symbol_1 %23
+         %24 = OpCompositeExtract %float %tint_symbol 1
+               OpStore %tint_symbol_2 %24
+         %25 = OpCompositeExtract %float %tint_symbol 2
+               OpStore %tint_symbol_3 %25
+         %26 = OpCompositeExtract %float %tint_symbol 3
+               OpStore %tint_symbol_4 %26
+         %27 = OpCompositeExtract %float %tint_symbol 4
+               OpStore %tint_symbol_5 %27
+         %28 = OpCompositeExtract %float %tint_symbol 5
+               OpStore %tint_symbol_6 %28
+         %29 = OpCompositeExtract %float %tint_symbol 6
+               OpStore %tint_symbol_7 %29
+         %30 = OpCompositeExtract %float %tint_symbol 7
+               OpStore %tint_symbol_8 %30
+         %31 = OpCompositeExtract %float %tint_symbol 8
+               OpStore %tint_symbol_9 %31
+               OpReturn
+               OpFunctionEnd
+       %main = OpFunction %void None %32
+         %34 = OpLabel
+               OpStore %tint_pointsize %float_1
+         %36 = OpFunctionCall %void %tint_symbol_10 %37
+               OpReturn
+               OpFunctionEnd