Revert "Revert "converted vertex shaders to device coords""

This reverts commit 29b3434e48ca41672266ac40f5b9e8f8a0405cb5.

Reason for revert: The Chrome perf regression is suspect & the Nexus 5 is broken w/o this CL.

Original change's description:
> Revert "converted vertex shaders to device coords"
> 
> This reverts commit e7e81c15c144b8133f696d0744ed9f7e8d06e936.
> 
> Reason for revert: Chrome perf regressions
> 
> Bug: skia:
> Change-Id: I17fadc97c4b8e80bfdccbf123554614a00c58473
> Reviewed-on: https://skia-review.googlesource.com/99040
> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
> Commit-Queue: Ethan Nicholas <ethannicholas@google.com>

TBR=csmartdalton@google.com,ethannicholas@google.com

Change-Id: Iff3c9fce65beeca16028ae59d4d08b1413b90530
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/99241
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/gl/GrGLUniformHandler.cpp b/src/gpu/gl/GrGLUniformHandler.cpp
index b3b4b9f..39392f9 100644
--- a/src/gpu/gl/GrGLUniformHandler.cpp
+++ b/src/gpu/gl/GrGLUniformHandler.cpp
@@ -10,10 +10,19 @@
 #include "gl/GrGLCaps.h"
 #include "gl/GrGLGpu.h"
 #include "gl/builders/GrGLProgramBuilder.h"
+#include "SkSLCompiler.h"
 
 #define GL_CALL(X) GR_GL_CALL(this->glGpu()->glInterface(), X)
 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->glGpu()->glInterface(), R, X)
 
+bool valid_name(const char* name) {
+    // disallow unknown names that start with "sk_"
+    if (!strncmp(name, GR_NO_MANGLE_PREFIX, strlen(GR_NO_MANGLE_PREFIX))) {
+        return !strcmp(name, SkSL::Compiler::RTADJUST_NAME);
+    }
+    return true;
+}
+
 GrGLSLUniformHandler::UniformHandle GrGLUniformHandler::internalAddUniformArray(
                                                                             uint32_t visibility,
                                                                             GrSLType type,
@@ -23,6 +32,7 @@
                                                                             int arrayCount,
                                                                             const char** outName) {
     SkASSERT(name && strlen(name));
+    SkASSERT(valid_name(name));
     SkASSERT(0 != visibility);
     SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeTemporarilyAcceptsPrecision(type));
 
@@ -36,7 +46,7 @@
     // uniform view matrix, they should upload the view matrix in their setData along with regular
     // uniforms.
     char prefix = 'u';
-    if ('u' == name[0]) {
+    if ('u' == name[0] || !strncmp(name, GR_NO_MANGLE_PREFIX, strlen(GR_NO_MANGLE_PREFIX))) {
         prefix = '\0';
     }
     fProgramBuilder->nameVariable(uni.fVariable.accessName(), prefix, name, mangleName);
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 118b904..04ebc6a 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -15,6 +15,7 @@
 #include "glsl/GrGLSLGeometryProcessor.h"
 #include "glsl/GrGLSLVarying.h"
 #include "glsl/GrGLSLXferProcessor.h"
+#include "SkSLCompiler.h"
 
 const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
 
@@ -74,13 +75,16 @@
     this->nameExpression(outputCoverage, "outputCoverage");
 
     SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid());
-    GrShaderFlags rtAdjustVisibility = kVertex_GrShaderFlag;
+    GrShaderFlags rtAdjustVisibility;
     if (proc.willUseGeoShader()) {
-        rtAdjustVisibility |= kGeometry_GrShaderFlag;
+        rtAdjustVisibility = kGeometry_GrShaderFlag;
+    } else {
+        rtAdjustVisibility = kVertex_GrShaderFlag;
     }
