[sksl][compute][spirv] Support barrier intrinsics

Implement SPIR-V codegen for workgroupBarrier and storageBarrier
intrinsics.

Bug: b/262428625
Change-Id: Ic7ea45a2108258c63d2cd0396f058efaf10ff4af
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/729099
Reviewed-by: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Arman Uguray <armansito@google.com>
diff --git a/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp b/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp
index 903cc37..8eb9554 100644
--- a/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp
@@ -302,6 +302,9 @@
         case k_atomicAdd_IntrinsicKind:   return SPECIAL(AtomicAdd);
         case k_atomicLoad_IntrinsicKind:  return SPECIAL(AtomicLoad);
         case k_atomicStore_IntrinsicKind: return SPECIAL(AtomicStore);
+
+        case k_storageBarrier_IntrinsicKind:   return SPECIAL(StorageBarrier);
+        case k_workgroupBarrier_IntrinsicKind: return SPECIAL(WorkgroupBarrier);
         default:
             return Intrinsic{kInvalid_IntrinsicOpcodeKind, 0, 0, 0, 0};
     }
@@ -1662,6 +1665,25 @@
         case kAtomicStore_SpecialIntrinsic:
             result = this->writeAtomicIntrinsic(c, kind, result, out);
             break;
+        case kStorageBarrier_SpecialIntrinsic:
+        case kWorkgroupBarrier_SpecialIntrinsic: {
+            // Both barrier types operate in the workgroup execution and memory scope and differ
+            // only in memory semantics. storageBarrier() is not a device-scope barrier.
+            SpvId scopeId =
+                    this->writeOpConstant(*fContext.fTypes.fUInt, (int32_t)SpvScopeWorkgroup);
+            int32_t memSemMask = (kind == kStorageBarrier_SpecialIntrinsic)
+                                         ? SpvMemorySemanticsAcquireReleaseMask |
+                                                   SpvMemorySemanticsUniformMemoryMask
+                                         : SpvMemorySemanticsAcquireReleaseMask |
+                                                   SpvMemorySemanticsWorkgroupMemoryMask;
+            SpvId memorySemanticsId = this->writeOpConstant(*fContext.fTypes.fUInt, memSemMask);
+            this->writeInstruction(SpvOpControlBarrier,
+                                   scopeId,  // execution scope
+                                   scopeId,  // memory scope
+                                   memorySemanticsId,
+                                   out);
+            break;
+        }
     }
     return result;
 }
diff --git a/src/sksl/codegen/SkSLSPIRVCodeGenerator.h b/src/sksl/codegen/SkSLSPIRVCodeGenerator.h
index d415361..9e652ac 100644
--- a/src/sksl/codegen/SkSLSPIRVCodeGenerator.h
+++ b/src/sksl/codegen/SkSLSPIRVCodeGenerator.h
@@ -142,6 +142,8 @@
         kAtomicAdd_SpecialIntrinsic,
         kAtomicLoad_SpecialIntrinsic,
         kAtomicStore_SpecialIntrinsic,
