Index: src/effects/gradients/SkGradientShader.cpp |
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp |
index 820c5b225d1d4187c1cf6a9e4d85d5fe5fca126b..457b89dcf5858a7ae53476df08cbcd488fec4863 100644 |
--- a/src/effects/gradients/SkGradientShader.cpp |
+++ b/src/effects/gradients/SkGradientShader.cpp |
@@ -228,23 +228,6 @@ void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const { |
desc.flatten(buffer); |
} |
-SkGradientShaderBase::GpuColorType SkGradientShaderBase::getGpuColorType(SkColor colors[3]) const { |
- if (fColorCount <= 3) { |
- memcpy(colors, fOrigColors, fColorCount * sizeof(SkColor)); |
- } |
- |
- if (SkShader::kClamp_TileMode == fTileMode) { |
- if (2 == fColorCount) { |
- return kTwo_GpuColorType; |
- } else if (3 == fColorCount && |
- (SkScalarAbs( |
- SkFixedToScalar(fRecs[1].fPos) - SK_ScalarHalf) < SK_Scalar1 / 1000)) { |
- return kThree_GpuColorType; |
- } |
- } |
- return kTexture_GpuColorType; |
-} |
- |
void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst, |
SkColor* colorSrc, Rec* recSrc, |
int count) { |
@@ -911,113 +894,190 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
#include "glsl/GrGLSLUniformHandler.h" |
#include "SkGr.h" |
-GrGradientEffect::GLSLProcessor::GLSLProcessor() |
- : fCachedYCoord(SK_ScalarMax) { |
+static inline bool close_to_one_half(const SkFixed& val) { |
+ return SkScalarNearlyEqual(SkFixedToScalar(val), SK_ScalarHalf); |
+} |
+ |
+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: |
+ return 4; |
+ case GrGradientEffect::kHardStopLeftEdged_ColorType: |
+ case GrGradientEffect::kHardStopRightEdged_ColorType: |
+ return 3; |
+#endif |
+ case GrGradientEffect::kTwo_ColorType: |
+ return 2; |
+ case GrGradientEffect::kThree_ColorType: |
+ return 3; |
+ case GrGradientEffect::kTexture_ColorType: |
+ return 0; |
+ } |
+ |
+ SkDEBUGFAIL("Unhandled ColorType in color_type_to_color_count()"); |
+ return -1; |
+} |
+ |
+GrGradientEffect::ColorType GrGradientEffect::determineColorType( |
+ const SkGradientShaderBase& shader) { |
+#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS |
+ 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[3], 1.0f)) { |
+ |
+ return kHardStopCentered_ColorType; |
+ } |
+ } else if (3 == shader.fColorCount) { |
+ if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) && |
+ SkScalarNearlyEqual(shader.fOrigPos[1], 0.0f) && |
+ SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) { |
+ |
+ return kHardStopLeftEdged_ColorType; |
+ } else if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) && |
+ SkScalarNearlyEqual(shader.fOrigPos[1], 1.0f) && |
+ SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) { |
+ |
+ return kHardStopRightEdged_ColorType; |
+ } |
+ } |
+ } |
+#endif |
+ |
+ if (SkShader::kClamp_TileMode == shader.getTileMode()) { |
+ if (2 == shader.fColorCount) { |
+ return kTwo_ColorType; |
+ } else if (3 == shader.fColorCount && |
+ close_to_one_half(shader.getRecs()[1].fPos)) { |
+ return kThree_ColorType; |
+ } |
+ } |
+ |
+ return kTexture_ColorType; |
} |
void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniformHandler, |
const GrGradientEffect& ge) { |
- |
- if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()) { // 2 Color case |
- fColorStartUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
- kVec4f_GrSLType, kDefault_GrSLPrecision, |
- "GradientStartColor"); |
- fColorEndUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
- kVec4f_GrSLType, kDefault_GrSLPrecision, |
- "GradientEndColor"); |
- |
- } else if (SkGradientShaderBase::kThree_GpuColorType == ge.getColorType()) { // 3 Color Case |
- fColorStartUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
- kVec4f_GrSLType, kDefault_GrSLPrecision, |
- "GradientStartColor"); |
- fColorMidUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
- kVec4f_GrSLType, kDefault_GrSLPrecision, |
- "GradientMidColor"); |
- fColorEndUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
- kVec4f_GrSLType, kDefault_GrSLPrecision, |
- "GradientEndColor"); |
- |
- } else { // if not a fast case |
+ if (int colorCount = color_type_to_color_count(ge.getColorType())) { |
+ fColorsUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag, |
+ kVec4f_GrSLType, |
+ kDefault_GrSLPrecision, |
+ "Colors", |
+ colorCount); |
+ } else { |
fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
kFloat_GrSLType, kDefault_GrSLPrecision, |
"GradientYCoordFS"); |
} |
} |
-static inline void set_color_uni(const GrGLSLProgramDataManager& pdman, |
- const GrGLSLProgramDataManager::UniformHandle uni, |
- const SkColor* color) { |
- pdman.set4f(uni, |
- SkColorGetR(*color) / 255.f, |
- SkColorGetG(*color) / 255.f, |
- SkColorGetB(*color) / 255.f, |
- SkColorGetA(*color) / 255.f); |
-} |
+static inline void set_after_interp_color_uni_array(const GrGLSLProgramDataManager& pdman, |
+ const GrGLSLProgramDataManager::UniformHandle uni, |
+ const SkTDArray<SkColor>& colors) { |
+ int count = colors.count(); |
+ constexpr int kSmallCount = 10; |
+ |
+ SkAutoSTArray<4*kSmallCount, float> vals(4*count); |
+ |
+ for (int i = 0; i < colors.count(); i++) { |
+ // RGBA |
+ vals[4*i + 0] = SkColorGetR(colors[i]) / 255.f; |
+ vals[4*i + 1] = SkColorGetG(colors[i]) / 255.f; |
+ vals[4*i + 2] = SkColorGetB(colors[i]) / 255.f; |
+ vals[4*i + 3] = SkColorGetA(colors[i]) / 255.f; |
+ } |
-static inline void set_mul_color_uni(const GrGLSLProgramDataManager& pdman, |
- const GrGLSLProgramDataManager::UniformHandle uni, |
- const SkColor* color){ |
- float a = SkColorGetA(*color) / 255.f; |
- float aDiv255 = a / 255.f; |
- pdman.set4f(uni, |
- SkColorGetR(*color) * aDiv255, |
- SkColorGetG(*color) * aDiv255, |
- SkColorGetB(*color) * aDiv255, |
- a); |
+ pdman.set4fv(uni, colors.count(), vals.get()); |
} |
-void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman, |
- const GrProcessor& processor) { |
+static inline void set_before_interp_color_uni_array(const GrGLSLProgramDataManager& pdman, |
+ const GrGLSLProgramDataManager::UniformHandle uni, |
+ const SkTDArray<SkColor>& colors) { |
+ int count = colors.count(); |
+ constexpr int kSmallCount = 10; |
- const GrGradientEffect& e = processor.cast<GrGradientEffect>(); |
+ SkAutoSTArray<4*kSmallCount, float> vals(4*count); |
+ for (int i = 0; i < count; i++) { |
+ float a = SkColorGetA(colors[i]) / 255.f; |
+ float aDiv255 = a / 255.f; |
- if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()){ |
+ // RGBA |
+ vals[4*i + 0] = SkColorGetR(colors[i]) * aDiv255; |
+ vals[4*i + 1] = SkColorGetG(colors[i]) * aDiv255; |
+ vals[4*i + 2] = SkColorGetB(colors[i]) * aDiv255; |
+ vals[4*i + 3] = a; |
+ } |
- if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { |
- set_mul_color_uni(pdman, fColorStartUni, e.getColors(0)); |
- set_mul_color_uni(pdman, fColorEndUni, e.getColors(1)); |
- } else { |
- set_color_uni(pdman, fColorStartUni, e.getColors(0)); |
- set_color_uni(pdman, fColorEndUni, e.getColors(1)); |
- } |
+ pdman.set4fv(uni, count, vals.get()); |
+} |
- } else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()){ |
+void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman, |
+ const GrProcessor& processor) { |
+ const GrGradientEffect& e = processor.cast<GrGradientEffect>(); |
- if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { |
- set_mul_color_uni(pdman, fColorStartUni, e.getColors(0)); |
- set_mul_color_uni(pdman, fColorMidUni, e.getColors(1)); |
- set_mul_color_uni(pdman, fColorEndUni, e.getColors(2)); |
- } else { |
- set_color_uni(pdman, fColorStartUni, e.getColors(0)); |
- set_color_uni(pdman, fColorMidUni, e.getColors(1)); |
- set_color_uni(pdman, fColorEndUni, e.getColors(2)); |
+ switch (e.getColorType()) { |
+#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS |
+ case GrGradientEffect::kHardStopCentered_ColorType: |
+ case GrGradientEffect::kHardStopLeftEdged_ColorType: |
+ case GrGradientEffect::kHardStopRightEdged_ColorType: |
+#endif |
+ case GrGradientEffect::kTwo_ColorType: |
+ case GrGradientEffect::kThree_ColorType: { |
+ if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { |
+ set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors); |
+ } else { |
+ set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors); |
+ } |
+ |
+ break; |
} |
- } else { |
- SkScalar yCoord = e.getYCoord(); |
- if (yCoord != fCachedYCoord) { |
- pdman.set1f(fFSYUni, yCoord); |
- fCachedYCoord = yCoord; |
+ case GrGradientEffect::kTexture_ColorType: { |
+ SkScalar yCoord = e.getYCoord(); |
+ if (yCoord != fCachedYCoord) { |
+ pdman.set1f(fFSYUni, yCoord); |
+ fCachedYCoord = yCoord; |
+ } |
+ break; |
} |
} |
} |
- |
uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor& processor) { |
const GrGradientEffect& e = processor.cast<GrGradientEffect>(); |
uint32_t key = 0; |
- if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()) { |
+ if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { |
+ key |= kPremulBeforeInterpKey; |
+ } |
+ |
+ if (GrGradientEffect::kTwo_ColorType == e.getColorType()) { |
key |= kTwoColorKey; |
- } else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()) { |
+ } else if (GrGradientEffect::kThree_ColorType == e.getColorType()) { |
key |= kThreeColorKey; |
} |
- |
- if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { |
- key |= kPremulBeforeInterpKey; |
+#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS |
+ else if (GrGradientEffect::kHardStopCentered_ColorType == e.getColorType()) { |
+ key |= kHardStopCenteredKey; |
+ } else if (GrGradientEffect::kHardStopLeftEdged_ColorType == e.getColorType()) { |
+ key |= kHardStopZeroZeroOneKey; |
+ } else if (GrGradientEffect::kHardStopRightEdged_ColorType == e.getColorType()) { |
+ key |= kHardStopZeroOneOneKey; |
+ } |
+ |
+ if (SkShader::TileMode::kClamp_TileMode == e.fTileMode) { |
+ key |= kClampTileMode; |
+ } else if (SkShader::TileMode::kRepeat_TileMode == e.fTileMode) { |
+ key |= kRepeatTileMode; |
+ } else { |
+ key |= kMirrorTileMode; |
} |
+#endif |
return key; |
} |
@@ -1030,56 +1090,183 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui |
const char* outputColor, |
const char* inputColor, |
const SamplerHandle* texSamplers) { |
- if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()){ |
- fragBuilder->codeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n", |
- uniformHandler->getUniformVariable(fColorStartUni).c_str(), |
- uniformHandler->getUniformVariable(fColorEndUni).c_str(), |
- gradientTValue); |
- // Note that we could skip this step if both colors are known to be opaque. Two |
- // considerations: |
- // The gradient SkShader reporting opaque is more restrictive than necessary in the two pt |
- // case. Make sure the key reflects this optimization (and note that it can use the same |
- // shader as thekBeforeIterp case). This same optimization applies to the 3 color case |
- // below. |
- if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { |
- fragBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n"); |
+ switch (ge.getColorType()) { |
+#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS |
+ case kHardStopCentered_ColorType: { |
+ const char* t = gradientTValue; |
+ const char* colors = uniformHandler->getUniformCStr(fColorsUni); |
+ |
+ fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t); |
+ |
+ // Account for tile mode |
+ if (SkShader::kRepeat_TileMode == ge.fTileMode) { |
+ fragBuilder->codeAppendf("clamp_t = fract(%s);", t); |
+ } else if (SkShader::kMirror_TileMode == ge.fTileMode) { |
+ fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t); |
+ fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t); |
+ fragBuilder->codeAppendf(" clamp_t = fract(%s);", t); |
+ fragBuilder->codeAppendf(" } else {"); |
+ fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t); |
+ fragBuilder->codeAppendf(" }"); |
+ fragBuilder->codeAppendf("}"); |
+ } |
+ |
+ // 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 colorTemp = mix(%s[0], %s[1], relative_t);", colors, |
+ colors); |
+ fragBuilder->codeAppendf("if (clamp_t >= 0.5) {"); |
+ fragBuilder->codeAppendf(" colorTemp = mix(%s[2], %s[3], relative_t);", colors, |
+ colors); |
+ fragBuilder->codeAppendf("}"); |
+ |
+ if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { |
+ fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); |
+ } |
+ fragBuilder->codeAppendf("%s = %s;", outputColor, |
+ (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); |
+ |
+ break; |
} |
- fragBuilder->codeAppendf("\t%s = %s;\n", outputColor, |
- (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); |
- } else if (SkGradientShaderBase::kThree_GpuColorType == ge.getColorType()) { |
- fragBuilder->codeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n", |
- gradientTValue); |
- fragBuilder->codeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s;\n", |
- uniformHandler->getUniformVariable(fColorStartUni).c_str()); |
- if (!glslCaps->canUseMinAndAbsTogether()) { |
- // The Tegra3 compiler will sometimes never return if we have |
- // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression. |
- fragBuilder->codeAppend("\tfloat minAbs = abs(oneMinus2t);\n"); |
- fragBuilder->codeAppend("\tminAbs = minAbs > 1.0 ? 1.0 : minAbs;\n"); |
- fragBuilder->codeAppendf("\tcolorTemp += (1.0 - minAbs) * %s;\n", |
- uniformHandler->getUniformVariable(fColorMidUni).c_str()); |
- } else { |
- fragBuilder->codeAppendf("\tcolorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s;\n", |
- uniformHandler->getUniformVariable(fColorMidUni).c_str()); |
+ case kHardStopLeftEdged_ColorType: { |
+ const char* t = gradientTValue; |
+ const char* colors = uniformHandler->getUniformCStr(fColorsUni); |
+ |
+ fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t); |
+ |
+ // Account for tile mode |
+ if (SkShader::kRepeat_TileMode == ge.fTileMode) { |
+ fragBuilder->codeAppendf("clamp_t = fract(%s);", t); |
+ } else if (SkShader::kMirror_TileMode == ge.fTileMode) { |
+ fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t); |
+ fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t); |
+ fragBuilder->codeAppendf(" clamp_t = fract(%s);", t); |
+ fragBuilder->codeAppendf(" } else {"); |
+ fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t); |
+ fragBuilder->codeAppendf(" }"); |
+ fragBuilder->codeAppendf("}"); |
+ } |
+ |
+ fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[1], %s[2], clamp_t);", colors, |
+ colors); |
+ if (SkShader::kClamp_TileMode == ge.fTileMode) { |
+ fragBuilder->codeAppendf("if (%s < 0.0) {", t); |
+ fragBuilder->codeAppendf(" colorTemp = %s[0];", colors); |
+ fragBuilder->codeAppendf("}"); |
+ } |
+ |
+ if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { |
+ fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); |
+ } |
+ fragBuilder->codeAppendf("%s = %s;", outputColor, |
+ (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); |
+ |
+ break; |
} |
- fragBuilder->codeAppendf("\tcolorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s;\n", |
- uniformHandler->getUniformVariable(fColorEndUni).c_str()); |
- if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { |
- fragBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n"); |
+ |
+ case kHardStopRightEdged_ColorType: { |
+ const char* t = gradientTValue; |
+ const char* colors = uniformHandler->getUniformCStr(fColorsUni); |
+ |
+ fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t); |
+ |
+ // Account for tile mode |
+ if (SkShader::kRepeat_TileMode == ge.fTileMode) { |
+ fragBuilder->codeAppendf("clamp_t = fract(%s);", t); |
+ } else if (SkShader::kMirror_TileMode == ge.fTileMode) { |
+ fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t); |
+ fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t); |
+ fragBuilder->codeAppendf(" clamp_t = fract(%s);", t); |
+ fragBuilder->codeAppendf(" } else {"); |
+ fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t); |
+ fragBuilder->codeAppendf(" }"); |
+ fragBuilder->codeAppendf("}"); |
+ } |
+ |
+ fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp_t);", colors, |
+ colors); |
+ if (SkShader::kClamp_TileMode == ge.fTileMode) { |
+ fragBuilder->codeAppendf("if (%s > 1.0) {", t); |
+ fragBuilder->codeAppendf(" colorTemp = %s[2];", colors); |
+ fragBuilder->codeAppendf("}"); |
+ } |
+ |
+ if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { |
+ fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); |
+ } |
+ fragBuilder->codeAppendf("%s = %s;", outputColor, |
+ (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); |
+ |
+ break; |
} |
+#endif |
- fragBuilder->codeAppendf("\t%s = %s;\n", outputColor, |
- (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); |
- } else { |
- fragBuilder->codeAppendf("\tvec2 coord = vec2(%s, %s);\n", |
- gradientTValue, |
- uniformHandler->getUniformVariable(fFSYUni).c_str()); |
- fragBuilder->codeAppendf("\t%s = ", outputColor); |
- fragBuilder->appendTextureLookupAndModulate(inputColor, |
- texSamplers[0], |
- "coord"); |
- fragBuilder->codeAppend(";\n"); |
+ case kTwo_ColorType: { |
+ const char* t = gradientTValue; |
+ const char* colors = uniformHandler->getUniformCStr(fColorsUni); |
+ |
+ fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp(%s, 0.0, 1.0));", |
+ colors, colors, t); |
+ |
+ // We could skip this step if both colors are known to be opaque. Two |
+ // considerations: |
+ // The gradient SkShader reporting opaque is more restrictive than necessary in the two |
+ // pt case. Make sure the key reflects this optimization (and note that it can use the |
+ // same shader as thekBeforeIterp case). This same optimization applies to the 3 color |
+ // case below. |
+ if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { |
+ fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); |
+ } |
+ |
+ fragBuilder->codeAppendf("%s = %s;", outputColor, |
+ (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); |
+ |
+ break; |
+ } |
+ |
+ case kThree_ColorType: { |
+ const char* t = gradientTValue; |
+ const char* colors = uniformHandler->getUniformCStr(fColorsUni); |
+ |
+ fragBuilder->codeAppendf("float oneMinus2t = 1.0 - (2.0 * %s);", t); |
+ fragBuilder->codeAppendf("vec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s[0];", |
+ colors); |
+ if (!glslCaps->canUseMinAndAbsTogether()) { |
+ // The Tegra3 compiler will sometimes never return if we have |
+ // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression. |
+ fragBuilder->codeAppendf("float minAbs = abs(oneMinus2t);"); |
+ fragBuilder->codeAppendf("minAbs = minAbs > 1.0 ? 1.0 : minAbs;"); |
+ fragBuilder->codeAppendf("colorTemp += (1.0 - minAbs) * %s[1];", colors); |
+ } else { |
+ fragBuilder->codeAppendf("colorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s[1];", |
+ colors); |
+ } |
+ fragBuilder->codeAppendf("colorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s[2];", colors); |
+ |
+ if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { |
+ fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); |
+ } |
+ |
+ fragBuilder->codeAppendf("%s = %s;", outputColor, |
+ (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); |
+ |
+ break; |
+ } |
+ |
+ case kTexture_ColorType: { |
+ const char* fsyuni = uniformHandler->getUniformCStr(fFSYUni); |
+ |
+ fragBuilder->codeAppendf("vec2 coord = vec2(%s, %s);", gradientTValue, fsyuni); |
+ fragBuilder->codeAppendf("%s = ", outputColor); |
+ fragBuilder->appendTextureLookupAndModulate(inputColor, texSamplers[0], "coord"); |
+ fragBuilder->codeAppend(";"); |
+ |
+ break; |
+ } |
} |
} |
@@ -1092,56 +1279,89 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx, |
fIsOpaque = shader.isOpaque(); |
- fColorType = shader.getGpuColorType(&fColors[0]); |
+ fColorType = this->determineColorType(shader); |
- // The two and three color specializations do not currently support tiling. |
- if (SkGradientShaderBase::kTwo_GpuColorType == fColorType || |
- SkGradientShaderBase::kThree_GpuColorType == fColorType) { |
- fRow = -1; |
+ if (kTexture_ColorType != fColorType) { |
+ if (shader.fOrigColors) { |
+ fColors = SkTDArray<SkColor>(shader.fOrigColors, shader.fColorCount); |
+ } |
- if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) { |
- fPremulType = kBeforeInterp_PremulType; |
- } else { |
- fPremulType = kAfterInterp_PremulType; |
+#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS |
+ if (shader.fOrigPos) { |
+ fPositions = SkTDArray<SkScalar>(shader.fOrigPos, shader.fColorCount); |
} |
- fCoordTransform.reset(kCoordSet, matrix); |
- } else { |
- // doesn't matter how this is set, just be consistent because it is part of the effect key. |
- fPremulType = kBeforeInterp_PremulType; |
- SkBitmap bitmap; |
- shader.getGradientTableBitmap(&bitmap); |
- |
- GrTextureStripAtlas::Desc desc; |
- desc.fWidth = bitmap.width(); |
- desc.fHeight = 32; |
- desc.fRowHeight = bitmap.height(); |
- desc.fContext = ctx; |
- desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *ctx->caps()); |
- fAtlas = GrTextureStripAtlas::GetAtlas(desc); |
- SkASSERT(fAtlas); |
- |
- // We always filter the gradient table. Each table is one row of a texture, always y-clamp. |
- GrTextureParams params; |
- params.setFilterMode(GrTextureParams::kBilerp_FilterMode); |
- params.setTileModeX(tileMode); |
- |
- fRow = fAtlas->lockRow(bitmap); |
- if (-1 != fRow) { |
- fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf * fAtlas->getNormalizedTexelHeight(); |
- fCoordTransform.reset(kCoordSet, matrix, fAtlas->getTexture(), params.filterMode()); |
- fTextureAccess.reset(fAtlas->getTexture(), params); |
- } else { |
- SkAutoTUnref<GrTexture> texture( |
- GrRefCachedBitmapTexture(ctx, bitmap, params, SkSourceGammaTreatment::kRespect)); |
- if (!texture) { |
- return; |
+#endif |
+ } |
+ |
+#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS |
+ fTileMode = tileMode; |
+#endif |
+ |
+ switch (fColorType) { |
+ // The two and three color specializations do not currently support tiling. |
+ case kTwo_ColorType: |
+ case kThree_ColorType: |
+#if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS |
+ case kHardStopLeftEdged_ColorType: |
+ case kHardStopRightEdged_ColorType: |
+ case kHardStopCentered_ColorType: |
+#endif |
+ fRow = -1; |
+ |
+ if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) { |
+ fPremulType = kBeforeInterp_PremulType; |
+ } else { |
+ fPremulType = kAfterInterp_PremulType; |
} |
- fCoordTransform.reset(kCoordSet, matrix, texture, params.filterMode()); |
- fTextureAccess.reset(texture, params); |
- fYCoord = SK_ScalarHalf; |
- } |
- this->addTextureAccess(&fTextureAccess); |
+ |
+ fCoordTransform.reset(kCoordSet, matrix); |
+ |
+ break; |
+ case kTexture_ColorType: |
+ // doesn't matter how this is set, just be consistent because it is part of the |
+ // effect key. |
+ fPremulType = kBeforeInterp_PremulType; |
+ |
+ SkBitmap bitmap; |
+ shader.getGradientTableBitmap(&bitmap); |
+ |
+ GrTextureStripAtlas::Desc desc; |
+ desc.fWidth = bitmap.width(); |
+ desc.fHeight = 32; |
+ desc.fRowHeight = bitmap.height(); |
+ desc.fContext = ctx; |
+ desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *ctx->caps()); |
+ fAtlas = GrTextureStripAtlas::GetAtlas(desc); |
+ SkASSERT(fAtlas); |
+ |
+ // We always filter the gradient table. Each table is one row of a texture, always |
+ // y-clamp. |
+ GrTextureParams params; |
+ params.setFilterMode(GrTextureParams::kBilerp_FilterMode); |
+ params.setTileModeX(tileMode); |
+ |
+ fRow = fAtlas->lockRow(bitmap); |
+ if (-1 != fRow) { |
+ fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight(); |
+ fCoordTransform.reset(kCoordSet, matrix, fAtlas->getTexture(), params.filterMode()); |
+ fTextureAccess.reset(fAtlas->getTexture(), params); |
+ } else { |
+ SkAutoTUnref<GrTexture> texture( |
+ GrRefCachedBitmapTexture(ctx, bitmap, params, |
+ SkSourceGammaTreatment::kRespect)); |
+ if (!texture) { |
+ return; |
+ } |
+ fCoordTransform.reset(kCoordSet, matrix, texture, params.filterMode()); |
+ fTextureAccess.reset(texture, params); |
+ fYCoord = SK_ScalarHalf; |
+ } |
+ |
+ this->addTextureAccess(&fTextureAccess); |
+ |
+ break; |
} |
+ |
this->addCoordTransform(&fCoordTransform); |
} |
@@ -1152,30 +1372,27 @@ GrGradientEffect::~GrGradientEffect() { |
} |
bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const { |
- const GrGradientEffect& s = processor.cast<GrGradientEffect>(); |
- |
- if (this->fColorType == s.getColorType()){ |
+ const GrGradientEffect& ge = processor.cast<GrGradientEffect>(); |
- if (SkGradientShaderBase::kTwo_GpuColorType == fColorType) { |
- if (this->getPremulType() != s.getPremulType() || |
- *this->getColors(0) != *s.getColors(0) || |
- *this->getColors(1) != *s.getColors(1)) { |
- return false; |
- } |
- } else if (SkGradientShaderBase::kThree_GpuColorType == fColorType) { |
- if (this->getPremulType() != s.getPremulType() || |
- *this->getColors(0) != *s.getColors(0) || |
- *this->getColors(1) != *s.getColors(1) || |
- *this->getColors(2) != *s.getColors(2)) { |
+ if (this->fColorType == ge.getColorType()) { |
+ if (kTexture_ColorType == fColorType) { |
+ if (fYCoord != ge.getYCoord()) { |
return false; |
} |
} else { |
- if (fYCoord != s.getYCoord()) { |
+ if (this->getPremulType() != ge.getPremulType() || |
+ this->fColors.count() != ge.fColors.count()) { |
return false; |
} |
+ |
+ for (int i = 0; i < this->fColors.count(); i++) { |
+ if (*this->getColors(i) != *ge.getColors(i)) { |
+ return false; |
+ } |
+ } |
} |
- SkASSERT(this->useAtlas() == s.useAtlas()); |
+ SkASSERT(this->useAtlas() == ge.useAtlas()); |
return true; |
} |