Loosen ES3 restrictions in Runtime Effects for debugging.

This CL adds a RuntimeEffect option flag which skips over the various
`strictES2Mode` checks sprinkled throughout IR generation.

Runtime Effects still won't allow a lot of ES3 things (the Pipeline
stage will reject unsupported statement types, SkVM doesn't support most
non-ES2 constructs, etc). However, this change will give us the ability
to test many more features involving arrays and structs that previously
were off-limits due to ES2 restrictions, and will shore up some
legitimate gaps in our testing. This is a useful starting point to allow
for improved test coverage.

Change-Id: I4a5bc43914e65fc7e59f1cecb76a0ec5a7f05f2f
Bug: skia:11209
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/402157
Commit-Queue: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/tests/SkRuntimeEffectTest.cpp b/tests/SkRuntimeEffectTest.cpp
index 77f66b7..a6ba883 100644
--- a/tests/SkRuntimeEffectTest.cpp
+++ b/tests/SkRuntimeEffectTest.cpp
@@ -75,11 +75,23 @@
             "unknown identifier 'sk_Caps'");
 }
 
+DEF_TEST(SkRuntimeEffectCanDisableES2Restrictions, r) {
+    auto test_valid_es3 = [](skiatest::Reporter* r, const char* sksl) {
+        SkRuntimeEffect::Options opt;
+        opt.enforceES2Restrictions = false;
+        auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(sksl), opt);
+        REPORTER_ASSERT(r, effect, "%s", errorText.c_str());
+    };
+
+    test_invalid_effect(r, "float f[2] = float[2](0, 1);" EMPTY_MAIN, "construction of array type");
+    test_valid_es3     (r, "float f[2] = float[2](0, 1);" EMPTY_MAIN);
+}
+
 DEF_TEST(SkRuntimeEffectForColorFilter, r) {
     // Tests that the color filter factory rejects or accepts certain SkSL constructs
     auto test_valid = [r](const char* sksl) {
         auto [effect, errorText] = SkRuntimeEffect::MakeForColorFilter(SkString(sksl));
-        REPORTER_ASSERT(r, effect, errorText.c_str());
+        REPORTER_ASSERT(r, effect, "%s", errorText.c_str());
     };
 
     auto test_invalid = [r](const char* sksl, const char* expected) {
@@ -131,7 +143,7 @@
     // Tests that the shader factory rejects or accepts certain SkSL constructs
     auto test_valid = [r](const char* sksl) {
         auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(sksl));
-        REPORTER_ASSERT(r, effect, errorText.c_str());
+        REPORTER_ASSERT(r, effect, "%s", errorText.c_str());
     };
 
     auto test_invalid = [r](const char* sksl, const char* expected) {
diff --git a/tests/SkSLTest.cpp b/tests/SkSLTest.cpp
index 20b3a44..20bcff5 100644
--- a/tests/SkSLTest.cpp
+++ b/tests/SkSLTest.cpp
@@ -19,6 +19,8 @@
 #include "include/effects/SkRuntimeEffect.h"
 #include "include/private/SkSLDefines.h"  // for kDefaultInlineThreshold
 #include "include/utils/SkRandom.h"
+#include "src/gpu/GrCaps.h"
+#include "src/gpu/GrDirectContextPriv.h"
 #include "tests/Test.h"
 #include "tools/Resources.h"
 #include "tools/ToolUtils.h"
@@ -92,8 +94,12 @@
                     SkColorGetA(color), SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
 }
 
-static void test_permutations(skiatest::Reporter* r, SkSurface* surface, const char* testFile) {
+static void test_permutations(skiatest::Reporter* r,
+                              SkSurface* surface,
+                              const char* testFile,
+                              bool worksInES2) {
     SkRuntimeEffect::Options options;
+    options.enforceES2Restrictions = worksInES2;
     options.forceNoInline = false;
     test_one_permutation(r, surface, testFile, "", options);
 
@@ -105,14 +111,28 @@
     const SkImageInfo info = SkImageInfo::MakeN32Premul(kRect.width(), kRect.height());
     sk_sp<SkSurface> surface(SkSurface::MakeRaster(info));
 
-    test_permutations(r, surface.get(), testFile);
+    test_permutations(r, surface.get(), testFile, /*worksInES2=*/true);
 }
 
 static void test_gpu(skiatest::Reporter* r, GrDirectContext* ctx, const char* testFile) {
     const SkImageInfo info = SkImageInfo::MakeN32Premul(kRect.width(), kRect.height());
     sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info));
 
-    test_permutations(r, surface.get(), testFile);
+    test_permutations(r, surface.get(), testFile, /*worksInES2=*/true);
+}
+
+static void test_es3(skiatest::Reporter* r, GrDirectContext* ctx, const char* testFile) {
+    // We don't have an ES2 caps bit, so we check for integer support and derivatives support.
+    // Our ES2 bots should return false for these.
+    if (!ctx->priv().caps()->shaderCaps()->shaderDerivativeSupport() ||
+        !ctx->priv().caps()->shaderCaps()->integerSupport()) {
+        return;
+    }
+    // ES3-only tests never run on the CPU, because SkVM lacks support for many non-ES2 features.
+    const SkImageInfo info = SkImageInfo::MakeN32Premul(kRect.width(), kRect.height());
+    sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info));
+
+    test_permutations(r, surface.get(), testFile, /*worksInES2=*/false);
 }
 
 #define SKSL_TEST_CPU(name, path)                                   \
@@ -123,11 +143,16 @@
     DEF_GPUTEST_FOR_RENDERING_CONTEXTS(name ## _GPU, r, ctxInfo) {  \
         test_gpu(r, ctxInfo.directContext(), path);                 \
     }
