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