Slightly generalize GPU hard stop gradient implementation.
authorBrian Salomon <bsalomon@google.com>
Thu, 13 Oct 2016 20:08:36 +0000 (16:08 -0400)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Thu, 13 Oct 2016 20:30:20 +0000 (20:30 +0000)
With this CL we handle single off-center hardstop gradients.

BUG=chromium:543625

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=3303

Change-Id: Ic754e87469475ce15865c54055b8ed492e1d826d
Reviewed-on: https://skia-review.googlesource.com/3303
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
gm/hardstop_gradients.cpp
src/effects/gradients/SkGradientShader.cpp
src/effects/gradients/SkGradientShaderPriv.h

index 846465e..2ab2ed9 100644 (file)
  * order to highlight the differences between tile modes, the gradient
  * starts and ends at 30 pixel inset from either side of the rectangle.
  *
- *                            | Clamp         Repeat          Mirror
- * ___________________________|___________________________________________
- * 2-color                    | rect00        rect01          rect02
- * 3-color even               | rect10        rect11          rect12
- * 3-color texture            | rect20        rect21          rect22
- * 5-color hard stop          | rect30        rect31          rect32
- * 4-color hard stop centered | rect40        rect41          rect42
- * 3-color hard stop 001      | rect50        rect51          rect52
- * 3-color hard stop 011      | rect60        rect61          rect62
+ *                              | Clamp         Repeat          Mirror
+ * _____________________________|___________________________________________
+ * 2-color                      | rect00        rect01          rect02
+ * 3-color even                 | rect10        rect11          rect12
+ * 3-color texture              | rect20        rect21          rect22
+ * 5-color hard stop            | rect30        rect31          rect32
+ * 4-color hard stop centered   | rect40        rect41          rect42
+ * 3-color hard stop 001        | rect50        rect51          rect52
+ * 3-color hard stop 011        | rect60        rect61          rect62
+ * 4-color hard stop off-center | rect70        rect71          rect72
  *
  * The first three rows are cases covered by pre-hard-stop code; simple
  * 2-color gradients, 3-color gradients with the middle color centered,
@@ -32,7 +33,7 @@
  * is a generic hard stop gradient, while the three subsequent rows deal
  * with special cases of hard stop gradients; centered hard stop gradients
  * (with t-values 0, 0.5, 0.5, 1), and two edge cases (with t-values
- * 0, 0, 1 and 0, 1, 1).
+ * 0, 0, 1 and 0, 1, 1). The final row has a single off-center hard stop.
  */
 
 #include "gm.h"
@@ -42,7 +43,7 @@
 const int WIDTH  = 500;
 const int HEIGHT = 500;
 
-const int NUM_ROWS = 7;
+const int NUM_ROWS = 8;
 const int NUM_COLS = 3;
 
 const int CELL_WIDTH  = WIDTH  / NUM_COLS;
@@ -108,6 +109,7 @@ protected:
         SkScalar row5[] = {0.00f, 0.50f, 0.50f, 1.00f};
         SkScalar row6[] = {0.00f, 0.00f, 1.00f};
         SkScalar row7[] = {0.00f, 1.00f, 1.00f};