+#define SKSL_TEST_ES3(name, path)                                   \
+    DEF_GPUTEST_FOR_RENDERING_CONTEXTS(name ## _GPU, r, ctxInfo) {  \
+        test_es3(r, ctxInfo.directContext(), path);                 \
+    }
 #define SKSL_TEST(name, path) SKSL_TEST_CPU(name, path) SKSL_TEST_GPU(name, path)
 
 SKSL_TEST(SkSLAssignmentOps,                   "folding/AssignmentOps.sksl")
 SKSL_TEST(SkSLBoolFolding,                     "folding/BoolFolding.sksl")
 SKSL_TEST(SkSLIntFoldingES2,                   "folding/IntFoldingES2.sksl")
+SKSL_TEST_ES3(SkSLIntFoldingES3,               "folding/IntFoldingES3.sksl")
 SKSL_TEST(SkSLFloatFolding,                    "folding/FloatFolding.sksl")
 // skbug.com/11919: Fails on Nexus5/7, and Intel GPUs
 SKSL_TEST_CPU(SkSLMatrixFoldingES2,            "folding/MatrixFoldingES2.sksl")
@@ -137,6 +162,8 @@
 SKSL_TEST(SkSLVectorVectorFolding,             "folding/VectorVectorFolding.sksl")
 
 SKSL_TEST(SkSLForBodyMustBeInlinedIntoAScope,     "inliner/ForBodyMustBeInlinedIntoAScope.sksl")
+SKSL_TEST_ES3(SkSLForInitializerExpressionsCanBeInlined,
+         "inliner/ForInitializerExpressionsCanBeInlined.sksl")
 SKSL_TEST(SkSLForWithoutReturnInsideCanBeInlined, "inliner/ForWithoutReturnInsideCanBeInlined.sksl")
 SKSL_TEST(SkSLForWithReturnInsideCannotBeInlined, "inliner/ForWithReturnInsideCannotBeInlined.sksl")
 SKSL_TEST(SkSLIfBodyMustBeInlinedIntoAScope,      "inliner/IfBodyMustBeInlinedIntoAScope.sksl")
@@ -167,6 +194,9 @@
 SKSL_TEST(SkSLTernaryResultsCannotBeInlined,      "inliner/TernaryResultsCannotBeInlined.sksl")
 SKSL_TEST(SkSLTernaryTestCanBeInlined,            "inliner/TernaryTestCanBeInlined.sksl")
 SKSL_TEST(SkSLTrivialArgumentsInlineDirectly,     "inliner/TrivialArgumentsInlineDirectly.sksl")
+SKSL_TEST_ES3(SkSLWhileBodyMustBeInlinedIntoAScope,
+         "inliner/WhileBodyMustBeInlinedIntoAScope.sksl")
+SKSL_TEST_ES3(SkSLWhileTestCannotBeInlined,       "inliner/WhileTestCannotBeInlined.sksl")
 
 // TODO(skia:11052): SPIR-V does not yet honor `out` param semantics correctly
 SKSL_TEST_CPU(SkSLInlinerHonorsGLSLOutParamSemantics,
@@ -244,17 +274,12 @@
 /*
 TODO(skia:11209): enable these tests when Runtime Effects have support for ES3
 
-SKSL_TEST(SkSLIntFoldingES3,                   "folding/IntFoldingES3.sksl")
 SKSL_TEST(SkSLMatrixFoldingES3,                "folding/MatrixFoldingES3.sksl")
 
 SKSL_TEST(SkSLDoWhileBodyMustBeInlinedIntoAScope, "inliner/DoWhileBodyMustBeInlinedIntoAScope.sksl")
 SKSL_TEST(SkSLDoWhileTestCannotBeInlined,         "inliner/DoWhileTestCannotBeInlined.sksl")
-SKSL_TEST(SkSLEnumsCanBeInlinedSafely,            "inliner/EnumsCanBeInlinedSafely.sksl")
-SKSL_TEST(SkSLForInitializerExpressionsCanBeInlined,
-     "inliner/ForInitializerExpressionsCanBeInlined.sksl")
+SKSL_TEST(SkSLEnumsCanBeInlinedSafely,         "inliner/EnumsCanBeInlinedSafely.sksl")
 SKSL_TEST(SkSLStaticSwitch,                       "inliner/StaticSwitch.sksl")
-SKSL_TEST(SkSLWhileBodyMustBeInlinedIntoAScope,   "inliner/WhileBodyMustBeInlinedIntoAScope.sksl")
-SKSL_TEST(SkSLWhileTestCannotBeInlined,           "inliner/WhileTestCannotBeInlined.sksl")
 
 SKSL_TEST(SkSLIntrinsicAbsInt,                 "intrinsics/AbsInt.sksl")
 SKSL_TEST(SkSLIntrinsicClampInt,               "intrinsics/ClampInt.sksl")
diff --git a/tests/sksl/inliner/ForInitializerExpressionsCanBeInlined.glsl b/tests/sksl/inliner/ForInitializerExpressionsCanBeInlined.glsl
index 29c2e35..52339f3 100644
--- a/tests/sksl/inliner/ForInitializerExpressionsCanBeInlined.glsl
+++ b/tests/sksl/inliner/ForInitializerExpressionsCanBeInlined.glsl
@@ -8,7 +8,7 @@
     return v + vec4(0.125);
 }
 vec4 main() {
-    for (sk_FragColor = vec4(0.0625);shouldLoop_bh4(sk_FragColor); sk_FragColor = grow_h4h4(sk_FragColor)) {
+    for (vec4 color = vec4(0.0625);shouldLoop_bh4(color); color = grow_h4h4(color)) {
     }
     return colorGreen;
 }