-    fUniformHandles.fRTAdjustmentUni = this->uniformHandler()->addUniform(rtAdjustVisibility,
-                                                                          kFloat4_GrSLType,
-                                                                          "rtAdjustment");
+    fUniformHandles.fRTAdjustmentUni = this->uniformHandler()->addUniform(
+                                                                     rtAdjustVisibility,
+                                                                     kFloat4_GrSLType,
+                                                                     SkSL::Compiler::RTADJUST_NAME);
     const char* rtAdjustName =
         this->uniformHandler()->getUniformCStr(fUniformHandles.fRTAdjustmentUni);
 
diff --git a/src/gpu/glsl/GrGLSLUniformHandler.h b/src/gpu/glsl/GrGLSLUniformHandler.h
index e1511c2..662486e 100644
--- a/src/gpu/glsl/GrGLSLUniformHandler.h
+++ b/src/gpu/glsl/GrGLSLUniformHandler.h
@@ -12,6 +12,9 @@
 #include "GrShaderVar.h"
 #include "GrSwizzle.h"
 
+// variable names beginning with this prefix will not be mangled
+#define GR_NO_MANGLE_PREFIX "sk_"
+
 class GrGLSLProgramBuilder;
 
 class GrGLSLUniformHandler {
@@ -51,7 +54,8 @@
                                   int arrayCount,
                                   const char** outName = nullptr) {
         SkASSERT(!GrSLTypeIsCombinedSamplerType(type));
-        return this->internalAddUniformArray(visibility, type, precision, name, true, arrayCount,
+        bool mangle = strncmp(name, GR_NO_MANGLE_PREFIX, strlen(GR_NO_MANGLE_PREFIX));
+        return this->internalAddUniformArray(visibility, type, precision, name, mangle, arrayCount,
                                              outName);
     }
 
@@ -61,7 +65,8 @@
                                   int arrayCount,
                                   const char** outName = nullptr) {
         SkASSERT(!GrSLTypeIsCombinedSamplerType(type));
-        return this->internalAddUniformArray(visibility, type, kDefault_GrSLPrecision, name, true,
+        bool mangle = strncmp(name, GR_NO_MANGLE_PREFIX, strlen(GR_NO_MANGLE_PREFIX));
+        return this->internalAddUniformArray(visibility, type, kDefault_GrSLPrecision, name, mangle,
                                              arrayCount, outName);
     }
 
diff --git a/src/gpu/glsl/GrGLSLVertexGeoBuilder.cpp b/src/gpu/glsl/GrGLSLVertexGeoBuilder.cpp
index 1cf85f7..dba57bb 100644
--- a/src/gpu/glsl/GrGLSLVertexGeoBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLVertexGeoBuilder.cpp
@@ -23,16 +23,14 @@
             out->appendf("{float2 _posTmp = %s;", devPos);
         }
         out->appendf("_posTmp = floor(_posTmp) + half2(0.5, 0.5);"
-                     "sk_Position = float4(_posTmp.x * %s.x + %s.y,"
-                                          "_posTmp.y * %s.z + %s.w, 0, 1);}",
-                     rtAdjustName, rtAdjustName, rtAdjustName, rtAdjustName);
+                     "sk_Position = float4(_posTmp, 0, 1);}");
     } else if (kFloat3_GrSLType == devPosType) {
-        out->appendf("sk_Position = float4(dot(%s.xz, %s.xy), dot(%s.yz, %s.zw), 0, %s.z);",
-                     devPos, rtAdjustName, devPos, rtAdjustName, devPos);
+        out->appendf("sk_Position = float4(%s.x , %s.y, 0, %s.z);",
+                     devPos, devPos, devPos);
     } else {
         SkASSERT(kFloat2_GrSLType == devPosType);
-        out->appendf("sk_Position = float4(%s.x * %s.x + %s.y, %s.y * %s.z + %s.w, 0, 1);",
-                     devPos, rtAdjustName, rtAdjustName, devPos, rtAdjustName, rtAdjustName);
+        out->appendf("sk_Position = float4(%s.x , %s.y, 0, 1);",
+                     devPos, devPos);
     }
 }
 
