Revert "Revert "Additional SkSL benches""

This reverts commit 127797193962d40ec0f4aec52bc346a530d1f4a6.

Change-Id: I7985ef22ddd19adcab468acc684b330ce6978c8d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/332738
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
diff --git a/bench/SkSLBench.cpp b/bench/SkSLBench.cpp
index ac83a6f..ff4fa04 100644
--- a/bench/SkSLBench.cpp
+++ b/bench/SkSLBench.cpp
@@ -7,7 +7,13 @@
 #include "bench/Benchmark.h"
 #include "bench/ResultsWriter.h"
 #include "bench/SkSLBench.h"
+#include "include/core/SkCanvas.h"
+#include "src/gpu/GrCaps.h"
+#include "src/gpu/GrRecordingContextPriv.h"
+#include "src/gpu/mock/GrMockCaps.h"
 #include "src/sksl/SkSLCompiler.h"
+#include "src/sksl/SkSLIRGenerator.h"
+#include "src/sksl/SkSLParser.h"
 
 class SkSLCompilerStartupBench : public Benchmark {
 protected:
@@ -28,10 +34,81 @@
 
 DEF_BENCH(return new SkSLCompilerStartupBench();)
 
-class SkSLBench : public Benchmark {
+enum class Output {
+    kNone,
+    kGLSL,
+    kMetal,
+    kSPIRV
+};
+
+class SkSLCompileBench : public Benchmark {
 public:
-    SkSLBench(SkSL::String name, const char* src)
-        : fName("sksl_" + name)
+    static const char* output_string(Output output) {
+        switch (output) {
+            case Output::kNone: return "";
+            case Output::kGLSL: return "glsl_";
+            case Output::kMetal: return "metal_";
+            case Output::kSPIRV: return "spirv_";
+        }
+        SkUNREACHABLE;
+    }
+
+    SkSLCompileBench(SkSL::String name, const char* src, bool optimize, Output output)
+        : fName(SkSL::String("sksl_") + (optimize ? "" : "unoptimized_") + output_string(output) +
+                name)
+        , fSrc(src)
+        , fCaps(GrContextOptions(), GrMockOptions())
+        , fCompiler(fCaps.shaderCaps())
+        , fOutput(output) {
+            fSettings.fOptimize = optimize;
+            // The test programs we compile don't follow Vulkan rules and thus produce invalid
+            // SPIR-V. This is harmless, so long as we don't try to validate them.
+            fSettings.fValidateSPIRV = false;
+        }
+
+protected:
+    const char* onGetName() override {
+        return fName.c_str();
+    }
+
+    bool isSuitableFor(Backend backend) override {
+        return backend == kNonRendering_Backend;
+    }
+
+    void onDraw(int loops, SkCanvas* canvas) override {
+        for (int i = 0; i < loops; i++) {
+            std::unique_ptr<SkSL::Program> program = fCompiler.convertProgram(
+                                                                      SkSL::Program::kFragment_Kind,
+                                                                      fSrc,
+                                                                      fSettings);
+            if (fCompiler.errorCount()) {
+                SK_ABORT("shader compilation failed: %s\n", fCompiler.errorText().c_str());
+            }
+            SkSL::String result;
+            switch (fOutput) {
+                case Output::kNone: break;
+                case Output::kGLSL:  SkAssertResult(fCompiler.toGLSL(*program,  &result)); break;
+                case Output::kMetal: SkAssertResult(fCompiler.toMetal(*program, &result)); break;
+                case Output::kSPIRV: SkAssertResult(fCompiler.toSPIRV(*program, &result)); break;
+            }
+        }
+    }
+
+private:
+    SkSL::String fName;
+    SkSL::String fSrc;
+    GrMockCaps fCaps;
+    SkSL::Compiler fCompiler;
+    SkSL::Program::Settings fSettings;
+    Output fOutput;
+
+    using INHERITED = Benchmark;
+};
+
+class SkSLParseBench : public Benchmark {
+public:
+    SkSLParseBench(SkSL::String name, const char* src)
+        : fName("sksl_parse_" + name)
         , fSrc(src)
         , fCompiler(/*caps=*/nullptr) {}
 
@@ -44,15 +121,21 @@
         return backend == kNonRendering_Backend;
     }
 
+    void onDelayedSetup() override {
+        SkSL::ParsedModule module = fCompiler.moduleForProgramKind(
+                                                               SkSL::Program::Kind::kFragment_Kind);
+        fCompiler.irGenerator().setSymbolTable(module.fSymbols);
+    }
+
     void onDraw(int loops, SkCanvas*) override {
         for (int i = 0; i < loops; i++) {
-            std::unique_ptr<SkSL::Program> program = fCompiler.convertProgram(
-                                                                      SkSL::Program::kFragment_Kind,
-                                                                      fSrc,
-                                                                      fSettings);
+            fCompiler.irGenerator().pushSymbolTable();
+            SkSL::Parser parser(fSrc.c_str(), fSrc.length(), *fCompiler.irGenerator().symbolTable(),
+                                fCompiler);
+            parser.compilationUnit();
+            fCompiler.irGenerator().popSymbolTable();
             if (fCompiler.errorCount()) {
-                printf("%s\n", fCompiler.errorText().c_str());
-                SK_ABORT("shader compilation failed");
+                SK_ABORT("shader compilation failed: %s\n", fCompiler.errorText().c_str());
             }
         }
     }
@@ -68,22 +151,33 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-DEF_BENCH(return new SkSLBench("large", R"(
-uniform half urange_Stage1;
-uniform half4 uleftBorderColor_Stage1_c0_c0;
-uniform half4 urightBorderColor_Stage1_c0_c0;
-uniform float3x3 umatrix_Stage1_c0_c0_c0;
-uniform half2 ufocalParams_Stage1_c0_c0_c0_c0;
-uniform float4 uscale0_1_Stage1_c0_c0_c1;
-uniform float4 uscale2_3_Stage1_c0_c0_c1;
-uniform float4 uscale4_5_Stage1_c0_c0_c1;
-uniform float4 uscale6_7_Stage1_c0_c0_c1;
-uniform float4 ubias0_1_Stage1_c0_c0_c1;
-uniform float4 ubias2_3_Stage1_c0_c0_c1;
-uniform float4 ubias4_5_Stage1_c0_c0_c1;
-uniform float4 ubias6_7_Stage1_c0_c0_c1;
-uniform half4 uthresholds1_7_Stage1_c0_c0_c1;
-uniform half4 uthresholds9_13_Stage1_c0_c0_c1;
+#define COMPILER_BENCH(name, text)                                                               \
+static constexpr char name ## _SRC[] = text;                                                     \
+DEF_BENCH(return new SkSLParseBench(#name, name ## _SRC);)                                       \
+DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/false, Output::kNone);)  \
+DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/true,  Output::kNone);)  \
+DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/true,  Output::kGLSL);)  \
+DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/true,  Output::kMetal);) \
+DEF_BENCH(return new SkSLCompileBench(#name, name ## _SRC, /*optimize=*/true,  Output::kSPIRV);)
+
+// Metal requires a layout set and binding for all of its uniforms. We just care that these shaders
+// compile, not that they actually work, so we just fill them with zeroes.
+COMPILER_BENCH(large, R"(
+layout(set=0, binding=0) uniform half urange_Stage1;
+layout(set=0, binding=0) uniform half4 uleftBorderColor_Stage1_c0_c0;
+layout(set=0, binding=0) uniform half4 urightBorderColor_Stage1_c0_c0;
+layout(set=0, binding=0) uniform float3x3 umatrix_Stage1_c0_c0_c0;
+layout(set=0, binding=0) uniform half2 ufocalParams_Stage1_c0_c0_c0_c0;
+layout(set=0, binding=0) uniform float4 uscale0_1_Stage1_c0_c0_c1;
+layout(set=0, binding=0) uniform float4 uscale2_3_Stage1_c0_c0_c1;
+layout(set=0, binding=0) uniform float4 uscale4_5_Stage1_c0_c0_c1;
+layout(set=0, binding=0) uniform float4 uscale6_7_Stage1_c0_c0_c1;
+layout(set=0, binding=0) uniform float4 ubias0_1_Stage1_c0_c0_c1;
+layout(set=0, binding=0) uniform float4 ubias2_3_Stage1_c0_c0_c1;
+layout(set=0, binding=0) uniform float4 ubias4_5_Stage1_c0_c0_c1;
+layout(set=0, binding=0) uniform float4 ubias6_7_Stage1_c0_c0_c1;
+layout(set=0, binding=0) uniform half4 uthresholds1_7_Stage1_c0_c0_c1;
+layout(set=0, binding=0) uniform half4 uthresholds9_13_Stage1_c0_c0_c1;
 flat in half4 vcolor_Stage0;
 in float vcoverage_Stage0;
 flat in float4 vgeomSubset_Stage0;
@@ -347,12 +441,12 @@
         sk_FragColor = output_Stage1 * outputCoverage_Stage0;
     }
 }
-)");)
+)");
 