+        kStorageBarrier_SpecialIntrinsic,
+        kWorkgroupBarrier_SpecialIntrinsic,
     };
 
     enum class Precision {
diff --git a/tests/sksl/compute/AtomicOperations.asm.comp b/tests/sksl/compute/AtomicOperations.asm.comp
index 39a2e74..0a1745c 100644
--- a/tests/sksl/compute/AtomicOperations.asm.comp
+++ b/tests/sksl/compute/AtomicOperations.asm.comp
@@ -1,9 +1,62 @@
-### Compilation failed:
-
-error: 14: unsupported intrinsic 'void workgroupBarrier()'
-    workgroupBarrier();
-    ^^^^^^^^^^^^^^^^^^
-error: 22: unsupported intrinsic 'void workgroupBarrier()'
-    workgroupBarrier();
-    ^^^^^^^^^^^^^^^^^^
-2 errors
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main" %sk_LocalInvocationID
+OpExecutionMode %main LocalSize 16 16 1
+OpName %ssbo "ssbo"
+OpMemberName %ssbo 0 "globalCounter"
+OpName %sk_LocalInvocationID "sk_LocalInvocationID"
+OpName %localCounter "localCounter"
+OpName %main "main"
+OpMemberDecorate %ssbo 0 Offset 0
+OpMemberDecorate %ssbo 0 RelaxedPrecision
+OpDecorate %ssbo BufferBlock
+OpDecorate %3 Binding 0
+OpDecorate %3 DescriptorSet 0
+OpDecorate %sk_LocalInvocationID BuiltIn LocalInvocationId
+%uint = OpTypeInt 32 0
+%ssbo = OpTypeStruct %uint
+%_ptr_Uniform_ssbo = OpTypePointer Uniform %ssbo
+%3 = OpVariable %_ptr_Uniform_ssbo Uniform
+%v3uint = OpTypeVector %uint 3
+%_ptr_Input_v3uint = OpTypePointer Input %v3uint
+%sk_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
+%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
+%localCounter = OpVariable %_ptr_Workgroup_uint Workgroup
+%void = OpTypeVoid
+%13 = OpTypeFunction %void
+%uint_0 = OpConstant %uint 0
+%bool = OpTypeBool
+%uint_2 = OpConstant %uint 2
+%uint_264 = OpConstant %uint 264
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%main = OpFunction %void None %13
+%14 = OpLabel
+%15 = OpLoad %v3uint %sk_LocalInvocationID
+%16 = OpCompositeExtract %uint %15 0
+%18 = OpIEqual %bool %16 %uint_0
+OpSelectionMerge %21 None
+OpBranchConditional %18 %20 %21
+%20 = OpLabel
+OpAtomicStore %localCounter %uint_2 %uint_0 %uint_0
+OpBranch %21
+%21 = OpLabel
+OpControlBarrier %uint_2 %uint_2 %uint_264
+%26 = OpAtomicIAdd %uint %localCounter %uint_2 %uint_0 %uint_1
+OpControlBarrier %uint_2 %uint_2 %uint_264
+%29 = OpLoad %v3uint %sk_LocalInvocationID
+%30 = OpCompositeExtract %uint %29 0
+%31 = OpIEqual %bool %30 %uint_0
+OpSelectionMerge %33 None
+OpBranchConditional %31 %32 %33
+%32 = OpLabel
+%37 = OpAccessChain %_ptr_Uniform_uint %3 %int_0
+%39 = OpAtomicLoad %uint %localCounter %uint_2 %uint_0
+%34 = OpAtomicIAdd %uint %37 %uint_1 %uint_0 %39
+OpBranch %33
+%33 = OpLabel
+OpReturn
+OpFunctionEnd
diff --git a/tests/sksl/compute/AtomicOperationsOverArrayAndStruct.asm.comp b/tests/sksl/compute/AtomicOperationsOverArrayAndStruct.asm.comp
index 4891e27..f0a3120 100644
--- a/tests/sksl/compute/AtomicOperationsOverArrayAndStruct.asm.comp
+++ b/tests/sksl/compute/AtomicOperationsOverArrayAndStruct.asm.comp
@@ -1,9 +1,94 @@
-### Compilation failed:
-
-error: 21: unsupported intrinsic 'void workgroupBarrier()'
-    workgroupBarrier();
-    ^^^^^^^^^^^^^^^^^^
-error: 30: unsupported intrinsic 'void workgroupBarrier()'
-    workgroupBarrier();
-    ^^^^^^^^^^^^^^^^^^
-2 errors
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main" %sk_LocalInvocationID
+OpExecutionMode %main LocalSize 16 16 1
+OpName %GlobalCounts "GlobalCounts"
+OpMemberName %GlobalCounts 0 "firstHalfCount"
+OpMemberName %GlobalCounts 1 "secondHalfCount"
+OpName %ssbo "ssbo"
+OpMemberName %ssbo 0 "globalCounts"
+OpName %sk_LocalInvocationID "sk_LocalInvocationID"
+OpName %localCounts "localCounts"
+OpName %main "main"
+OpName %idx "idx"
+OpMemberDecorate %GlobalCounts 0 Offset 0
+OpMemberDecorate %GlobalCounts 0 RelaxedPrecision
+OpMemberDecorate %GlobalCounts 1 Offset 4
+OpMemberDecorate %GlobalCounts 1 RelaxedPrecision
+OpMemberDecorate %ssbo 0 Offset 0
+OpMemberDecorate %ssbo 0 RelaxedPrecision
+OpDecorate %ssbo BufferBlock
+OpDecorate %3 Binding 0
+OpDecorate %3 DescriptorSet 0
+OpDecorate %sk_LocalInvocationID BuiltIn LocalInvocationId
+OpDecorate %_arr_uint_int_2 ArrayStride 16
+%uint = OpTypeInt 32 0
+%GlobalCounts = OpTypeStruct %uint %uint
+%ssbo = OpTypeStruct %GlobalCounts
+%_ptr_Uniform_ssbo = OpTypePointer Uniform %ssbo
+%3 = OpVariable %_ptr_Uniform_ssbo Uniform
+%v3uint = OpTypeVector %uint 3
+%_ptr_Input_v3uint = OpTypePointer Input %v3uint
+%sk_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input
+%int = OpTypeInt 32 1
+%int_2 = OpConstant %int 2
+%_arr_uint_int_2 = OpTypeArray %uint %int_2
+%_ptr_Workgroup__arr_uint_int_2 = OpTypePointer Workgroup %_arr_uint_int_2
+%localCounts = OpVariable %_ptr_Workgroup__arr_uint_int_2 Workgroup
+%void = OpTypeVoid
+%17 = OpTypeFunction %void
+%uint_0 = OpConstant %uint 0
+%bool = OpTypeBool
+%int_0 = OpConstant %int 0
+%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
+%uint_2 = OpConstant %uint 2
+%int_1 = OpConstant %int 1
+%uint_264 = OpConstant %uint 264
+%_ptr_Function_uint = OpTypePointer Function %uint
+%uint_512 = OpConstant %uint 512
+%uint_1 = OpConstant %uint 1
+%_ptr_Uniform_uint = OpTypePointer Uniform %uint
+%main = OpFunction %void None %17
+%18 = OpLabel
+%idx = OpVariable %_ptr_Function_uint Function
+%19 = OpLoad %v3uint %sk_LocalInvocationID
+%20 = OpCompositeExtract %uint %19 0
+%22 = OpIEqual %bool %20 %uint_0
+OpSelectionMerge %25 None
+OpBranchConditional %22 %24 %25
+%24 = OpLabel
+%28 = OpAccessChain %_ptr_Workgroup_uint %localCounts %int_0
+OpAtomicStore %28 %uint_2 %uint_0 %uint_0
+%33 = OpAccessChain %_ptr_Workgroup_uint %localCounts %int_1
+OpAtomicStore %33 %uint_2 %uint_0 %uint_0
+OpBranch %25
+%25 = OpLabel
+OpControlBarrier %uint_2 %uint_2 %uint_264
+%38 = OpLoad %v3uint %sk_LocalInvocationID
+%39 = OpCompositeExtract %uint %38 0
+%41 = OpULessThan %bool %39 %uint_512
+%42 = OpSelect %int %41 %int_0 %int_1
+%43 = OpBitcast %uint %42
+OpStore %idx %43
+%45 = OpAccessChain %_ptr_Workgroup_uint %localCounts %43
+%44 = OpAtomicIAdd %uint %45 %uint_2 %uint_0 %uint_1
+OpControlBarrier %uint_2 %uint_2 %uint_264
+%48 = OpLoad %v3uint %sk_LocalInvocationID
+%49 = OpCompositeExtract %uint %48 0
+%50 = OpIEqual %bool %49 %uint_0
+OpSelectionMerge %52 None
+OpBranchConditional %50 %51 %52
+%51 = OpLabel
+%54 = OpAccessChain %_ptr_Uniform_uint %3 %int_0 %int_0
+%57 = OpAccessChain %_ptr_Workgroup_uint %localCounts %int_0
+%56 = OpAtomicLoad %uint %57 %uint_2 %uint_0
+%53 = OpAtomicIAdd %uint %54 %uint_1 %uint_0 %56
+%59 = OpAccessChain %_ptr_Uniform_uint %3 %int_0 %int_1
+%61 = OpAccessChain %_ptr_Workgroup_uint %localCounts %int_1
+%60 = OpAtomicLoad %uint %61 %uint_2 %uint_0
+%58 = OpAtomicIAdd %uint %59 %uint_1 %uint_0 %60
+OpBranch %52
+%52 = OpLabel
+OpReturn
+OpFunctionEnd
diff --git a/tests/sksl/compute/Barrier.asm.comp b/tests/sksl/compute/Barrier.asm.comp
index 393b5cd..98619e8 100644
--- a/tests/sksl/compute/Barrier.asm.comp
+++ b/tests/sksl/compute/Barrier.asm.comp
@@ -1,9 +1,18 @@
-### Compilation failed:
-
-error: 2: unsupported intrinsic 'void workgroupBarrier()'
-    workgroupBarrier();
-    ^^^^^^^^^^^^^^^^^^
-error: 3: unsupported intrinsic 'void storageBarrier()'
-    storageBarrier();
-    ^^^^^^^^^^^^^^^^
-2 errors
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main"
+OpExecutionMode %main LocalSize 16 16 1
+OpName %main "main"
+%void = OpTypeVoid
+%4 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_2 = OpConstant %uint 2
+%uint_264 = OpConstant %uint 264
+%uint_72 = OpConstant %uint 72
+%main = OpFunction %void None %4
+%5 = OpLabel
+OpControlBarrier %uint_2 %uint_2 %uint_264
+OpControlBarrier %uint_2 %uint_2 %uint_72
+OpReturn
+OpFunctionEnd
diff --git a/tests/sksl/compute/Workgroup.asm.comp b/tests/sksl/compute/Workgroup.asm.comp
index ca63ab2..a6eb5cd 100644
--- a/tests/sksl/compute/Workgroup.asm.comp
+++ b/tests/sksl/compute/Workgroup.asm.comp
@@ -1,9 +1,162 @@
-### Compilation failed:
-
-error: 30: unsupported intrinsic 'void workgroupBarrier()'
-    workgroupBarrier();
-    ^^^^^^^^^^^^^^^^^^
-error: 42: unsupported intrinsic 'void workgroupBarrier()'
-        workgroupBarrier();
-        ^^^^^^^^^^^^^^^^^^
-2 errors
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %main "main" %sk_GlobalInvocationID
+OpExecutionMode %main LocalSize 16 16 1
+OpName %inputs "inputs"
+OpMemberName %inputs 0 "in_data"
+OpName %outputs "outputs"
+OpMemberName %outputs 0 "out_data"
+OpName %sk_GlobalInvocationID "sk_GlobalInvocationID"
+OpName %shared_data "shared_data"
+OpName %store_vIf "store_vIf"
+OpName %main "main"
+OpName %id "id"
+OpName %rd_id "rd_id"
+OpName %wr_id "wr_id"
+OpName %mask "mask"
+OpName %step "step"
+OpDecorate %_runtimearr_float ArrayStride 16
+OpMemberDecorate %inputs 0 Offset 0
+OpDecorate %inputs BufferBlock
+OpDecorate %4 Binding 0
+OpDecorate %4 DescriptorSet 0
+OpMemberDecorate %outputs 0 Offset 0
+OpDecorate %outputs BufferBlock
+OpDecorate %9 Binding 1
+OpDecorate %9 DescriptorSet 0
+OpDecorate %sk_GlobalInvocationID BuiltIn GlobalInvocationId
+OpDecorate %_arr_float_int_1024 ArrayStride 16
+%float = OpTypeFloat 32
+%_runtimearr_float = OpTypeRuntimeArray %float
+%inputs = OpTypeStruct %_runtimearr_float
+%_ptr_Uniform_inputs = OpTypePointer Uniform %inputs
+%4 = OpVariable %_ptr_Uniform_inputs Uniform
+%outputs = OpTypeStruct %_runtimearr_float
+%_ptr_Uniform_outputs = OpTypePointer Uniform %outputs
+%9 = OpVariable %_ptr_Uniform_outputs Uniform
+%uint = OpTypeInt 32 0
+%v3uint = OpTypeVector %uint 3
+%_ptr_Input_v3uint = OpTypePointer Input %v3uint
+%sk_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
+%int = OpTypeInt 32 1
+%int_1024 = OpConstant %int 1024
+%_arr_float_int_1024 = OpTypeArray %float %int_1024
+%_ptr_Workgroup__arr_float_int_1024 = OpTypePointer Workgroup %_arr_float_int_1024
+%shared_data = OpVariable %_ptr_Workgroup__arr_float_int_1024 Workgroup
+%void = OpTypeVoid
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_Function_float = OpTypePointer Function %float
+%24 = OpTypeFunction %void %_ptr_Function_uint %_ptr_Function_float
+%_ptr_Workgroup_float = OpTypePointer Workgroup %float
+%32 = OpTypeFunction %void
+%int_0 = OpConstant %int 0
+%uint_2 = OpConstant %uint 2
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%uint_1 = OpConstant %uint 1
+%uint_264 = OpConstant %uint 264
+%uint_0 = OpConstant %uint 0
+%uint_10 = OpConstant %uint 10
+%bool = OpTypeBool
+%store_vIf = OpFunction %void None %24
+%25 = OpFunctionParameter %_ptr_Function_uint
+%26 = OpFunctionParameter %_ptr_Function_float
+%27 = OpLabel
+%28 = OpLoad %float %26
+%29 = OpLoad %uint %25
+%30 = OpAccessChain %_ptr_Workgroup_float %shared_data %29
+OpStore %30 %28
+OpReturn
+OpFunctionEnd
+%main = OpFunction %void None %32
+%33 = OpLabel
+%id = OpVariable %_ptr_Function_uint Function
+%rd_id = OpVariable %_ptr_Function_uint Function
+%wr_id = OpVariable %_ptr_Function_uint Function
+%mask = OpVariable %_ptr_Function_uint Function
+%step = OpVariable %_ptr_Function_uint Function
+%85 = OpVariable %_ptr_Function_uint Function
+%91 = OpVariable %_ptr_Function_float Function
+%35 = OpLoad %v3uint %sk_GlobalInvocationID
+%36 = OpCompositeExtract %uint %35 0
+OpStore %id %36
+%42 = OpIMul %uint %36 %uint_2
+%43 = OpAccessChain %_ptr_Uniform_float %4 %int_0 %42
+%45 = OpLoad %float %43
+%46 = OpIMul %uint %36 %uint_2
+%47 = OpAccessChain %_ptr_Workgroup_float %shared_data %46
+OpStore %47 %45
+%48 = OpLoad %uint %id
+%49 = OpIMul %uint %48 %uint_2
+%51 = OpIAdd %uint %49 %uint_1
+%52 = OpAccessChain %_ptr_Uniform_float %4 %int_0 %51
+%53 = OpLoad %float %52
+%54 = OpLoad %uint %id
+%55 = OpIMul %uint %54 %uint_2
+%56 = OpIAdd %uint %55 %uint_1
+%57 = OpAccessChain %_ptr_Workgroup_float %shared_data %56
+OpStore %57 %53
+OpControlBarrier %uint_2 %uint_2 %uint_264
+OpStore %step %uint_0
+OpBranch %62
+%62 = OpLabel
+OpLoopMerge %66 %65 None
+OpBranch %63
+%63 = OpLabel
+%67 = OpLoad %uint %step
+%69 = OpULessThan %bool %67 %uint_10
+OpBranchConditional %69 %64 %66
+%64 = OpLabel
+%71 = OpLoad %uint %step
+%72 = OpShiftLeftLogical %uint %uint_1 %71
+%73 = OpISub %uint %72 %uint_1
+OpStore %mask %73
+%74 = OpLoad %uint %id
+%75 = OpLoad %uint %step
+%76 = OpShiftRightLogical %uint %74 %75
+%77 = OpLoad %uint %step
+%78 = OpIAdd %uint %77 %uint_1
+%79 = OpShiftLeftLogical %uint %76 %78
+%80 = OpIAdd %uint %79 %73
+OpStore %rd_id %80
+%81 = OpIAdd %uint %80 %uint_1
+%82 = OpLoad %uint %id
+%83 = OpBitwiseAnd %uint %82 %73
+%84 = OpIAdd %uint %81 %83
+OpStore %wr_id %84
+OpStore %85 %84
+%86 = OpAccessChain %_ptr_Workgroup_float %shared_data %84
+%87 = OpLoad %float %86
+%88 = OpAccessChain %_ptr_Workgroup_float %shared_data %80
+%89 = OpLoad %float %88
+%90 = OpFAdd %float %87 %89
+OpStore %91 %90
+%92 = OpFunctionCall %void %store_vIf %85 %91
+OpControlBarrier %uint_2 %uint_2 %uint_264
+OpBranch %65
+%65 = OpLabel
+%94 = OpLoad %uint %step
+%95 = OpIAdd %uint %94 %uint_1
+OpStore %step %95
+OpBranch %62
+%66 = OpLabel
+%96 = OpLoad %uint %id
+%97 = OpIMul %uint %96 %uint_2
+%98 = OpAccessChain %_ptr_Workgroup_float %shared_data %97
+%99 = OpLoad %float %98
+%100 = OpLoad %uint %id
+%101 = OpIMul %uint %100 %uint_2
+%102 = OpAccessChain %_ptr_Uniform_float %9 %int_0 %101
+OpStore %102 %99
+%103 = OpLoad %uint %id
+%104 = OpIMul %uint %103 %uint_2
+%105 = OpIAdd %uint %104 %uint_1
+%106 = OpAccessChain %_ptr_Workgroup_float %shared_data %105
+%107 = OpLoad %float %106
+%108 = OpLoad %uint %id
+%109 = OpIMul %uint %108 %uint_2
+%110 = OpIAdd %uint %109 %uint_1
+%111 = OpAccessChain %_ptr_Uniform_float %9 %int_0 %110
+OpStore %111 %107
+OpReturn
+OpFunctionEnd