diff --git a/src/gpu/vk/GrVkUniformHandler.cpp b/src/gpu/vk/GrVkUniformHandler.cpp
index 040926e..e76cbda 100644
--- a/src/gpu/vk/GrVkUniformHandler.cpp
+++ b/src/gpu/vk/GrVkUniformHandler.cpp
@@ -203,7 +203,7 @@
     // uniform view matrix, they should upload the view matrix in their setData along with regular
     // uniforms.
     char prefix = 'u';
-    if ('u' == name[0]) {
+    if ('u' == name[0] || !strncmp(name, GR_NO_MANGLE_PREFIX, strlen(GR_NO_MANGLE_PREFIX))) {
         prefix = '\0';
     }
     fProgramBuilder->nameVariable(uni.fVariable.accessName(), prefix, name, mangleName);
diff --git a/src/sksl/README b/src/sksl/README
index 7c2cf04..e9e4656 100644
--- a/src/sksl/README
+++ b/src/sksl/README
@@ -38,7 +38,8 @@
   'do_something_else();', depending on whether that cap is enabled or not.
 * no #version statement is required, and it will be ignored if present
 * the output color is sk_FragColor (do not declare it)
-* use sk_Position instead of gl_Position
+* use sk_Position instead of gl_Position. sk_Position is in device coordinates
+  rather than normalized coordinates.
 * use sk_PointSize instead of gl_PointSize
 * use sk_VertexID instead of gl_VertexID
 * use sk_InstanceID instead of gl_InstanceID
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index bf321c8..7589da98 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -200,7 +200,8 @@
     fIRGenerator->fSymbolTable->add(skArgsName, std::unique_ptr<Symbol>(skArgs));
 
     std::vector<std::unique_ptr<ProgramElement>> ignored;
-    fIRGenerator->convertProgram(SKSL_INCLUDE, strlen(SKSL_INCLUDE), *fTypes, &ignored);
+    fIRGenerator->convertProgram(Program::kFragment_Kind, SKSL_INCLUDE, strlen(SKSL_INCLUDE),
+                                 *fTypes, &ignored);
     fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
     if (fErrorCount) {
         printf("Unexpected errors: %s\n", fErrorText.c_str());
@@ -1164,19 +1165,19 @@
     std::vector<std::unique_ptr<ProgramElement>> elements;
     switch (kind) {
         case Program::kVertex_Kind:
-            fIRGenerator->convertProgram(SKSL_VERT_INCLUDE, strlen(SKSL_VERT_INCLUDE), *fTypes,
-                                         &elements);
+            fIRGenerator->convertProgram(kind, SKSL_VERT_INCLUDE, strlen(SKSL_VERT_INCLUDE),
+                                         *fTypes, &elements);
             break;
         case Program::kFragment_Kind:
-            fIRGenerator->convertProgram(SKSL_FRAG_INCLUDE, strlen(SKSL_FRAG_INCLUDE), *fTypes,
-                                         &elements);
+            fIRGenerator->convertProgram(kind, SKSL_FRAG_INCLUDE, strlen(SKSL_FRAG_INCLUDE),
+                                         *fTypes, &elements);
             break;
         case Program::kGeometry_Kind:
-            fIRGenerator->convertProgram(SKSL_GEOM_INCLUDE, strlen(SKSL_GEOM_INCLUDE), *fTypes,
-                                         &elements);
+            fIRGenerator->convertProgram(kind, SKSL_GEOM_INCLUDE, strlen(SKSL_GEOM_INCLUDE),
+                                         *fTypes, &elements);
             break;
         case Program::kFragmentProcessor_Kind:
-            fIRGenerator->convertProgram(SKSL_FP_INCLUDE, strlen(SKSL_FP_INCLUDE), *fTypes,
+            fIRGenerator->convertProgram(kind, SKSL_FP_INCLUDE, strlen(SKSL_FP_INCLUDE), *fTypes,
                                          &elements);
             break;
     }
@@ -1188,7 +1189,7 @@
     }
     std::unique_ptr<String> textPtr(new String(std::move(text)));
     fSource = textPtr.get();
-    fIRGenerator->convertProgram(textPtr->c_str(), textPtr->size(), *fTypes, &elements);
+    fIRGenerator->convertProgram(kind, textPtr->c_str(), textPtr->size(), *fTypes, &elements);
     if (!fErrorCount) {
         for (auto& element : elements) {
             if (element->fKind == ProgramElement::kFunction_Kind) {
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index ca39c8c..eb2fc45 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -45,6 +45,9 @@
  */
 class Compiler : public ErrorReporter {
 public:
+    static constexpr const char* RTADJUST_NAME  = "sk_RTAdjust";
+    static constexpr const char* PERVERTEX_NAME = "sk_PerVertex";
+
     enum Flags {
         kNone_Flags = 0,
         // permits static if/switch statements to be used with non-constant tests. This is used when
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 019aee8..3388a47 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -154,6 +154,9 @@
     this->pushSymbolTable();
     fInvocations = -1;
     fInputs.reset();
+    fSkPerVertex = nullptr;
+    fRTAdjust = nullptr;
+    fRTAdjustInterfaceBlock = nullptr;
 }
 
 void IRGenerator::finish() {
@@ -171,8 +174,26 @@
             return this->convertBlock((ASTBlock&) statement);
         case ASTStatement::kVarDeclaration_Kind:
             return this->convertVarDeclarationStatement((ASTVarDeclarationStatement&) statement);
-        case ASTStatement::kExpression_Kind:
-            return this->convertExpressionStatement((ASTExpressionStatement&) statement);
+        case ASTStatement::kExpression_Kind: {
+            std::unique_ptr<Statement> result =
+                              this->convertExpressionStatement((ASTExpressionStatement&) statement);
+            if (fRTAdjust && Program::kGeometry_Kind == fKind) {
+                ASSERT(result->fKind == Statement::kExpression_Kind);
+                Expression& expr = *((ExpressionStatement&) *result).fExpression;
+                if (expr.fKind == Expression::kFunctionCall_Kind) {
+                    FunctionCall& fc = (FunctionCall&) expr;
+                    if (fc.fFunction.fBuiltin && fc.fFunction.fName == "EmitVertex") {
+                        std::vector<std::unique_ptr<Statement>> statements;
+                        statements.push_back(getNormalizeSkPositionCode());
+                        statements.push_back(std::move(result));
+                        return std::unique_ptr<Block>(new Block(statement.fOffset,
+                                                                std::move(statements),
+                                                                fSymbolTable));
+                    }
+                }
+            }
+            return result;
+        }
         case ASTStatement::kIf_Kind:
             return this->convertIf((ASTIfStatement&) statement);
         case ASTStatement::kFor_Kind:
@@ -257,6 +278,11 @@
         }
         auto var = std::unique_ptr<Variable>(new Variable(decl.fOffset, decl.fModifiers,
                                                           varDecl.fName, *type, storage));
+        if (var->fName == Compiler::RTADJUST_NAME) {
+            ASSERT(!fRTAdjust);
+            ASSERT(var->fType == *fContext.fFloat4_Type);
+            fRTAdjust = var.get();
+        }
         std::unique_ptr<Expression> value;
         if (varDecl.fValue) {
             value = this->convertExpression(*varDecl.fValue);
@@ -472,6 +498,10 @@
 
 std::unique_ptr<Statement> IRGenerator::convertReturn(const ASTReturnStatement& r) {
     ASSERT(fCurrentFunction);
+    // early returns from a vertex main function will bypass the sk_Position normalization, so
+    // assert that we aren't doing that. It is of course possible to fix this by adding a
+    // normalization before each return, but it will probably never actually be necessary.
+    ASSERT(Program::kVertex_Kind != fKind || !fRTAdjust || "main" != fCurrentFunction->fName);
     if (r.fExpression) {
         std::unique_ptr<Expression> result = this->convertExpression(*r.fExpression);
         if (!result) {
@@ -575,6 +605,40 @@
     return std::unique_ptr<Block>(new Block(-1, std::move(children)));
 }
 
+std::unique_ptr<Statement> IRGenerator::getNormalizeSkPositionCode() {
+    // sk_Position = float4(sk_Position.x * rtAdjust.x + sk_Position.w * rtAdjust.y,
+    //                      sk_Position.y * rtAdjust.z + sk_Position.w * rtAdjust.w,
+    //                      0,
+    //                      sk_Position.w);
+    ASSERT(fSkPerVertex && fRTAdjust);
+    #define REF(var) std::unique_ptr<Expression>(\
+                                  new VariableReference(-1, *var, VariableReference::kRead_RefKind))
+    #define FIELD(var, idx) std::unique_ptr<Expression>(\
+                    new FieldAccess(REF(var), idx, FieldAccess::kAnonymousInterfaceBlock_OwnerKind))
+    #define POS std::unique_ptr<Expression>(new FieldAccess(REF(fSkPerVertex), 0, \
+                                                   FieldAccess::kAnonymousInterfaceBlock_OwnerKind))
+    #define ADJUST (fRTAdjustInterfaceBlock ? \
+                    FIELD(fRTAdjustInterfaceBlock, fRTAdjustFieldIndex) : \
+                    REF(fRTAdjust))
+    #define SWIZZLE(expr, field) std::unique_ptr<Expression>(new Swizzle(fContext, expr, { field }))
+    #define OP(left, op, right) std::unique_ptr<Expression>(\
+                                   new BinaryExpression(-1, left, op, right, *fContext.fFloat_Type))
+    std::vector<std::unique_ptr<Expression>> children;
+    children.push_back(OP(OP(SWIZZLE(POS, 0), Token::STAR, SWIZZLE(ADJUST, 0)),
+                          Token::PLUS,
+                          OP(SWIZZLE(POS, 3), Token::STAR, SWIZZLE(ADJUST, 1))));
+    children.push_back(OP(OP(SWIZZLE(POS, 1), Token::STAR, SWIZZLE(ADJUST, 2)),
+                          Token::PLUS,
+                          OP(SWIZZLE(POS, 3), Token::STAR, SWIZZLE(ADJUST, 3))));
+    children.push_back(std::unique_ptr<Expression>(new FloatLiteral(fContext, -1, 0.0)));
+    children.push_back(SWIZZLE(POS, 3));
+    std::unique_ptr<Expression> result = OP(POS, Token::EQ,
+                                 std::unique_ptr<Expression>(new Constructor(-1,
+                                                                             *fContext.fFloat4_Type,
+                                                                             std::move(children))));
+    return std::unique_ptr<Statement>(new ExpressionStatement(std::move(result)));
+}
+
 void IRGenerator::convertFunction(const ASTFunction& f) {
     const Type* returnType = this->convertType(*f.fReturnType);
     if (!returnType) {
@@ -691,7 +755,9 @@
         }
         // conservatively assume all user-defined functions have side effects
         ((Modifiers&) decl->fModifiers).fFlags |= Modifiers::kHasSideEffects_Flag;
-
+        if (Program::kVertex_Kind == fKind && f.fName == "main" && fRTAdjust) {
+            body->fStatements.insert(body->fStatements.end(), this->getNormalizeSkPositionCode());
+        }
         fProgramElements->push_back(std::unique_ptr<FunctionDefinition>(
                                         new FunctionDefinition(f.fOffset, *decl, std::move(body))));
     }
@@ -702,6 +768,7 @@
     AutoSymbolTable table(this);
     std::vector<Type::Field> fields;
     bool haveRuntimeArray = false;
+    bool foundRTAdjust = false;
     for (size_t i = 0; i < intf.fDeclarations.size(); i++) {
         std::unique_ptr<VarDeclarations> decl = this->convertVarDeclarations(
                                                                          *intf.fDeclarations[i],
@@ -716,6 +783,11 @@
                               "only the last entry in an interface block may be a runtime-sized "
                               "array");
             }
+            if (vd.fVar == fRTAdjust) {
+                foundRTAdjust = true;
+                ASSERT(vd.fVar->fType == *fContext.fFloat4_Type);
+                fRTAdjustFieldIndex = fields.size();
+            }
             fields.push_back(Type::Field(vd.fVar->fModifiers, vd.fVar->fName,
                                          &vd.fVar->fType));
             if (vd.fValue) {
@@ -769,6 +841,9 @@
     Variable* var = new Variable(intf.fOffset, intf.fModifiers,
                                  intf.fInstanceName.fLength ? intf.fInstanceName : intf.fTypeName,
                                  *type, Variable::kGlobal_Storage);
+    if (foundRTAdjust) {
+        fRTAdjustInterfaceBlock = var;
+    }
     old->takeOwnership(var);
     if (intf.fInstanceName.fLength) {
         old->addWithoutOwnership(intf.fInstanceName, var);
@@ -778,6 +853,10 @@
                                                                        (int) i)));
         }
     }