-DEF_BENCH(return new SkSLBench("medium", R"(
-    uniform half2 uDstTextureUpperLeft_Stage1;
-    uniform half2 uDstTextureCoordScale_Stage1;
-    uniform sampler2D uDstTextureSampler_Stage1;
+COMPILER_BENCH(medium, R"(
+    layout(set=0, binding=0) uniform half2 uDstTextureUpperLeft_Stage1;
+    layout(set=0, binding=0) uniform half2 uDstTextureCoordScale_Stage1;
+    layout(set=0, binding=0) uniform sampler2D uDstTextureSampler_Stage1;
     noperspective in half4 vQuadEdge_Stage0;
     noperspective in half4 vinColor_Stage0;
     out half4 sk_FragColor;
@@ -414,11 +508,11 @@
                            (half4(1.0) - outputCoverage_Stage0) * _dstColor;
         }
     }
-)"); )
+)");
 
-DEF_BENCH(return new SkSLBench("small", R"(
-    uniform float3x3 umatrix_Stage1_c0_c0;
-    uniform sampler2D uTextureSampler_0_Stage1;
+COMPILER_BENCH(small, R"(
+    layout(set=0, binding=0) uniform float3x3 umatrix_Stage1_c0_c0;
+    layout(set=0, binding=0) uniform sampler2D uTextureSampler_0_Stage1;
     noperspective in float2 vTransformedCoords_0_Stage0;
     out half4 sk_FragColor;
     half4 TextureEffect_Stage1_c0_c0_c0(half4 _input)
@@ -453,9 +547,9 @@
             sk_FragColor = output_Stage1 * outputCoverage_Stage0;
         }
     }
-)"); )
+)");
 
