Enforce that layout(binding=...) is set on interface blocks in Metal.

Previously, we would emit an invalid [[buffer(-1)]] annotation on the
block, causing the Metal compilation to fail.

Change-Id: I68b2439c05db3163686e84c5dcc9a5c43870ff67
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/340761
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
index 878bc8f..93e373f 100644
--- a/gn/sksl_tests.gni
+++ b/gn/sksl_tests.gni
@@ -180,6 +180,7 @@
   "$_tests/sksl/metal/CastMat2x3ToMat4x4.sksl",
   "$_tests/sksl/metal/CastMat4x4ToMat3x4.sksl",
   "$_tests/sksl/metal/CastMat4x4ToMat4x3.sksl",
+  "$_tests/sksl/metal/InterfaceBlocksRequireBinding.sksl",
   "$_tests/sksl/metal/NumericGlobals.sksl",
   "$_tests/sksl/metal/OpaqueTypeInInterfaceBlock.sksl",
   "$_tests/sksl/metal/OpaqueTypeInStruct.sksl",
diff --git a/src/sksl/SkSLMetalCodeGenerator.cpp b/src/sksl/SkSLMetalCodeGenerator.cpp
index c62b1ce..1ba9b3e 100644
--- a/src/sksl/SkSLMetalCodeGenerator.cpp
+++ b/src/sksl/SkSLMetalCodeGenerator.cpp
@@ -1089,6 +1089,11 @@
                 if (intf.typeName() == "sk_PerVertex") {
                     continue;
                 }
+                if (intf.variable().modifiers().fLayout.fBinding < 0) {
+                    fErrors.error(intf.fOffset,
+                                  "Metal interface blocks must have 'layout(binding=...)'");
+                    return false;
+                }
                 this->write(", constant ");
                 this->writeBaseType(intf.variable().type());
                 this->write("& " );
