Revert "Revert "added support for sk_Dimensions to SkSL""

This reverts commit e6ab998bc2e675ab0a426ec9434be887e5527ab3.

Bug: skia:
Change-Id: I19451f924d514dadac9d2c326bcc8404a1b501e9
Reviewed-on: https://skia-review.googlesource.com/149239
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 102dc4a..8a5308f 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -133,7 +133,11 @@
 void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc,
                                        const GrRenderTargetProxy* proxy) {
     GrRenderTarget* rt = proxy->peekRenderTarget();
-    // Load the RT height uniform if it is needed to y-flip gl_FragCoord.
+    // Load the RT size uniforms if they are needed
+    if (fBuiltinUniformHandles.fRTWidthUni.isValid() &&
+        fRenderTargetState.fRenderTargetSize.fWidth != rt->width()) {
+        fProgramDataManager.set1f(fBuiltinUniformHandles.fRTWidthUni, SkIntToScalar(rt->width()));
+    }
     if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
         fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) {
         fProgramDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height()));
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index ba290ac..f6890fd 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -159,6 +159,15 @@
     SkASSERT(fInstanceStride == primProc.debugOnly_instanceStride());
 }
 
+void GrGLProgramBuilder::addInputVars(const SkSL::Program::Inputs& inputs) {
+    if (inputs.fRTWidth) {
+        this->addRTWidthUniform(SKSL_RTWIDTH_NAME);
+    }
+    if (inputs.fRTHeight) {
+        this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
+    }
+}
+
 GrGLProgram* GrGLProgramBuilder::finalize() {
     TRACE_EVENT0("skia", TRACE_FUNC);
 
@@ -204,9 +213,7 @@
         if (GR_GL_GET_ERROR(this->gpu()->glInterface()) == GR_GL_NO_ERROR) {
             cached = this->checkLinkStatus(programID);
             if (cached) {
-                if (inputs.fRTHeight) {
-                    this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
-                }
+                this->addInputVars(inputs);
                 this->computeCountsAndStrides(programID, primProc, false);
             }
         } else {
@@ -231,9 +238,7 @@
             return nullptr;
         }
         inputs = fs->fInputs;
-        if (inputs.fRTHeight) {
-            this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
-        }
+        this->addInputVars(inputs);
         if (!this->compileAndAttachShaders(glsl.c_str(), glsl.size(), programID,
                                            GR_GL_FRAGMENT_SHADER, &shadersToDelete, settings,
                                            inputs)) {
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index 64e4269..b601b6b 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -48,6 +48,7 @@
     GrGLProgramBuilder(GrGLGpu*, const GrPipeline&, const GrPrimitiveProcessor&,
                        GrProgramDesc*);
 
+    void addInputVars(const SkSL::Program::Inputs& inputs);
     bool compileAndAttachShaders(const char* glsl,
                                  int length,
                                  GrGLuint programId,
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 66e333a..7b7b18d 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -371,6 +371,15 @@
     this->uniformHandler()->appendUniformDecls(visibility, out);
 }
 
+void GrGLSLProgramBuilder::addRTWidthUniform(const char* name) {
+        SkASSERT(!fUniformHandles.fRTWidthUni.isValid());
+        GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
+        fUniformHandles.fRTWidthUni =
+            uniformHandler->internalAddUniformArray(kFragment_GrShaderFlag,
+                                                    kHalf_GrSLType, kDefault_GrSLPrecision,
+                                                    name, false, 0, nullptr);
+}
+
 void GrGLSLProgramBuilder::addRTHeightUniform(const char* name) {
         SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
         GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h
index 8d263b8..073cfc6 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.h
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.h
@@ -49,8 +49,12 @@
         return this->uniformHandler()->samplerSwizzle(handle);
     }
 
-    // Used to add a uniform for the RenderTarget height (used for frag position) without mangling
+    // Used to add a uniform for the RenderTarget width (used for sk_Width) without mangling
     // the name of the uniform inside of a stage.
+    void addRTWidthUniform(const char* name);
+
+    // Used to add a uniform for the RenderTarget height (used for sk_Height and frag position)
+    // without mangling the name of the uniform inside of a stage.
     void addRTHeightUniform(const char* name);
 
     // Generates a name for a variable. The generated string will be name prefixed by the prefix
diff --git a/src/gpu/glsl/GrGLSLUniformHandler.h b/src/gpu/glsl/GrGLSLUniformHandler.h
index ae87faf..26681c1 100644
--- a/src/gpu/glsl/GrGLSLUniformHandler.h
+++ b/src/gpu/glsl/GrGLSLUniformHandler.h
@@ -20,7 +20,9 @@
 // Handles for program uniforms (other than per-effect uniforms)
 struct GrGLSLBuiltinUniformHandles {
     GrGLSLProgramDataManager::UniformHandle fRTAdjustmentUni;
-    // We use the render target height to provide a y-down frag coord when specifying
+    // Render target width, used to implement sk_Width
+    GrGLSLProgramDataManager::UniformHandle fRTWidthUni;
+    // Render target height, used to implement sk_Height and to calculate sk_FragCoord when
     // origin_upper_left is not supported.
     GrGLSLProgramDataManager::UniformHandle fRTHeightUni;
 };
diff --git a/src/sksl/README b/src/sksl/README
index dd0af98..5062ed9 100644
--- a/src/sksl/README
+++ b/src/sksl/README
@@ -57,6 +57,7 @@
   Use swizzles instead.
 * Use texture() instead of textureProj(), e.g. texture(sampler2D, float3) is
   equivalent to GLSL's textureProj(sampler2D, float3)
+* Render target width and height are available via sk_Width and sk_Height
 * some built-in functions and one or two rarely-used language features are not
   yet supported (sorry!)
 
diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp
index 9d39595..4eab6ba 100644
--- a/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -246,6 +246,12 @@
             this->write("%s");
             fFormatArgs.push_back(String("args.fOutputColor"));
             break;
+        case SK_WIDTH_BUILTIN:
+            this->write("sk_Width");
+            break;
+        case SK_HEIGHT_BUILTIN:
+            this->write("sk_Height");
+            break;
         default:
             if (ref.fVariable.fType.kind() == Type::kSampler_Kind) {
                 this->write("%s");
@@ -446,6 +452,9 @@
     }
 }
 
+void CPPCodeGenerator::writeInputVars() {
+}
+
 void CPPCodeGenerator::writePrivateVars() {
     for (const auto& p : fProgram) {
         if (ProgramElement::kVar_Kind == p.fKind) {
diff --git a/src/sksl/SkSLCPPCodeGenerator.h b/src/sksl/SkSLCPPCodeGenerator.h
index 014f917..39255d6 100644
--- a/src/sksl/SkSLCPPCodeGenerator.h
+++ b/src/sksl/SkSLCPPCodeGenerator.h
@@ -68,6 +68,8 @@
 
     void writeVarInitializer(const Variable& var, const Expression& value) override;
 
+    void writeInputVars() override;
+
     void writePrivateVars();
 
     void writePrivateVarValues();
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index f902962..339da2b 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -28,6 +28,8 @@
 #define SK_LASTFRAGCOLOR_BUILTIN       10008
 #define SK_MAIN_X_BUILTIN              10009
 #define SK_MAIN_Y_BUILTIN              10010
+#define SK_WIDTH_BUILTIN               10011
+#define SK_HEIGHT_BUILTIN              10012
 #define SK_FRAGCOORD_BUILTIN              15
 #define SK_CLOCKWISE_BUILTIN              17
 #define SK_VERTEXID_BUILTIN               42
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
index 85e26a1..a12357e 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp
@@ -730,7 +730,7 @@
     if (!fProgram.fSettings.fFlipY) {
         this->write("gl_FragCoord");
     } else if (const char* extension =
-               fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
+                                  fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
         if (!fSetupFragPositionGlobal) {
             if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
                 this->writeExtension(extension);
@@ -740,20 +740,13 @@
         }
         this->write("gl_FragCoord");
     } else {
-        if (!fSetupFragPositionGlobal) {
+        if (!fSetupFragPositionLocal) {
             // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
             // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
             // depending on the surrounding code, accessing .xy with a uniform involved can
             // do the same thing. Copying gl_FragCoord.xy into a temp float2 beforehand
             // (and only accessing .xy) seems to "fix" things.
             const char* precision = usesPrecisionModifiers() ? "highp " : "";
-            fGlobals.writeText("uniform ");
-            fGlobals.writeText(precision);
-            fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
-            fSetupFragPositionGlobal = true;
-        }
-        if (!fSetupFragPositionLocal) {
-            const char* precision = usesPrecisionModifiers() ? "highp " : "";
             fFunctionHeader += precision;
             fFunctionHeader += "    vec2 _sktmpCoord = gl_FragCoord.xy;\n";
             fFunctionHeader += precision;
@@ -777,6 +770,12 @@
         case SK_FRAGCOORD_BUILTIN:
             this->writeFragCoord();
             break;
+        case SK_WIDTH_BUILTIN:
+            this->write("u_skRTWidth");
+            break;
+        case SK_HEIGHT_BUILTIN:
+            this->write("u_skRTHeight");
+            break;
         case SK_CLOCKWISE_BUILTIN:
             this->write(fProgram.fSettings.fFlipY ? "(!gl_FrontFacing)" : "gl_FrontFacing");
             break;
@@ -1494,6 +1493,21 @@
     }
 }
 
+void GLSLCodeGenerator::writeInputVars() {
+    if (fProgram.fInputs.fRTWidth) {
+        const char* precision = usesPrecisionModifiers() ? "highp " : "";
+        fGlobals.writeText("uniform ");
+        fGlobals.writeText(precision);
+        fGlobals.writeText("float " SKSL_RTWIDTH_NAME ";\n");
+    }
+    if (fProgram.fInputs.fRTHeight) {
+        const char* precision = usesPrecisionModifiers() ? "highp " : "";
+        fGlobals.writeText("uniform ");
+        fGlobals.writeText(precision);
+        fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
+    }
+}
+
 bool GLSLCodeGenerator::generateCode() {
     fProgramKind = fProgram.fKind;
     if (fProgramKind != Program::kPipelineStage_Kind) {
@@ -1512,6 +1526,7 @@
     fOut = rawOut;
 
     write_stringstream(fExtensions, *rawOut);
+    this->writeInputVars();
     write_stringstream(fGlobals, *rawOut);
 
     if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h
index 3083b3e..95aa464 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.h
+++ b/src/sksl/SkSLGLSLCodeGenerator.h
@@ -118,7 +118,7 @@
 
     void writeModifiers(const Modifiers& modifiers, bool globalContext);
 
-    void writeGlobalVars(const VarDeclaration& vs);
+    virtual void writeInputVars();
 
     virtual void writeVarInitializer(const Variable& var, const Expression& value);
 
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index a793ddd..5d4e5c3 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -1025,16 +1025,25 @@
         }
         case Symbol::kVariable_Kind: {
             const Variable* var = (const Variable*) result;
-#ifndef SKSL_STANDALONE
-            if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) {
-                fInputs.fFlipY = true;
-                if (fSettings->fFlipY &&
-                    (!fSettings->fCaps ||
-                     !fSettings->fCaps->fragCoordConventionsExtensionString())) {
+            switch (var->fModifiers.fLayout.fBuiltin) {
+                case SK_WIDTH_BUILTIN:
+                    fInputs.fRTWidth = true;
+                    break;
+                case SK_HEIGHT_BUILTIN:
                     fInputs.fRTHeight = true;
-                }
-            }
+                    break;
+#ifndef SKSL_STANDALONE
+                case SK_FRAGCOORD_BUILTIN:
+                    if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) {
+                        fInputs.fFlipY = true;
+                        if (fSettings->fFlipY &&
+                            (!fSettings->fCaps ||
+                             !fSettings->fCaps->fragCoordConventionsExtensionString())) {
+                            fInputs.fRTHeight = true;
+                        }
+                    }
 #endif
+            }
             // default to kRead_RefKind; this will be corrected later if the variable is written to
             return std::unique_ptr<VariableReference>(new VariableReference(
                                                                  identifier.fOffset,
diff --git a/src/sksl/ir/SkSLProgram.h b/src/sksl/ir/SkSLProgram.h
index 59c9122..4cbde55 100644
--- a/src/sksl/ir/SkSLProgram.h
+++ b/src/sksl/ir/SkSLProgram.h
@@ -18,6 +18,9 @@
 #include "SkSLProgramElement.h"
 #include "SkSLSymbolTable.h"
 
+// name of the render target width uniform
+#define SKSL_RTWIDTH_NAME "u_skRTWidth"
+
 // name of the render target height uniform
 #define SKSL_RTHEIGHT_NAME "u_skRTHeight"
 
@@ -88,6 +91,9 @@
     };
 
     struct Inputs {
+        // if true, this program requires the render target width uniform to be defined
+        bool fRTWidth;
+
         // if true, this program requires the render target height uniform to be defined
         bool fRTHeight;
 
@@ -96,12 +102,13 @@
         bool fFlipY;
 
         void reset() {
+            fRTWidth = false;
             fRTHeight = false;
             fFlipY = false;
         }
 
         bool isEmpty() {
-            return !fRTHeight && !fFlipY;
+            return !fRTWidth && !fRTHeight && !fFlipY;
         }
     };
 
diff --git a/src/sksl/sksl_fp.inc b/src/sksl/sksl_fp.inc
index d407fd0..c5edc00 100644
--- a/src/sksl/sksl_fp.inc
+++ b/src/sksl/sksl_fp.inc
@@ -20,6 +20,9 @@
 layout(builtin=10004) out half4 sk_OutColor;
 layout(builtin=10005) float2[] sk_TransformedCoords2D;
 layout(builtin=10006) sampler2D[] sk_TextureSamplers;
+layout(builtin=10011) half sk_Width;
+layout(builtin=10012) half sk_Height;
 
 half4 process(fragmentProcessor fp);
+
 )
diff --git a/src/sksl/sksl_frag.inc b/src/sksl/sksl_frag.inc
index 202747a..5bc5f55 100644
--- a/src/sksl/sksl_frag.inc
+++ b/src/sksl/sksl_frag.inc
@@ -17,5 +17,7 @@
 
 layout(location=0,index=0,builtin=10001) out half4 sk_FragColor;
 layout(builtin=10008) half4 sk_LastFragColor;
+layout(builtin=10011) half sk_Width;
+layout(builtin=10012) half sk_Height;
 
 )
diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp
index 8acec62..9529766 100644
--- a/tests/SkSLGLSLTest.cpp
+++ b/tests/SkSLGLSLTest.cpp
@@ -1154,6 +1154,38 @@
          "}\n");
 }
 
+DEF_TEST(SkSLWidthAndHeight, r) {
+    SkSL::Program::Settings settings;
+    sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
+    settings.fCaps = caps.get();
+    SkSL::Program::Inputs inputs;
+    test(r,
+         "void main() { sk_FragColor.r = sk_FragCoord.x / sk_Width; }",
+         settings,
+         "#version 400\n"
+         "uniform float u_skRTWidth;\n"
+         "out vec4 sk_FragColor;\n"
+         "void main() {\n"
+         "    sk_FragColor.x = gl_FragCoord.x / u_skRTWidth;\n"
+         "}\n",
+         &inputs);
+    REPORTER_ASSERT(r, inputs.fRTWidth);
+    REPORTER_ASSERT(r, !inputs.fRTHeight);
+
+    test(r,
+         "void main() { sk_FragColor.r = sk_FragCoord.y / sk_Height; }",
+         settings,
+         "#version 400\n"
+         "uniform float u_skRTHeight;\n"
+         "out vec4 sk_FragColor;\n"
+         "void main() {\n"
+         "    sk_FragColor.x = gl_FragCoord.y / u_skRTHeight;\n"
+         "}\n",
+         &inputs);
+    REPORTER_ASSERT(r, !inputs.fRTWidth);
+    REPORTER_ASSERT(r, inputs.fRTHeight);
+}
+
 DEF_TEST(SkSLClockwise, r) {
     test(r,
          "void main() { sk_FragColor = half4(sk_Clockwise ? +1 : -1); }",