-DEF_BENCH(return new SkSLBench("tiny", "void main() { sk_FragColor = half4(1); }"); )
+COMPILER_BENCH(tiny, "void main() { sk_FragColor = half4(1); }");
 
 #if defined(SK_BUILD_FOR_UNIX)
 
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 8b9bbc3..27d389a 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -1655,7 +1655,7 @@
     AutoSource as(this, program.fSource.get());
     SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
     bool result = cg.generateCode();
-    if (result) {
+    if (result && program.fSettings.fValidateSPIRV) {
         spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
         const String& data = buffer.str();
         SkASSERT(0 == data.size() % 4);
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index 7a209f2..349ba79 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -42,6 +42,7 @@
 #define SK_POSITION_BUILTIN                0
 
 class SkBitSet;
+class SkSLCompileBench;
 
 namespace SkSL {
 
@@ -218,6 +219,12 @@
     LoadedModule loadModule(Program::Kind kind, ModuleData data, std::shared_ptr<SymbolTable> base);
     ParsedModule parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base);
 
+    IRGenerator& irGenerator() {
+        return *fIRGenerator;
+    }
+
+    const ParsedModule& moduleForProgramKind(Program::Kind kind);
+
 private:
     const ParsedModule& loadFPModule();
     const ParsedModule& loadGeometryModule();
@@ -225,8 +232,6 @@
     const ParsedModule& loadInterpreterModule();
     const ParsedModule& loadPipelineModule();
 
-    const ParsedModule& moduleForProgramKind(Program::Kind kind);
-
     void addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
                        DefinitionMap* definitions);
     void addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions);
@@ -295,6 +300,7 @@
     String fErrorText;
 
     friend class AutoSource;
+    friend class ::SkSLCompileBench;
 };
 
 #if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