diff --git a/tests/sksl/metal/InterfaceBlocksRequireBinding.sksl b/tests/sksl/metal/InterfaceBlocksRequireBinding.sksl
new file mode 100644
index 0000000..daaa330
--- /dev/null
+++ b/tests/sksl/metal/InterfaceBlocksRequireBinding.sksl
@@ -0,0 +1,3 @@
+testBlock { int x; };
+
+void main() {}
diff --git a/tests/sksl/metal/golden/InterfaceBlocksRequireBinding.metal b/tests/sksl/metal/golden/InterfaceBlocksRequireBinding.metal
new file mode 100644
index 0000000..84663ba
--- /dev/null
+++ b/tests/sksl/metal/golden/InterfaceBlocksRequireBinding.metal
@@ -0,0 +1,4 @@
+### Compilation failed:
+
+error: 1: Metal interface blocks must have 'layout(binding=...)'
+1 error
diff --git a/tests/sksl/shared/InterfaceBlockAnonymous.sksl b/tests/sksl/shared/InterfaceBlockAnonymous.sksl
index c596d52a..9c21d58 100644
--- a/tests/sksl/shared/InterfaceBlockAnonymous.sksl
+++ b/tests/sksl/shared/InterfaceBlockAnonymous.sksl
@@ -1,4 +1,4 @@
-uniform testBlock {
+layout(binding=789) uniform testBlock {
     half x;
     half y[2];
     layout(binding=12) half3x2 z;
diff --git a/tests/sksl/shared/InterfaceBlockArray.sksl b/tests/sksl/shared/InterfaceBlockArray.sksl
index b187482..c5c8449 100644
--- a/tests/sksl/shared/InterfaceBlockArray.sksl
+++ b/tests/sksl/shared/InterfaceBlockArray.sksl
@@ -1,4 +1,4 @@
-uniform testBlock {
+layout(binding=123) uniform testBlock {
     float x;
 } test[2];
 
diff --git a/tests/sksl/shared/InterfaceBlockNamed.sksl b/tests/sksl/shared/InterfaceBlockNamed.sksl
index 07d1919..a2450fb 100644
--- a/tests/sksl/shared/InterfaceBlockNamed.sksl
+++ b/tests/sksl/shared/InterfaceBlockNamed.sksl
@@ -1,4 +1,4 @@
-uniform testBlock {
+layout(binding=456) uniform testBlock {
     float x;
 } test;
 
diff --git a/tests/sksl/shared/golden/InterfaceBlockAnonymous.asm.frag b/tests/sksl/shared/golden/InterfaceBlockAnonymous.asm.frag
index 7077123..1a40193 100644
--- a/tests/sksl/shared/golden/InterfaceBlockAnonymous.asm.frag
+++ b/tests/sksl/shared/golden/InterfaceBlockAnonymous.asm.frag
@@ -29,6 +29,7 @@
 OpMemberDecorate %testBlock 3 Offset 96
 OpMemberDecorate %testBlock 3 RelaxedPrecision
 OpDecorate %testBlock Block
+OpDecorate %3 Binding 789
 OpDecorate %3 DescriptorSet 0
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
diff --git a/tests/sksl/shared/golden/InterfaceBlockAnonymous.glsl b/tests/sksl/shared/golden/InterfaceBlockAnonymous.glsl
index 1bf70df..c05c515 100644
--- a/tests/sksl/shared/golden/InterfaceBlockAnonymous.glsl
+++ b/tests/sksl/shared/golden/InterfaceBlockAnonymous.glsl
@@ -1,6 +1,6 @@
 
 out vec4 sk_FragColor;
-uniform testBlock {
+layout (binding = 789) uniform testBlock {
     float x;
     float[2] y;
     layout (binding = 12) mat3x2 z;
diff --git a/tests/sksl/shared/golden/InterfaceBlockAnonymous.metal b/tests/sksl/shared/golden/InterfaceBlockAnonymous.metal
index d1d23a8..f70b4ee 100644
--- a/tests/sksl/shared/golden/InterfaceBlockAnonymous.metal
+++ b/tests/sksl/shared/golden/InterfaceBlockAnonymous.metal
@@ -14,7 +14,7 @@
 };
 struct Globals {
     constant testBlock* _anonInterface0;
-};fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant testBlock& _anonInterface0 [[buffer(-1)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
+};fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant testBlock& _anonInterface0 [[buffer(789)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Globals globalStruct{&_anonInterface0};
     thread Globals* _globals = &globalStruct;
     (void)_globals;
diff --git a/tests/sksl/shared/golden/InterfaceBlockArray.asm.frag b/tests/sksl/shared/golden/InterfaceBlockArray.asm.frag
index 8121552..b3359fa 100644
--- a/tests/sksl/shared/golden/InterfaceBlockArray.asm.frag
+++ b/tests/sksl/shared/golden/InterfaceBlockArray.asm.frag
@@ -18,6 +18,7 @@
 OpMemberDecorate %testBlock 0 Offset 0
 OpDecorate %_arr_testBlock_int_2 ArrayStride 16
 OpDecorate %_arr_testBlock_int_2 Block
+OpDecorate %3 Binding 123
 OpDecorate %3 DescriptorSet 0
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
diff --git a/tests/sksl/shared/golden/InterfaceBlockArray.glsl b/tests/sksl/shared/golden/InterfaceBlockArray.glsl
index b5a2474..9968988 100644
--- a/tests/sksl/shared/golden/InterfaceBlockArray.glsl
+++ b/tests/sksl/shared/golden/InterfaceBlockArray.glsl
@@ -1,6 +1,6 @@
 
 out vec4 sk_FragColor;
-uniform testBlock {
+layout (binding = 123) uniform testBlock {
     float x;
 } test[2];
 void main() {
diff --git a/tests/sksl/shared/golden/InterfaceBlockArray.metal b/tests/sksl/shared/golden/InterfaceBlockArray.metal
index f548bd1..a4dbb31 100644
--- a/tests/sksl/shared/golden/InterfaceBlockArray.metal
+++ b/tests/sksl/shared/golden/InterfaceBlockArray.metal
@@ -11,7 +11,7 @@
 } test[2];
 struct Globals {
     constant testBlock* test;
-};fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant testBlock& test [[buffer(-1)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
+};fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant testBlock& test [[buffer(123)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Globals globalStruct{&test};
     thread Globals* _globals = &globalStruct;
     (void)_globals;
diff --git a/tests/sksl/shared/golden/InterfaceBlockNamed.asm.frag b/tests/sksl/shared/golden/InterfaceBlockNamed.asm.frag
index e77e4d4..4a243d7 100644
--- a/tests/sksl/shared/golden/InterfaceBlockNamed.asm.frag
+++ b/tests/sksl/shared/golden/InterfaceBlockNamed.asm.frag
@@ -1,10 +1,3 @@
-### Compilation failed:
-
-error: 1: SPIR-V validation error: Uniform id '3' is missing Binding decoration.
-From Vulkan spec, section 14.5.2:
-These variables must have DescriptorSet and Binding decorations specified
-  %3 = OpVariable %_ptr_Uniform_testBlock Uniform
-
 OpCapability Shader
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
@@ -17,6 +10,7 @@
 OpName %main "main"
 OpMemberDecorate %testBlock 0 Offset 0
 OpDecorate %testBlock Block
+OpDecorate %3 Binding 456
 OpDecorate %3 DescriptorSet 0
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
@@ -46,5 +40,3 @@
 OpStore %sk_FragColor %21
 OpReturn
 OpFunctionEnd
-
-1 error
diff --git a/tests/sksl/shared/golden/InterfaceBlockNamed.glsl b/tests/sksl/shared/golden/InterfaceBlockNamed.glsl
index 8b6791d..b4e1195 100644
--- a/tests/sksl/shared/golden/InterfaceBlockNamed.glsl
+++ b/tests/sksl/shared/golden/InterfaceBlockNamed.glsl
@@ -1,6 +1,6 @@
 
 out vec4 sk_FragColor;
-uniform testBlock {
+layout (binding = 456) uniform testBlock {
     float x;
 } test;
 void main() {
diff --git a/tests/sksl/shared/golden/InterfaceBlockNamed.metal b/tests/sksl/shared/golden/InterfaceBlockNamed.metal
index b0c132e..eeb8306 100644
--- a/tests/sksl/shared/golden/InterfaceBlockNamed.metal
+++ b/tests/sksl/shared/golden/InterfaceBlockNamed.metal
@@ -11,7 +11,7 @@
 } test;
 struct Globals {
     constant testBlock* test;
-};fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant testBlock& test [[buffer(-1)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
+};fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant testBlock& test [[buffer(456)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Globals globalStruct{&test};
     thread Globals* _globals = &globalStruct;
     (void)_globals;