+    if (var->fName == Compiler::PERVERTEX_NAME) {
+        ASSERT(!fSkPerVertex);
+        fSkPerVertex = var;
+    }
     return std::unique_ptr<InterfaceBlock>(new InterfaceBlock(intf.fOffset,
                                                               var,
                                                               intf.fTypeName,
@@ -2027,10 +2106,12 @@
     }
 }
 
-void IRGenerator::convertProgram(const char* text,
+void IRGenerator::convertProgram(Program::Kind kind,
+                                 const char* text,
                                  size_t length,
                                  SymbolTable& types,
                                  std::vector<std::unique_ptr<ProgramElement>>* out) {
+    fKind = kind;
     fProgramElements = out;
     Parser parser(text, length, types, fErrors);
     std::vector<std::unique_ptr<ASTDeclaration>> parsed = parser.file();
diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h
index 1df9b65..327fe6f 100644
--- a/src/sksl/SkSLIRGenerator.h
+++ b/src/sksl/SkSLIRGenerator.h
@@ -62,7 +62,8 @@
     IRGenerator(const Context* context, std::shared_ptr<SymbolTable> root,
                 ErrorReporter& errorReporter);
 
-    void convertProgram(const char* text,
+    void convertProgram(Program::Kind kind,
+                        const char* text,
                         size_t length,
                         SymbolTable& types,
                         std::vector<std::unique_ptr<ProgramElement>>* result);
@@ -156,12 +157,15 @@
     std::unique_ptr<Statement> convertWhile(const ASTWhileStatement& w);
     void convertEnum(const ASTEnum& e);
     std::unique_ptr<Block> applyInvocationIDWorkaround(std::unique_ptr<Block> main);
+    // returns a statement which converts sk_Position from device to normalized coordinates
+    std::unique_ptr<Statement> getNormalizeSkPositionCode();
 
     void fixRectSampling(std::vector<std::unique_ptr<Expression>>& arguments);
     void checkValid(const Expression& expr);
     void markWrittenTo(const Expression& expr, bool readWrite);
     void getConstantInt(const Expression& value, int64_t* out);
 
+    Program::Kind fKind;
     const FunctionDeclaration* fCurrentFunction;
     std::unordered_map<String, Program::Settings::Value> fCapsMap;
     std::shared_ptr<SymbolTable> fRootSymbolTable;
@@ -175,6 +179,10 @@
     ErrorReporter& fErrors;
     int fInvocations;
     std::vector<std::unique_ptr<ProgramElement>>* fProgramElements;
+    Variable* fSkPerVertex;
+    Variable* fRTAdjust;
+    Variable* fRTAdjustInterfaceBlock;
+    int fRTAdjustFieldIndex;
 
     friend class AutoSymbolTable;
     friend class AutoLoopLevel;