index 0b1242e..c9fb8f0 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp
@@ -535,7 +535,6 @@
             case FunctionClass::kFwidth:
                 if (!fFoundDerivatives &&
                     fProgram.fCaps->shaderDerivativeExtensionString()) {
-                    SkASSERT(fProgram.fCaps->shaderDerivativeSupport());
                     this->writeExtension(fProgram.fCaps->shaderDerivativeExtensionString());
                     fFoundDerivatives = true;
                 }
@@ -1485,8 +1484,10 @@
 }
 
 void GLSLCodeGenerator::writeHeader() {
-    this->write(fProgram.fCaps->versionDeclString());
-    this->writeLine();
+    if (fProgram.fCaps->versionDeclString()) {
+        this->write(fProgram.fCaps->versionDeclString());
+        this->writeLine();
+    }
 }
 
 void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 339c0de..7c6095d 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -2993,7 +2993,7 @@
     }
 
     Parser parser(text, length, *fSymbolTable, fErrors);
-    fFile = parser.file();
+    fFile = parser.compilationUnit();
     if (fErrors.errorCount()) {
         return {};
     }
diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h
index 50bd236..24d6742 100644
--- a/src/sksl/SkSLIRGenerator.h
+++ b/src/sksl/SkSLIRGenerator.h
@@ -133,6 +133,17 @@
 
     const Program::Settings* settings() const { return fSettings; }
 
+    std::shared_ptr<SymbolTable>& symbolTable() {
+        return fSymbolTable;
+    }
+
+    void setSymbolTable(std::shared_ptr<SymbolTable>& symbolTable) {
+        fSymbolTable = symbolTable;
+    }
+
+    void pushSymbolTable();
+    void popSymbolTable();
+
     const Context& fContext;
 
 private:
@@ -141,9 +152,6 @@
      */
     std::unique_ptr<ModifiersPool> releaseModifiers();
 
-    void pushSymbolTable();
-    void popSymbolTable();
-
     void checkModifiers(int offset, const Modifiers& modifiers, int permitted);
     StatementArray convertVarDeclarations(const ASTNode& decl, Variable::Storage storage);
     void convertFunction(const ASTNode& f);
@@ -242,7 +250,7 @@
     int fRTAdjustFieldIndex;
     bool fCanInline = true;
     // true if we are currently processing one of the built-in SkSL include files
-    bool fIsBuiltinCode;
+    bool fIsBuiltinCode = false;
     std::unique_ptr<ModifiersPool> fModifiers;
 
     friend class AutoSymbolTable;
diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp
index a066411..fa80885 100644
--- a/src/sksl/SkSLParser.cpp
+++ b/src/sksl/SkSLParser.cpp
@@ -138,7 +138,7 @@
     } while (false)
 
 /* (directive | section | declaration)* END_OF_FILE */
-std::unique_ptr<ASTFile> Parser::file() {
+std::unique_ptr<ASTFile> Parser::compilationUnit() {
     fFile = std::make_unique<ASTFile>();
     CREATE_NODE(result, 0, ASTNode::Kind::kFile);
     fFile->fRoot = result;
diff --git a/src/sksl/SkSLParser.h b/src/sksl/SkSLParser.h
index 41bea40..11fd7ca 100644
--- a/src/sksl/SkSLParser.h
+++ b/src/sksl/SkSLParser.h
@@ -91,7 +91,7 @@
      * Consumes a complete .sksl file and returns the parse tree. Errors are reported via the
      * ErrorReporter; the return value may contain some declarations even when errors have occurred.
      */
-    std::unique_ptr<ASTFile> file();
+    std::unique_ptr<ASTFile> compilationUnit();
 
     StringFragment text(Token token);
 
diff --git a/src/sksl/ir/SkSLProgram.h b/src/sksl/ir/SkSLProgram.h
index e6798c6..e0a5d61 100644
--- a/src/sksl/ir/SkSLProgram.h
+++ b/src/sksl/ir/SkSLProgram.h
@@ -144,6 +144,9 @@
         // If true, implicit conversions to lower precision numeric types are allowed
         // (eg, float to half)
         bool fAllowNarrowingConversions = false;
+        // If true, then Debug code will run SPIR-V output through the validator to ensure its
+        // correctness
+        bool fValidateSPIRV = true;
     };
 
     struct Inputs {