Chromium Code Reviews| Index: src/effects/gradients/SkGradientShader.cpp |
| diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp |
| index 820c5b225d1d4187c1cf6a9e4d85d5fe5fca126b..2be1b9e8bac57a0882bd0798be277eff6c42241f 100644 |
| --- a/src/effects/gradients/SkGradientShader.cpp |
| +++ b/src/effects/gradients/SkGradientShader.cpp |
| @@ -228,21 +228,48 @@ 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)); |
| +static inline bool close_to_one_half(const SkFixed& val) { |
| + return SkScalarNearlyEqual(SkFixedToScalar(val), SK_ScalarHalf); |
| +} |
| + |
| +GrGradientEffect::ColorType GrGradientEffect::determineColorTypeAndNumHardStops( |
| + 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 == fTileMode) { |
| - if (2 == fColorCount) { |
| - return kTwo_GpuColorType; |
| - } else if (3 == fColorCount && |
| - (SkScalarAbs( |
| - SkFixedToScalar(fRecs[1].fPos) - SK_ScalarHalf) < SK_Scalar1 / 1000)) { |
| - return kThree_GpuColorType; |
| + 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_GpuColorType; |
| + |
| + return kTexture_ColorType; |
| } |
| void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst, |
| @@ -911,113 +938,159 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
| #include "glsl/GrGLSLUniformHandler.h" |
| #include "SkGr.h" |
| -GrGradientEffect::GLSLProcessor::GLSLProcessor() |
| - : fCachedYCoord(SK_ScalarMax) { |
| +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; |
| } |
| void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniformHandler, |
| const GrGradientEffect& ge) { |
| + int colorCount = color_type_to_color_count(ge.getColorType()); |
| - 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 |
| - fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
| - kFloat_GrSLType, kDefault_GrSLPrecision, |
| - "GradientYCoordFS"); |
| + switch (ge.getColorType()) { |
|
bsalomon
2016/08/10 15:17:03
Could this whole thing become:
if (int colorCount
|
| +#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: |
| + fColorsUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag, |
| + kVec4f_GrSLType, |
| + kDefault_GrSLPrecision, |
| + "Colors", |
| + colorCount); |
| + break; |
| + |
| + case GrGradientEffect::kTexture_ColorType: |
| + fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag, |
| + kFloat_GrSLType, kDefault_GrSLPrecision, |
| + "GradientYCoordFS"); |
| + |
| + break; |
| } |
| } |
| -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 +1103,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 +1292,87 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx, |
| fIsOpaque = shader.isOpaque(); |
| - fColorType = shader.getGpuColorType(&fColors[0]); |
| + fColorType = this->determineColorTypeAndNumHardStops(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; |
| + |
| + 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 +1383,27 @@ GrGradientEffect::~GrGradientEffect() { |
| } |
| bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const { |
| - const GrGradientEffect& s = processor.cast<GrGradientEffect>(); |
| + const GrGradientEffect& ge = processor.cast<GrGradientEffect>(); |
| - if (this->fColorType == s.getColorType()){ |
| - |
| - 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; |
| } |