Re-land sksl fragment processor support

This reverts commit ed50200682e0de72c3abecaa4d5324ebcd1ed9f9.

Bug: skia:
Change-Id: I9caa7454b391450620d6989dc472abb3cf7a2cab
Reviewed-on: https://skia-review.googlesource.com/20965
Reviewed-by: Ben Wagner <benjaminwagner@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/sksl/ir/SkSLExpression.h b/src/sksl/ir/SkSLExpression.h
index 07dad1d..89a1a1e 100644
--- a/src/sksl/ir/SkSLExpression.h
+++ b/src/sksl/ir/SkSLExpression.h
@@ -36,6 +36,7 @@
         kIndex_Kind,
         kPrefix_Kind,
         kPostfix_Kind,
+        kSetting_Kind,
         kSwizzle_Kind,
         kVariableReference_Kind,
         kTernary_Kind,
diff --git a/src/sksl/ir/SkSLFunctionDeclaration.h b/src/sksl/ir/SkSLFunctionDeclaration.h
index 8704c9a..64236d3 100644
--- a/src/sksl/ir/SkSLFunctionDeclaration.h
+++ b/src/sksl/ir/SkSLFunctionDeclaration.h
@@ -71,7 +71,7 @@
     bool determineFinalTypes(const std::vector<std::unique_ptr<Expression>>& arguments,
                              std::vector<const Type*>* outParameterTypes,
                              const Type** outReturnType) const {
-        assert(arguments.size() == fParameters.size());
+        ASSERT(arguments.size() == fParameters.size());
         int genericIndex = -1;
         for (size_t i = 0; i < arguments.size(); i++) {
             if (fParameters[i]->fType.kind() == Type::kGeneric_Kind) {
@@ -93,7 +93,7 @@
             }
         }
         if (fReturnType.kind() == Type::kGeneric_Kind) {
-            assert(genericIndex != -1);
+            ASSERT(genericIndex != -1);
             *outReturnType = fReturnType.coercibleTypes()[genericIndex];
         } else {
             *outReturnType = &fReturnType;
diff --git a/src/sksl/ir/SkSLLayout.h b/src/sksl/ir/SkSLLayout.h
index 3a8416ac..8bf0472 100644
--- a/src/sksl/ir/SkSLLayout.h
+++ b/src/sksl/ir/SkSLLayout.h
@@ -8,6 +8,7 @@
 #ifndef SKSL_LAYOUT
 #define SKSL_LAYOUT
 
+#include "SkSLString.h"
 #include "SkSLUtil.h"
 
 namespace SkSL {
@@ -42,6 +43,16 @@
         kR8I,
     };
 
+    // used by SkSL processors
+    enum Key {
+        // field is not a key
+        kNo_Key,
+        // field is a key
+        kKey_Key,
+        // key is 0 or 1 depending on whether the matrix is an identity matrix
+        kIdentity_Key,
+    };
+
     static const char* FormatToStr(Format format) {
         switch (format) {
             case Format::kUnspecified:  return "";
@@ -55,7 +66,6 @@
             case Format::kR8I:          return "r8i";
         }
         ABORT("Unexpected format");
-        return "";
     }
 
     static bool ReadFormat(String str, Format* format) {
@@ -90,7 +100,7 @@
     Layout(int location, int offset, int binding, int index, int set, int builtin,
            int inputAttachmentIndex, bool originUpperLeft, bool overrideCoverage,
            bool blendSupportAllEquations, Format format, bool pushconstant, Primitive primitive,
-           int maxVertices, int invocations)
+           int maxVertices, int invocations, String when, Key key)
     : fLocation(location)
     , fOffset(offset)
     , fBinding(binding)
@@ -105,7 +115,9 @@
     , fPushConstant(pushconstant)
     , fPrimitive(primitive)
     , fMaxVertices(maxVertices)
-    , fInvocations(invocations) {}
+    , fInvocations(invocations)
+    , fWhen(when)
+    , fKey(key) {}
 
     Layout()
     : fLocation(-1)
@@ -122,7 +134,8 @@
     , fPushConstant(false)
     , fPrimitive(kUnspecified_Primitive)
     , fMaxVertices(-1)
-    , fInvocations(-1) {}
+    , fInvocations(-1)
+    , fKey(kNo_Key) {}
 
     String description() const {
         String result;
@@ -215,6 +228,22 @@
             result += separator + "invocations = " + to_string(fInvocations);
             separator = ", ";
         }
+        if (fWhen.size()) {
+            result += separator + "when = " + fWhen;
+            separator = ", ";
+        }
+        switch (fKey) {
+            case kNo_Key:
+                break;
+            case kKey_Key:
+                result += separator + "key";
+                separator = ", ";
+                break;
+            case kIdentity_Key:
+                result += separator + "key=identity";
+                separator = ", ";
+                break;
+        }
         if (result.size() > 0) {
             result = "layout (" + result + ")";
         }
@@ -261,6 +290,8 @@
     Primitive fPrimitive;
     int fMaxVertices;
     int fInvocations;
+    String fWhen;
+    Key fKey;
 };
 
 } // namespace
