[spirv-reader] Add PrimitiveId support

Add support for a `PrimitiveId` in SPIR-V and map it to the experimental
chromium primitive_id feature.

Fixed: 439598372
Change-Id: Ia2f80fb67e1ead863d2a22275bd5a68d48d0e975
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/258275
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: James Price <jrprice@google.com>
Auto-Submit: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc
index 812aaa3..d79879a 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -633,6 +633,8 @@
                 return core::BuiltinValue::kClipDistances;
             case spv::BuiltIn::CullDistance:
                 return core::BuiltinValue::kCullDistance;
+            case spv::BuiltIn::PrimitiveId:
+                return core::BuiltinValue::kPrimitiveId;
             default:
                 TINT_UNIMPLEMENTED() << "unhandled SPIR-V BuiltIn: " << static_cast<uint32_t>(b);
         }
diff --git a/src/tint/lang/spirv/reader/parser/var_test.cc b/src/tint/lang/spirv/reader/parser/var_test.cc
index ada4b02..235516d 100644
--- a/src/tint/lang/spirv/reader/parser/var_test.cc
+++ b/src/tint/lang/spirv/reader/parser/var_test.cc
@@ -3362,5 +3362,71 @@
 )");
 }
 
+TEST_F(SpirvParserTest, PrimitiveId) {
+    EXPECT_IR(R"(
+               OpCapability Shader
+               OpCapability Geometry
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %main_primitive_id_Input %main_loc0_Output
+               OpExecutionMode %main OriginUpperLeft
+               OpName %main_primitive_id_Input "main_primitive_id_Input"
+               OpName %main_loc0_Output "main_loc0_Output"
+               OpName %main_inner "main_inner"
+               OpName %prim_id "prim_id"
+               OpName %main "main"
+               OpDecorate %main_primitive_id_Input Flat
+               OpDecorate %main_primitive_id_Input BuiltIn PrimitiveId
+               OpDecorate %main_loc0_Output Location 0
+       %uint = OpTypeInt 32 0
+%_ptr_Input_uint = OpTypePointer Input %uint
+%main_primitive_id_Input = OpVariable %_ptr_Input_uint Input
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%main_loc0_Output = OpVariable %_ptr_Output_v4float Output
+         %10 = OpTypeFunction %v4float %uint
+       %void = OpTypeVoid
+         %16 = OpTypeFunction %void
+ %main_inner = OpFunction %v4float None %10
+    %prim_id = OpFunctionParameter %uint
+         %11 = OpLabel
+         %12 = OpConvertUToF %float %prim_id
+         %13 = OpCompositeConstruct %v4float %12 %12 %12 %12
+               OpReturnValue %13
+               OpFunctionEnd
+       %main = OpFunction %void None %16
+         %17 = OpLabel
+         %18 = OpLoad %uint %main_primitive_id_Input None
+         %19 = OpFunctionCall %v4float %main_inner %18
+               OpStore %main_loc0_Output %19 None
+               OpReturn
+               OpFunctionEnd
+)",
+              R"(
+$B1: {  # root
+  %main_primitive_id_Input:ptr<__in, u32, read> = var undef @builtin(primitive_id)
+  %main_loc0_Output:ptr<__out, vec4<f32>, read_write> = var undef @location(0)
+}
+
+%main_inner = func(%prim_id:u32):vec4<f32> {
+  $B2: {
+    %5:f32 = spirv.convert_u_to_f<f32> %prim_id
+    %6:vec4<f32> = construct %5, %5, %5, %5
+    ret %6
+  }
+}
+%main = @fragment func():void {
+  $B3: {
+    undef = phony %main_loc0_Output
+    undef = phony %main_primitive_id_Input
+    %8:u32 = load %main_primitive_id_Input
+    %9:vec4<f32> = call %main_inner, %8
+    store %main_loc0_Output, %9
+    ret
+  }
+}
+)");
+}
+
 }  // namespace
 }  // namespace tint::spirv::reader
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index 4074579..98249c6 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -268,6 +268,10 @@
                         Enable(wgsl::Extension::kClipDistances);
                         attrs.Push(b.Builtin(core::BuiltinValue::kClipDistances));
                         break;
+                    case core::BuiltinValue::kPrimitiveId:
+                        Enable(wgsl::Extension::kChromiumExperimentalPrimitiveId);
+                        attrs.Push(b.Builtin(core::BuiltinValue::kPrimitiveId));
+                        break;
                     default:
                         TINT_UNIMPLEMENTED() << builtin.value();
                 }
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
index fdc7530..d6d4424 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
@@ -327,15 +327,17 @@
         MakeBuiltinParam(b, ty.u32(), core::BuiltinValue::kSampleIndex),
         MakeBuiltinParam(b, ty.u32(), core::BuiltinValue::kSampleMask),
         MakeBuiltinParam(b, ty.u32(), core::BuiltinValue::kSubgroupSize),
+        MakeBuiltinParam(b, ty.u32(), core::BuiltinValue::kPrimitiveId),
     });
 
     fn->Block()->Append(b.Return(fn));
 
     EXPECT_WGSL(R"(
 enable subgroups;
+enable chromium_experimental_primitive_id;
 
 @fragment
-fn f(@builtin(front_facing) v : bool, @builtin(sample_index) v_1 : u32, @builtin(sample_mask) v_2 : u32, @builtin(subgroup_size) v_3 : u32) {
+fn f(@builtin(front_facing) v : bool, @builtin(sample_index) v_1 : u32, @builtin(sample_mask) v_2 : u32, @builtin(subgroup_size) v_3 : u32, @builtin(primitive_id) v_4 : u32) {
 }
 )");
 }