+        SkScalar row8[] = {0.00f, 0.30f, 0.30f, 1.00f};
 
         SkScalar* positions[NUM_ROWS] = {
             nullptr,
@@ -117,6 +119,7 @@ protected:
             row5,
             row6,
             row7,
+            row8,
         };
 
         int numGradientColors[NUM_ROWS] = {
@@ -127,6 +130,7 @@ protected:
             4,
             3,
             3,
+            4,
         };
 
         SkShader::TileMode tilemodes[NUM_COLS] = {
index bedc6e8..eee2cbf 100644 (file)
@@ -1125,7 +1125,7 @@ static inline bool close_to_one_half(const SkFixed& val) {
 static inline int color_type_to_color_count(GrGradientEffect::ColorType colorType) {
     switch (colorType) {
 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
-        case GrGradientEffect::kHardStopCentered_ColorType:
+        case GrGradientEffect::kSingleHardStop_ColorType:
             return 4;
         case GrGradientEffect::kHardStopLeftEdged_ColorType:
         case GrGradientEffect::kHardStopRightEdged_ColorType:
@@ -1149,11 +1149,10 @@ GrGradientEffect::ColorType GrGradientEffect::determineColorType(
     if (shader.fOrigPos) {
         if (4 == shader.fColorCount) {
             if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
-                SkScalarNearlyEqual(shader.fOrigPos[1], 0.5f) &&
-                SkScalarNearlyEqual(shader.fOrigPos[2], 0.5f) &&
+                SkScalarNearlyEqual(shader.fOrigPos[1], shader.fOrigPos[2]) &&
                 SkScalarNearlyEqual(shader.fOrigPos[3], 1.0f)) {
 
-                return kHardStopCentered_ColorType;
+                return kSingleHardStop_ColorType;
             }
         } else if (3 == shader.fColorCount) {
             if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) &&
@@ -1191,6 +1190,10 @@ void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniform
                                                      kDefault_GrSLPrecision,
                                                      "Colors",
                                                      colorCount);
+        if (ge.fColorType == kSingleHardStop_ColorType) {
+            fHardStopT = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
+                                                    kDefault_GrSLPrecision, "HardStopT");
+        }
     } else {
         fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                              kFloat_GrSLType, kDefault_GrSLPrecision,
@@ -1291,7 +1294,9 @@ void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager&
 
     switch (e.getColorType()) {
 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
-        case GrGradientEffect::kHardStopCentered_ColorType:
+        case GrGradientEffect::kSingleHardStop_ColorType:
+            pdman.set1f(fHardStopT, e.fPositions[1]);
+            // fall through
         case GrGradientEffect::kHardStopLeftEdged_ColorType:
         case GrGradientEffect::kHardStopRightEdged_ColorType:
 #endif
@@ -1347,7 +1352,7 @@ uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor&
         key |= kThreeColorKey;
     }
 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
-    else if (GrGradientEffect::kHardStopCentered_ColorType == e.getColorType()) {
+    else if (GrGradientEffect::kSingleHardStop_ColorType == e.getColorType()) {
         key |= kHardStopCenteredKey;
     } else if (GrGradientEffect::kHardStopLeftEdged_ColorType == e.getColorType()) {
         key |= kHardStopZeroZeroOneKey;
@@ -1379,9 +1384,10 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui
                                                 const TextureSamplers& texSamplers) {
     switch (ge.getColorType()) {
 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
-        case kHardStopCentered_ColorType: {
+        case kSingleHardStop_ColorType: {
             const char* t      = gradientTValue;
             const char* colors = uniformHandler->getUniformCStr(fColorsUni);
+            const char* stopT = uniformHandler->getUniformCStr(fHardStopT);
 
             fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
 
@@ -1399,18 +1405,18 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui
             }
 
             // Calculate color
-            fragBuilder->codeAppendf("float relative_t = fract(2.0 * clamp_t);");
-            if (SkShader::kClamp_TileMode == ge.fTileMode) {
-                fragBuilder->codeAppendf("relative_t += step(1.0, %s);", t);
-            }
-
-            fragBuilder->codeAppendf("vec4 start = %s[0];", colors);
-            fragBuilder->codeAppendf("vec4 end   = %s[1];", colors);
-            fragBuilder->codeAppendf("if (clamp_t >= 0.5) {");
+            fragBuilder->codeAppend ("vec4 start, end;");
+            fragBuilder->codeAppend ("float relative_t;");
+            fragBuilder->codeAppendf("if (clamp_t < %s) {", stopT);
+            fragBuilder->codeAppendf("    start = %s[0];", colors);
+            fragBuilder->codeAppendf("    end   = %s[1];", colors);
+            fragBuilder->codeAppendf("    relative_t = clamp_t / %s;", stopT);
+            fragBuilder->codeAppend ("} else {");
             fragBuilder->codeAppendf("    start = %s[2];", colors);
             fragBuilder->codeAppendf("    end   = %s[3];", colors);
-            fragBuilder->codeAppendf("}");
-            fragBuilder->codeAppendf("vec4 colorTemp = mix(start, end, relative_t);");
+            fragBuilder->codeAppendf("    relative_t = (clamp_t - %s) / (1 - %s);", stopT, stopT);
+            fragBuilder->codeAppend ("}");
+            fragBuilder->codeAppend ("vec4 colorTemp = mix(start, end, relative_t);");
 
             if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
                 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
@@ -1599,7 +1605,7 @@ GrGradientEffect::GrGradientEffect(const CreateArgs& args) {
 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
         case kHardStopLeftEdged_ColorType:
         case kHardStopRightEdged_ColorType:
-        case kHardStopCentered_ColorType:
+        case kSingleHardStop_ColorType:
 #endif
             fRow = -1;
 
@@ -1683,36 +1689,38 @@ GrGradientEffect::~GrGradientEffect() {
 bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
     const GrGradientEffect& ge = processor.cast<GrGradientEffect>();
 
-    if (this->fColorType == ge.getColorType()) {
-        if (kTexture_ColorType == fColorType) {
-            if (fYCoord != ge.getYCoord()) {
-                return false;
-            }
-        } else {
-            if (this->getPremulType() != ge.getPremulType() ||
-                this->fColors.count() != ge.fColors.count() ||
-                this->fColors4f.count() != ge.fColors4f.count()) {
+    if (this->fColorType != ge.getColorType()) {
+        return false;
+    }
+    SkASSERT(this->useAtlas() == ge.useAtlas());
+    if (kTexture_ColorType == fColorType) {
+        if (fYCoord != ge.getYCoord()) {
+            return false;
+        }
+    } else {
+        if (kSingleHardStop_ColorType == fColorType) {
+            if (!SkScalarNearlyEqual(ge.fPositions[1], fPositions[1])) {
                 return false;
             }
+        }
+        if (this->getPremulType() != ge.getPremulType() ||
+            this->fColors.count() != ge.fColors.count() ||
+            this->fColors4f.count() != ge.fColors4f.count()) {
+            return false;
+        }
 
-            for (int i = 0; i < this->fColors.count(); i++) {
-                if (*this->getColors(i) != *ge.getColors(i)) {
-                    return false;
-                }
+        for (int i = 0; i < this->fColors.count(); i++) {
+            if (*this->getColors(i) != *ge.getColors(i)) {
+                return false;
             }
-            for (int i = 0; i < this->fColors4f.count(); i++) {
-                if (*this->getColors4f(i) != *ge.getColors4f(i)) {
-                    return false;
-                }
+        }
+        for (int i = 0; i < this->fColors4f.count(); i++) {
+            if (*this->getColors4f(i) != *ge.getColors4f(i)) {
+                return false;
             }
         }
-
-
-        SkASSERT(this->useAtlas() == ge.useAtlas());
-        return GrColorSpaceXform::Equals(this->fColorSpaceXform.get(), ge.fColorSpaceXform.get());
     }
-
-    return false;
+    return GrColorSpaceXform::Equals(this->fColorSpaceXform.get(), ge.fColorSpaceXform.get());
 }
 
 void GrGradientEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
index d94363d..36ccab0 100644 (file)
@@ -363,7 +363,7 @@ public:
         kTexture_ColorType,
 
 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
-        kHardStopCentered_ColorType,   // 0, 0.5, 0.5, 1
+        kSingleHardStop_ColorType,     // 0, t, t, 1
         kHardStopLeftEdged_ColorType,  // 0, 0, 1
         kHardStopRightEdged_ColorType, // 0, 1, 1
 #endif
@@ -510,6 +510,7 @@ private:
 
     SkScalar fCachedYCoord;
     GrGLSLProgramDataManager::UniformHandle fColorsUni;
+    GrGLSLProgramDataManager::UniformHandle fHardStopT;
     GrGLSLProgramDataManager::UniformHandle fFSYUni;
     GrGLSLProgramDataManager::UniformHandle fColorSpaceXformUni;