[glsl][ir] Add `SampleMask` to ShaderIO.

This CL updates the ShaderIO polyfill for GLSL IR to support the needed
SampleMask conversions. In GLSL, the `in` mask is named
`gl_SampleMaskIn` and is an array of `i32` values. The output mask is
`gl_SampleMask` and is an array of `i32` values. The ShaderIO code is
updated to access the given arrays and bitcast the values to/from the
WGSL `u32` sample mask values.

Bug: 42251044
Change-Id: I9498a988f00d8fa8f2f4aca3a0de443643b34b56
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/208334
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/glsl/writer/raise/shader_io.cc b/src/tint/lang/glsl/writer/raise/shader_io.cc
index c1f9189..a13a9c6 100644
--- a/src/tint/lang/glsl/writer/raise/shader_io.cc
+++ b/src/tint/lang/glsl/writer/raise/shader_io.cc
@@ -124,8 +124,15 @@
         for (auto io : entries) {
             StringStream name;
 
+            const core::type::MemoryView* ptr = nullptr;
             if (io.attributes.builtin) {
                 name << GLSLBuiltinToString(*io.attributes.builtin, addrspace);
+
+                if (io.attributes.builtin == core::BuiltinValue::kSampleMask) {
+                    ptr = ty.ptr(addrspace, ty.array(ty.i32(), 1), access);
+                } else {
+                    ptr = ty.ptr(addrspace, io.type, access);
+                }
             } else {
                 name << ir.NameOf(func).Name();
 
@@ -136,10 +143,10 @@
                     }
                 }
                 name << name_suffix;
+                ptr = ty.ptr(addrspace, io.type, access);
             }
 
             // Create an IO variable and add it to the root block.
-            auto* ptr = ty.ptr(addrspace, io.type, access);
             auto* var = b.Var(name.str(), ptr);
             var->SetAttributes(io.attributes);
             ir.root_block->Append(var);
@@ -164,30 +171,27 @@
         auto* from = input_vars[idx]->Result(0);
         auto* value = builder.Load(from)->Result(0);
 
-        // TODO(dsinclair): Enable when `bitcast` is supported
-        // auto& builtin = inputs[idx].attributes.builtin;
-        // if (builtin.has_value()) {
-        //     switch (builtin.value()) {
-        //         case core::BuiltinValue::kVertexIndex:
-        //         case core::BuiltinValue::kInstanceIndex:
-        //         case core::BuiltinValue::kSampleIndex: {
-        //             // GLSL uses i32 for these, so bitcast to u32.
-        //             value = builder.Bitcast(ty.u32(), value)->Result(0);
-        //             break;
-        //         }
-        //         case core::BuiltinValue::kSampleMask: {
-        //             // gl_SampleMask is an array of i32. Retrieve the first element and
-        //             // bitcast it to u32.
-        //             auto* ptr = ty.ptr(core::AddressSpace::kOut, ty.i32(), core::Access::kWrite);
-
-        //             auto* elem = builder.Load(builder.Access(ptr, value, 0_u));
-        //             value = builder.Bitcast(ty.u32(), elem)->Result(0);
-        //             break;
-        //         }
-        //         default:
-        //             break;
-        //     }
-        // }
+        auto& builtin = inputs[idx].attributes.builtin;
+        if (builtin.has_value()) {
+            switch (builtin.value()) {
+                case core::BuiltinValue::kVertexIndex:
+                case core::BuiltinValue::kInstanceIndex:
+                case core::BuiltinValue::kSampleIndex: {
+                    // GLSL uses i32 for these, so convert to u32.
+                    value = builder.Convert(ty.u32(), value)->Result(0);
+                    break;
+                }
+                case core::BuiltinValue::kSampleMask: {
+                    // gl_SampleMaskIn is an array of i32. Retrieve the first element and
+                    // convert it to u32.
+                    auto* elem = builder.Access(ty.i32(), value, 0_u);
+                    value = builder.Convert(ty.u32(), elem)->Result(0);
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
 
         return value;
     }
@@ -201,6 +205,13 @@
 
         // Store the output to the global variable declared earlier.
         auto* to = output_vars[idx]->Result(0);
+
+        if (outputs[idx].attributes.builtin == core::BuiltinValue::kSampleMask) {
+            auto* ptr = ty.ptr(core::AddressSpace::kOut, ty.i32(), core::Access::kWrite);
+            to = builder.Access(ptr, to, 0_u)->Result(0);
+            value = builder.Convert(ty.i32(), value)->Result(0);
+        }
+
         builder.Store(to, value);
 
         if (outputs[idx].attributes.builtin == core::BuiltinValue::kPosition) {
diff --git a/src/tint/lang/glsl/writer/raise/shader_io_test.cc b/src/tint/lang/glsl/writer/raise/shader_io_test.cc
index a258636..638540f 100644
--- a/src/tint/lang/glsl/writer/raise/shader_io_test.cc
+++ b/src/tint/lang/glsl/writer/raise/shader_io_test.cc
@@ -979,7 +979,7 @@
     EXPECT_EQ(expect, str());
 }
 
-// Test that we change the type of the sample mask builtin to an array for SPIR-V.
+// Test that we change the type of the sample mask builtin to an array for GLSL
 TEST_F(GlslWriter_ShaderIOTest, SampleMask) {
     auto* str_ty = ty.Struct(mod.symbols.New("Outputs"),
                              {
@@ -1042,9 +1042,9 @@
 }
 
 $B1: {  # root
-  %gl_SampleMaskIn:ptr<__in, u32, read> = var @builtin(sample_mask)
+  %gl_SampleMaskIn:ptr<__in, array<i32, 1>, read> = var @builtin(sample_mask)
   %foo_loc0_Output:ptr<__out, f32, write> = var @location(0)
-  %gl_SampleMask:ptr<__out, u32, write> = var @builtin(sample_mask)
+  %gl_SampleMask:ptr<__out, array<i32, 1>, write> = var @builtin(sample_mask)
 }
 
 %foo_inner = func(%mask_in:u32):Outputs {
@@ -1055,12 +1055,16 @@
 }
 %foo = @fragment func():void {
   $B3: {
-    %8:u32 = load %gl_SampleMaskIn
-    %9:Outputs = call %foo_inner, %8
-    %10:f32 = access %9, 0u
-    store %foo_loc0_Output, %10
-    %11:u32 = access %9, 1u
-    store %gl_SampleMask, %11
+    %8:array<i32, 1> = load %gl_SampleMaskIn
+    %9:i32 = access %8, 0u
+    %10:u32 = convert %9
+    %11:Outputs = call %foo_inner, %10
+    %12:f32 = access %11, 0u
+    store %foo_loc0_Output, %12
+    %13:u32 = access %11, 1u
+    %14:ptr<__out, i32, write> = access %gl_SampleMask, 0u
+    %15:i32 = convert %13
+    store %14, %15
     ret
   }
 }