Report an error if sk_LastFragColor is referenced without fbFetchSupport

Adjusted default caps in skslc to be consistent with runtime behavior,
and added optional settings mode to enable the feature. Tests for both
scenarios. (The error test crashed prior to the fix).

Bug: oss-fuzz:38726
Change-Id: I5270d4837ac982085d7baf5abd4b361f7bfb8562
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/449062
Reviewed-by: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
index 9fe303b..1b14664 100644
--- a/gn/sksl_tests.gni
+++ b/gn/sksl_tests.gni
@@ -69,6 +69,7 @@
   "/sksl/errors/InvalidOutParams.sksl",
   "/sksl/errors/InvalidToken.sksl",
   "/sksl/errors/InvalidUnary.sksl",
+  "/sksl/errors/LastFragColorWithoutCaps.sksl",
   "/sksl/errors/LayoutInFunctions.sksl",
   "/sksl/errors/LayoutRepeatedQualifiers.sksl",
   "/sksl/errors/MatrixToVectorCast3x3.sksl",
@@ -161,6 +162,7 @@
 sksl_glsl_tests = [
   "/sksl/glsl/ForceHighPrecision.sksl",
   "/sksl/glsl/IncompleteShortIntPrecision.sksl",
+  "/sksl/glsl/LastFragColor.sksl",
   "/sksl/glsl/LayoutQualifiers.sksl",
   "/sksl/glsl/ShortIntPrecision.sksl",
   "/sksl/glsl/TextureSharpenVersion110.sksl",
diff --git a/resources/sksl/errors/LastFragColorWithoutCaps.sksl b/resources/sksl/errors/LastFragColorWithoutCaps.sksl
new file mode 100644
index 0000000..dbc7649
--- /dev/null
+++ b/resources/sksl/errors/LastFragColorWithoutCaps.sksl
@@ -0,0 +1,3 @@
+void main() {
+    sk_FragColor = sk_LastFragColor;
+}
diff --git a/resources/sksl/glsl/LastFragColor.sksl b/resources/sksl/glsl/LastFragColor.sksl
new file mode 100644
index 0000000..d49af63
--- /dev/null
+++ b/resources/sksl/glsl/LastFragColor.sksl
@@ -0,0 +1,5 @@
+/*#pragma settings FramebufferFetchSupport*/
+
+void main() {
+    sk_FragColor = sk_LastFragColor;
+}
diff --git a/src/sksl/SkSLMain.cpp b/src/sksl/SkSLMain.cpp
index 17102fa..2ab727f 100644
--- a/src/sksl/SkSLMain.cpp
+++ b/src/sksl/SkSLMain.cpp
@@ -139,6 +139,10 @@
                     static auto s_emulateAbsIntCaps = Factory::EmulateAbsIntFunction();
                     *caps = s_emulateAbsIntCaps.get();
                 }
+                if (settingsText.consumeSuffix(" FramebufferFetchSupport")) {
+                    static auto s_fbFetchSupport = Factory::FramebufferFetchSupport();
+                    *caps = s_fbFetchSupport.get();
+                }
                 if (settingsText.consumeSuffix(" IncompleteShortIntPrecision")) {
                     static auto s_incompleteShortIntCaps = Factory::IncompleteShortIntPrecision();
                     *caps = s_incompleteShortIntCaps.get();
diff --git a/src/sksl/SkSLUtil.h b/src/sksl/SkSLUtil.h
index aab1444..f19afb7 100644
--- a/src/sksl/SkSLUtil.h
+++ b/src/sksl/SkSLUtil.h
@@ -89,7 +89,7 @@
         return fGLSLGeneration > k110_GrGLSLGeneration;
     }
 
-    bool fFBFetchSupport = true;
+    bool fFBFetchSupport = false;
     bool fbFetchSupport() const {
         return fFBFetchSupport;
     }
@@ -346,6 +346,13 @@
         return result;
     }
 
+    static ShaderCapsPointer FramebufferFetchSupport() {
+        ShaderCapsPointer result = MakeShaderCaps();
+        result->fFBFetchSupport = true;
+        result->fFBFetchColorName = "gl_LastFragData[0]";
+        return result;
+    }
+
     static ShaderCapsPointer IncompleteShortIntPrecision() {
         ShaderCapsPointer result = MakeShaderCaps();
         result->fVersionDeclString = "#version 310es";
diff --git a/src/sksl/codegen/SkSLGLSLCodeGenerator.cpp b/src/sksl/codegen/SkSLGLSLCodeGenerator.cpp
index 6284a25..8c62aee 100644
--- a/src/sksl/codegen/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLGLSLCodeGenerator.cpp
@@ -777,7 +777,12 @@
             this->write("gl_InstanceID");
             break;
         case SK_LASTFRAGCOLOR_BUILTIN:
-            this->write(this->caps().fbFetchColorName());
+            if (this->caps().fbFetchSupport()) {
+                this->write(this->caps().fbFetchColorName());
+            } else {
+                fContext.fErrors->error(ref.fOffset,
+                                        "sk_LastFragColor requires framebuffer fetch support");
+            }
             break;
         default:
             this->write(ref.variable()->name());
diff --git a/tests/sksl/errors/LastFragColorWithoutCaps.glsl b/tests/sksl/errors/LastFragColorWithoutCaps.glsl
new file mode 100644
index 0000000..59d172a
--- /dev/null
+++ b/tests/sksl/errors/LastFragColorWithoutCaps.glsl
@@ -0,0 +1,4 @@
+### Compilation failed:
+
+error: 2: sk_LastFragColor requires framebuffer fetch support
+1 error
diff --git a/tests/sksl/glsl/LastFragColor.glsl b/tests/sksl/glsl/LastFragColor.glsl
new file mode 100644
index 0000000..c74d66a
--- /dev/null
+++ b/tests/sksl/glsl/LastFragColor.glsl
@@ -0,0 +1,5 @@
+
+out vec4 sk_FragColor;
+void main() {
+    sk_FragColor = gl_LastFragData[0];
+}
diff --git a/tests/sksl/shared/Caps.asm.frag b/tests/sksl/shared/Caps.asm.frag
index 6ee2715..4ba5887 100644
--- a/tests/sksl/shared/Caps.asm.frag
+++ b/tests/sksl/shared/Caps.asm.frag
@@ -42,7 +42,6 @@
 OpStore %y %int_0
 OpStore %z %int_0
 OpStore %x %int_1
-OpStore %y %int_1
 OpStore %z %int_1
 %20 = OpLoad %int %x
 %21 = OpConvertSToF %float %20
diff --git a/tests/sksl/shared/Caps.glsl b/tests/sksl/shared/Caps.glsl
index f4079c3..c4b0cfa 100644
--- a/tests/sksl/shared/Caps.glsl
+++ b/tests/sksl/shared/Caps.glsl
@@ -5,7 +5,6 @@
     int y = 0;
     int z = 0;
     x = 1;
-    y = 1;
     z = 1;
     sk_FragColor.xyz = vec3(float(x), float(y), float(z));
 }
diff --git a/tests/sksl/shared/Caps.metal b/tests/sksl/shared/Caps.metal
index dcff059..18871ef 100644
--- a/tests/sksl/shared/Caps.metal
+++ b/tests/sksl/shared/Caps.metal
@@ -13,7 +13,6 @@
     int y = 0;
     int z = 0;
     x = 1;
-    y = 1;
     z = 1;
     _out.sk_FragColor.xyz = float3(float(x), float(y), float(z));
     return _out;