diff --git a/src/sksl/ir/SkSLPrefixExpression.h b/src/sksl/ir/SkSLPrefixExpression.h
index acab37e..5ac84c6 100644
--- a/src/sksl/ir/SkSLPrefixExpression.h
+++ b/src/sksl/ir/SkSLPrefixExpression.h
@@ -33,9 +33,8 @@
                fOperand->hasSideEffects();
     }
 
-    virtual std::unique_ptr<Expression> constantPropagate(
-                                                        const IRGenerator& irGenerator,
-                                                        const DefinitionMap& definitions) override {
+    std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
+                                                  const DefinitionMap& definitions) override {
         if (fOperand->fKind == Expression::kFloatLiteral_Kind) {
             return std::unique_ptr<Expression>(new FloatLiteral(
                                                               irGenerator.fContext,
diff --git a/src/sksl/ir/SkSLProgram.h b/src/sksl/ir/SkSLProgram.h
index 96bd5c4..a3eeaa3 100644
--- a/src/sksl/ir/SkSLProgram.h
+++ b/src/sksl/ir/SkSLProgram.h
@@ -11,7 +11,9 @@
 #include <vector>
 #include <memory>
 
-#include "SkSLContext.h"
+#include "SkSLBoolLiteral.h"
+#include "SkSLExpression.h"
+#include "SkSLIntLiteral.h"
 #include "SkSLModifiers.h"
 #include "SkSLProgramElement.h"
 #include "SkSLSymbolTable.h"
@@ -21,11 +23,46 @@
 
 namespace SkSL {
 
+class Context;
+
 /**
  * Represents a fully-digested program, ready for code generation.
  */
 struct Program {
     struct Settings {
+        struct Value {
+            Value(bool b)
+            : fKind(kBool_Kind)
+            , fValue(b) {}
+
+            Value(int i)
+            : fKind(kInt_Kind)
+            , fValue(i) {}
+
+            std::unique_ptr<Expression> literal(const Context& context, Position position) const {
+                switch (fKind) {
+                    case Program::Settings::Value::kBool_Kind:
+                        return std::unique_ptr<Expression>(new BoolLiteral(context,
+                                                                           position,
+                                                                           fValue));
+                    case Program::Settings::Value::kInt_Kind:
+                        return std::unique_ptr<Expression>(new IntLiteral(context,
+                                                                          position,
+                                                                          fValue));
+                    default:
+                        ASSERT(false);
+                        return nullptr;
+                }
+            }
+
+            enum {
+                kBool_Kind,
+                kInt_Kind,
+            } fKind;
+
+            int fValue;
+        };
+
 #ifdef SKSL_STANDALONE
         const StandaloneShaderCaps* fCaps = &standaloneCaps;
 #else
@@ -34,6 +71,10 @@
         // if false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the y coordinate
         // must be flipped.
         bool fFlipY = false;
+        // if true, Setting objects (e.g. sk_Caps.fbFetchSupport) should be replaced with their
+        // constant equivalents during compilation
+        bool fReplaceSettings = true;
+        std::unordered_map<String, Value> fArgs;
     };
 
     struct Inputs {
@@ -57,7 +98,8 @@
     enum Kind {
         kFragment_Kind,
         kVertex_Kind,
-        kGeometry_Kind
+        kGeometry_Kind,
+        kFragmentProcessor_Kind
     };
 
     Program(Kind kind,
diff --git a/src/sksl/ir/SkSLProgramElement.h b/src/sksl/ir/SkSLProgramElement.h
index ebb4e9a..1e2bb48 100644
--- a/src/sksl/ir/SkSLProgramElement.h
+++ b/src/sksl/ir/SkSLProgramElement.h
@@ -21,7 +21,8 @@
         kFunction_Kind,
         kInterfaceBlock_Kind,
         kExtension_Kind,
-        kModifiers_Kind
+        kModifiers_Kind,
+        kSection_Kind
     };
 
     ProgramElement(Position position, Kind kind)
diff --git a/src/sksl/ir/SkSLSection.h b/src/sksl/ir/SkSLSection.h
new file mode 100644
index 0000000..f9815b1
--- /dev/null
+++ b/src/sksl/ir/SkSLSection.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_SECTION
+#define SKSL_SECTION
+
+#include "SkSLProgramElement.h"
+
+namespace SkSL {
+
+/**
+ * A section declaration (e.g. @body { body code here })..
+ */
+struct Section : public ProgramElement {
+    Section(Position position, String name, String arg, String text)
+    : INHERITED(position, kSection_Kind)
+    , fName(std::move(name))
+    , fArgument(std::move(arg))
+    , fText(std::move(text)) {}
+
+    String description() const override {
+        String result = "@" + fName;
+        if (fArgument.size()) {
+            result += "(" + fArgument + ")";
+        }
+        result += " { " + fText + " }";
+        return result;
+    }
+
+    const String fName;
+    const String fArgument;
+    const String fText;
+
+    typedef ProgramElement INHERITED;
+};
+
+} // namespace
+
+#endif
diff --git a/src/sksl/ir/SkSLSetting.cpp b/src/sksl/ir/SkSLSetting.cpp
new file mode 100644
index 0000000..2d4a8ba
--- /dev/null
+++ b/src/sksl/ir/SkSLSetting.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSLSetting.h"
+#include "SkSLIRGenerator.h"
+#include "SkSLVariableReference.h"
+
+namespace SkSL {
+
+std::unique_ptr<Expression> Setting::constantPropagate(const IRGenerator& irGenerator,
+                                                       const DefinitionMap& definitions) {
+        if (irGenerator.fSettings->fReplaceSettings) {
+            return VariableReference::copy_constant(irGenerator, fValue.get());
+        }
+        return nullptr;
+    }
+} // namespace
+
diff --git a/src/sksl/ir/SkSLSetting.h b/src/sksl/ir/SkSLSetting.h
new file mode 100644
index 0000000..995fcf5
--- /dev/null
+++ b/src/sksl/ir/SkSLSetting.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_SETTING
+#define SKSL_SETTING
+
+#include "SkSLContext.h"
+#include "SkSLExpression.h"
+
+namespace SkSL {
+
+/**
+ * Represents a compile-time constant setting, such as sk_Caps.fbFetchSupport. These are generally
+ * collapsed down to their constant representations during the compilation process.
+ */
+struct Setting : public Expression {
+    Setting(Position position, String name, std::unique_ptr<Expression> value)
+    : INHERITED(position, kSetting_Kind, value->fType)
+    , fName(std::move(name))
+    , fValue(std::move(value)) {
+        ASSERT(fValue->isConstant());
+    }
+
+    std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
+                                                  const DefinitionMap& definitions) override;
+
+    String description() const override {
+        return fName;
+    }
+
+    bool hasSideEffects() const override {
+        return false;
+    }
+
+    bool isConstant() const override {
+        return true;
+    }
+
+    const String fName;
+    std::unique_ptr<Expression> fValue;
+
+    typedef Expression INHERITED;
+};
+
+} // namespace
+
+#endif
diff --git a/src/sksl/ir/SkSLSwizzle.h b/src/sksl/ir/SkSLSwizzle.h
index 1e36c41..442e92f 100644
--- a/src/sksl/ir/SkSLSwizzle.h
+++ b/src/sksl/ir/SkSLSwizzle.h
@@ -71,10 +71,8 @@
         ASSERT(fComponents.size() >= 1 && fComponents.size() <= 4);
     }
 
-    virtual std::unique_ptr<Expression> constantPropagate(
-                                                        const IRGenerator& irGenerator,
-                                                        const DefinitionMap& definitions) override {
-
+    std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
+                                                  const DefinitionMap& definitions) override {
         if (fBase->fKind == Expression::kConstructor_Kind && fBase->isConstant()) {
             // we're swizzling a constant vector, e.g. vec4(1).x. Simplify it.
             ASSERT(fBase->fKind == Expression::kConstructor_Kind);
diff --git a/src/sksl/ir/SkSLVarDeclarations.h b/src/sksl/ir/SkSLVarDeclarations.h
index c07fee8..1eda87e 100644
--- a/src/sksl/ir/SkSLVarDeclarations.h
+++ b/src/sksl/ir/SkSLVarDeclarations.h
@@ -55,7 +55,7 @@
  * A variable declaration statement, which may consist of one or more individual variables.
  */
 struct VarDeclarations : public ProgramElement {
-    VarDeclarations(Position position, const Type* baseType, 
+    VarDeclarations(Position position, const Type* baseType,
                     std::vector<std::unique_ptr<VarDeclaration>> vars)
     : INHERITED(position, kVar_Kind)
     , fBaseType(*baseType) {
diff --git a/src/sksl/ir/SkSLVariableReference.h b/src/sksl/ir/SkSLVariableReference.h
index 92aef94..ba17437 100644
--- a/src/sksl/ir/SkSLVariableReference.h
+++ b/src/sksl/ir/SkSLVariableReference.h
@@ -14,6 +14,7 @@
 #include "SkSLFloatLiteral.h"
 #include "SkSLIRGenerator.h"
 #include "SkSLIntLiteral.h"
+#include "SkSLSetting.h"
 
 namespace SkSL {
 
@@ -104,6 +105,12 @@
                 return std::unique_ptr<Expression>(new Constructor(Position(), c->fType,
                                                                    std::move(args)));
             }
+            case Expression::kSetting_Kind: {
+                const Setting* s = (const Setting*) expr;
+                return std::unique_ptr<Expression>(new Setting(Position(), s->fName,
+                                                               copy_constant(irGenerator,
+                                                                             s->fValue.get())));
+            }
             default:
                 ABORT("unsupported constant\n");
         }