Fix SPIR-V issue with multiple interface blocks and u_skRTFlip.

The SPIR-V code generator would attempt to synthesize u_skRTFlip in
every interface block that it found, under the (normally reasonable)
assumption that we would only have one interface block. We now only
attempt to synthesize u_skRTFlip one time.

Previously, this error was just reported as "symbol 'u_skRTFlip'
declared more than once" but due to http://review.skia.org/793576
we no longer have a ThreadContext set up while the SPIR-V code
generator executes. The ThreadContext is used to report this error
because `SymbolTable::add` has historically never taken a Context
reference. In a followup I will remove the reliance on
ThreadContext here. (This is, in fact, one of the last few places
where ThreadContext is used at all.)

Bug: oss-fuzz:65538
Change-Id: I5b81c00764da8cca0d4edad6da1aa85c953753e2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/796736
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
index 9e4149e..119e8d3 100644
--- a/gn/sksl_tests.gni
+++ b/gn/sksl_tests.gni
@@ -401,6 +401,7 @@
   "spirv/Ossfuzz37627.sksl",
   "spirv/Ossfuzz44096.sksl",
   "spirv/Ossfuzz53202.sksl",
+  "spirv/Ossfuzz65538.sksl",
   "spirv/StructArrayMemberInDifferentLayouts.sksl",
   "spirv/UnusedInterfaceBlock.sksl",
   "spirv/WrongCombinedSamplerLayoutForWebGPUSampler.sksl",
diff --git a/resources/sksl/BUILD.bazel b/resources/sksl/BUILD.bazel
index c027a2f..1cb19d2 100644
--- a/resources/sksl/BUILD.bazel
+++ b/resources/sksl/BUILD.bazel
@@ -1093,6 +1093,7 @@
         "spirv/Ossfuzz37627.sksl",
         "spirv/Ossfuzz44096.sksl",
         "spirv/Ossfuzz53202.sksl",
+        "spirv/Ossfuzz65538.sksl",
         "spirv/StructArrayMemberInDifferentLayouts.sksl",
         "spirv/UnusedInterfaceBlock.sksl",
         "spirv/WrongCombinedSamplerLayoutForWebGPUSampler.sksl",
diff --git a/resources/sksl/spirv/Ossfuzz65538.sksl b/resources/sksl/spirv/Ossfuzz65538.sksl
new file mode 100644
index 0000000..7ea882d
--- /dev/null
+++ b/resources/sksl/spirv/Ossfuzz65538.sksl
@@ -0,0 +1,5 @@
+InterfaceBlockA { int a; };
+InterfaceBlockB { int b; };
+void main() {
+    bool e = sk_FragCoord.y > 0; /* synthesizes u_skRTFlip */
+}
diff --git a/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp b/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp
index 1cbf7b0..bebad7b 100644
--- a/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLSPIRVCodeGenerator.cpp
@@ -4390,7 +4390,7 @@
     SpvStorageClass_ storageClass =
             get_storage_class_for_global_variable(intfVar, SpvStorageClassFunction);
     if (fProgram.fInterface.fRTFlipUniform != Program::Interface::kRTFlip_None && appendRTFlip &&
-        type.isStruct()) {
+        !fWroteRTFlip && type.isStruct()) {
         // We can only have one interface block (because we use push_constant and that is limited
         // to one per program), so we need to append rtflip to this one rather than synthesize an
         // entirely new block when the variable is referenced. And we can't modify the existing
diff --git a/tests/sksl/spirv/Ossfuzz65538.asm.frag b/tests/sksl/spirv/Ossfuzz65538.asm.frag
new file mode 100644
index 0000000..da6bec8
--- /dev/null
+++ b/tests/sksl/spirv/Ossfuzz65538.asm.frag
@@ -0,0 +1,43 @@
+### Compilation failed:
+
+error: SPIR-V validation error: Variables can not have a function[7] storage class outside of a function
+  %4 = OpVariable %_ptr_Function_InterfaceBlockA Function
+
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %sk_FragCoord
+               OpExecutionMode %main OriginUpperLeft
+               OpName %InterfaceBlockA "InterfaceBlockA"
+               OpMemberName %InterfaceBlockA 0 "a"
+               OpMemberName %InterfaceBlockA 1 "u_skRTFlip"
+               OpName %InterfaceBlockB "InterfaceBlockB"
+               OpMemberName %InterfaceBlockB 0 "b"
+               OpName %sk_FragCoord "sk_FragCoord"
+               OpName %main "main"
+               OpMemberDecorate %InterfaceBlockA 0 Offset 0
+               OpMemberDecorate %InterfaceBlockA 1 Offset 16384
+               OpDecorate %InterfaceBlockA Block
+               OpMemberDecorate %InterfaceBlockB 0 Offset 0
+               OpDecorate %InterfaceBlockB Block
+               OpDecorate %sk_FragCoord BuiltIn FragCoord
+        %int = OpTypeInt 32 1
+      %float = OpTypeFloat 32
+    %v2float = OpTypeVector %float 2
+%InterfaceBlockA = OpTypeStruct %int %v2float
+%_ptr_Function_InterfaceBlockA = OpTypePointer Function %InterfaceBlockA
+          %4 = OpVariable %_ptr_Function_InterfaceBlockA Function
+%InterfaceBlockB = OpTypeStruct %int
+%_ptr_Function_InterfaceBlockB = OpTypePointer Function %InterfaceBlockB
+         %10 = OpVariable %_ptr_Function_InterfaceBlockB Function
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%sk_FragCoord = OpVariable %_ptr_Input_v4float Input
+       %void = OpTypeVoid
+         %17 = OpTypeFunction %void
+       %main = OpFunction %void None %17
+         %18 = OpLabel
+               OpReturn
+               OpFunctionEnd
+
+1 error