Index: src/effects/gradients/SkGradientShader.cpp |
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp |
index ca6386acb0e6dcfd1c53c5d594b9fa543e7a38bc..f1b5e582918d03f2107432bdf3d8dbafab07fcf3 100644 |
--- a/src/effects/gradients/SkGradientShader.cpp |
+++ b/src/effects/gradients/SkGradientShader.cpp |
@@ -831,28 +831,113 @@ GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory) |
GrGLGradientEffect::~GrGLGradientEffect() { } |
-void GrGLGradientEffect::emitYCoordUniform(GrGLShaderBuilder* builder) { |
- fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
- kFloat_GrSLType, "GradientYCoordFS"); |
+void GrGLGradientEffect::emitUniforms(GrGLShaderBuilder* builder, EffectKey key) { |
+ |
+ if (GrGradientEffect::kTwo_ColorType == ColorTypeFromKey(key)) { // 2 Color case |
+ fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
+ kVec4f_GrSLType, "GradientStartColor"); |
+ fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
+ kVec4f_GrSLType, "GradientEndColor"); |
+ |
+ } else if (GrGradientEffect::kThree_ColorType == ColorTypeFromKey(key)){ // 3 Color Case |
+ fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
+ kVec4f_GrSLType, "GradientStartColor"); |
+ fColorMidUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
+ kVec4f_GrSLType, "GradientMidColor"); |
+ fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
+ kVec4f_GrSLType, "GradientEndColor"); |
+ |
+ } else { // if not a fast case |
+ fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
+ kFloat_GrSLType, "GradientYCoordFS"); |
+ } |
+} |
+ |
+static inline void set_color_uni(const GrGLUniformManager& uman, |
+ const GrGLUniformManager::UniformHandle uni, |
+ const SkColor* color) { |
+ uman.set4f(uni, |
+ SkColorGetR(*color) / 255.f, |
+ SkColorGetG(*color) / 255.f, |
+ SkColorGetB(*color) / 255.f, |
+ SkColorGetA(*color) / 255.f); |
+} |
+ |
+static inline void set_mul_color_uni(const GrGLUniformManager& uman, |
+ const GrGLUniformManager::UniformHandle uni, |
+ const SkColor* color){ |
+ float a = SkColorGetA(*color) / 255.f; |
+ float aDiv255 = a / 255.f; |
+ uman.set4f(uni, |
+ SkColorGetR(*color) * aDiv255, |
+ SkColorGetG(*color) * aDiv255, |
+ SkColorGetB(*color) * aDiv255, |
+ a); |
} |
void GrGLGradientEffect::setData(const GrGLUniformManager& uman, |
const GrDrawEffect& drawEffect) { |
+ |
const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>(); |
- const GrTexture* texture = e.texture(0); |
- fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, texture); |
- SkScalar yCoord = e.getYCoord(); |
- if (yCoord != fCachedYCoord) { |
- uman.set1f(fFSYUni, yCoord); |
- fCachedYCoord = yCoord; |
+ |
+ if (GrGradientEffect::kTwo_ColorType == e.getColorType()){ |
+ |
+ fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, NULL); |
+ if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { |
+ set_mul_color_uni(uman, fColorStartUni, e.getColors(0)); |
+ set_mul_color_uni(uman, fColorEndUni, e.getColors(1)); |
+ } else { |
+ set_color_uni(uman, fColorStartUni, e.getColors(0)); |
+ set_color_uni(uman, fColorEndUni, e.getColors(1)); |
+ } |
+ |
+ } else if (GrGradientEffect::kThree_ColorType == e.getColorType()){ |
+ |
+ fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, NULL); |
+ if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { |
+ set_mul_color_uni(uman, fColorStartUni, e.getColors(0)); |
+ set_mul_color_uni(uman, fColorMidUni, e.getColors(1)); |
+ set_mul_color_uni(uman, fColorEndUni, e.getColors(2)); |
+ } else { |
+ set_color_uni(uman, fColorStartUni, e.getColors(0)); |
+ set_color_uni(uman, fColorMidUni, e.getColors(1)); |
+ set_color_uni(uman, fColorEndUni, e.getColors(2)); |
+ } |
+ } else { |
+ const GrTexture* texture = e.texture(0); |
+ fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, texture); |
+ |
+ SkScalar yCoord = e.getYCoord(); |
+ if (yCoord != fCachedYCoord) { |
+ uman.set1f(fFSYUni, yCoord); |
+ fCachedYCoord = yCoord; |
+ } |
} |
} |
-GrGLEffect::EffectKey GrGLGradientEffect::GenMatrixKey(const GrDrawEffect& drawEffect) { |
+ |
+GrGLEffect::EffectKey GrGLGradientEffect::GenBaseGradientKey(const GrDrawEffect& drawEffect) { |
const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>(); |
- const GrTexture* texture = e.texture(0); |
- return GrGLEffectMatrix::GenKey(e.getMatrix(), drawEffect, kCoordsType, texture); |
+ const GrTexture* texture = NULL; |
+ |
+ if (GrGradientEffect::kTexture_ColorType == e.getColorType()){ |
+ texture = e.texture(0); |
+ } |
+ |
+ EffectKey key = GrGLEffectMatrix::GenKey(e.getMatrix(), drawEffect, kCoordsType, texture); |
+ |
+ if (GrGradientEffect::kTwo_ColorType == e.getColorType()) { |
+ key |= kTwoColorKey; |
+ } else if (GrGradientEffect::kThree_ColorType == e.getColorType()){ |
+ key |= kThreeColorKey; |
+ } |
+ |
+ if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { |
+ key |= kPremulBeforeInterpKey; |
+ } |
+ |
+ return key; |
} |
void GrGLGradientEffect::setupMatrix(GrGLShaderBuilder* builder, |
@@ -867,18 +952,57 @@ void GrGLGradientEffect::setupMatrix(GrGLShaderBuilder* builder, |
vsVaryingType); |
} |
-void GrGLGradientEffect::emitColorLookup(GrGLShaderBuilder* builder, |
- const char* gradientTValue, |
- const char* outputColor, |
- const char* inputColor, |
- const GrGLShaderBuilder::TextureSampler& sampler) { |
+void GrGLGradientEffect::emitColor(GrGLShaderBuilder* builder, |
+ const char* gradientTValue, |
+ EffectKey key, |
+ const char* outputColor, |
+ const char* inputColor, |
+ const GrGLShaderBuilder::TextureSamplerArray& samplers) { |
+ if (GrGradientEffect::kTwo_ColorType == ColorTypeFromKey(key)){ |
+ builder->fsCodeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n", |
+ builder->getUniformVariable(fColorStartUni).c_str(), |
+ builder->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 == PremulTypeFromKey(key)) { |
+ builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n"); |
+ } |
+ |
+ SkString output; |
+ builder->fsCodeAppendf("\t%s = ", outputColor); |
+ GrGLSLModulatef<4>(&output, inputColor, "colorTemp"); |
+ builder->fsCodeAppend(output.c_str()); |
+ builder->fsCodeAppend(";\n"); |
+ } else if (GrGradientEffect::kThree_ColorType == ColorTypeFromKey(key)){ |
+ builder->fsCodeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n", |
+ gradientTValue); |
+ builder->fsCodeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s +(1.0 - min(abs(oneMinus2t), 1.0)) * %s + clamp(-oneMinus2t, 0.0, 1.0) * %s;\n", |
+ builder->getUniformVariable(fColorStartUni).c_str(), |
+ builder->getUniformVariable(fColorMidUni).c_str(), |
+ builder->getUniformVariable(fColorEndUni).c_str()); |
+ if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(key)) { |
+ builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n"); |
+ } |
- builder->fsCodeAppendf("\tvec2 coord = vec2(%s, %s);\n", |
- gradientTValue, |
- builder->getUniformVariable(fFSYUni).c_str()); |
- builder->fsCodeAppendf("\t%s = ", outputColor); |
- builder->fsAppendTextureLookupAndModulate(inputColor, sampler, "coord"); |
- builder->fsCodeAppend(";\n"); |
+ SkString output; |
+ builder->fsCodeAppendf("\t%s = ", outputColor); |
+ GrGLSLModulatef<4>(&output, inputColor, "colorTemp"); |
+ builder->fsCodeAppend(output.c_str()); |
+ builder->fsCodeAppend(";\n"); |
+ } else { |
+ builder->fsCodeAppendf("\tvec2 coord = vec2(%s, %s);\n", |
+ gradientTValue, |
+ builder->getUniformVariable(fFSYUni).c_str()); |
+ builder->fsCodeAppendf("\t%s = ", outputColor); |
+ builder->fsAppendTextureLookupAndModulate(inputColor, |
+ samplers[0], |
+ "coord"); |
+ builder->fsCodeAppend(";\n"); |
+ } |
} |
///////////////////////////////////////////////////////////////////// |
@@ -887,48 +1011,77 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx, |
const SkGradientShaderBase& shader, |
const SkMatrix& matrix, |
SkShader::TileMode tileMode) { |
- // TODO: check for simple cases where we don't need a texture: |
- //GradientInfo info; |
- //shader.asAGradient(&info); |
- //if (info.fColorCount == 2) { ... |
- fMatrix = matrix; |
- |
- SkBitmap bitmap; |
- shader.getGradientTableBitmap(&bitmap); |
+ fMatrix = matrix; |
fIsOpaque = shader.isOpaque(); |
- GrTextureStripAtlas::Desc desc; |
- desc.fWidth = bitmap.width(); |
- desc.fHeight = 32; |
- desc.fRowHeight = bitmap.height(); |
- desc.fContext = ctx; |
- desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config()); |
- fAtlas = GrTextureStripAtlas::GetAtlas(desc); |
- SkASSERT(NULL != fAtlas); |
- |
- // We always filter the gradient table. Each table is one row of a texture, so 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->getVerticalScaleFactor(); |
- fTextureAccess.reset(fAtlas->getTexture(), params); |
+ SkShader::GradientInfo info; |
+ SkScalar pos[3] = {0}; |
+ |
+ info.fColorCount = 3; |
+ info.fColors = &fColors[0]; |
+ info.fColorOffsets = &pos[0]; |
+ shader.asAGradient(&info); |
+ |
+ // The two and three color specializations do not currently support tiling. |
+ bool foundSpecialCase = false; |
+ if (SkShader::kClamp_TileMode == info.fTileMode) { |
+ if (2 == info.fColorCount) { |
+ fRow = -1; // flag for no atlas |
+ fColorType = kTwo_ColorType; |
+ foundSpecialCase = true; |
+ } else if (3 == info.fColorCount && |
+ (SkScalarAbs(pos[1] - SK_ScalarHalf) < SK_Scalar1 / 1000)) { // 3 color symmetric |
+ fRow = -1; // flag for no atlas |
+ fColorType = kThree_ColorType; |
+ foundSpecialCase = true; |
+ } |
+ } |
+ if (foundSpecialCase) { |
+ if (SkGradientShader::kInterpolateColorsInPremul_Flag & info.fGradientFlags) { |
+ fPremulType = kBeforeInterp_PremulType; |
+ } else { |
+ fPremulType = kAfterInterp_PremulType; |
+ } |
} else { |
- GrTexture* texture = GrLockAndRefCachedBitmapTexture(ctx, bitmap, ¶ms); |
- fTextureAccess.reset(texture, params); |
- fYCoord = SK_ScalarHalf; |
- |
- // Unlock immediately, this is not great, but we don't have a way of |
- // knowing when else to unlock it currently, so it may get purged from |
- // the cache, but it'll still be ref'd until it's no longer being used. |
- GrUnlockAndUnrefCachedBitmapTexture(texture); |
+ // 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); |
+ fColorType = kTexture_ColorType; |
+ |
+ GrTextureStripAtlas::Desc desc; |
+ desc.fWidth = bitmap.width(); |
+ desc.fHeight = 32; |
+ desc.fRowHeight = bitmap.height(); |
+ desc.fContext = ctx; |
+ desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config()); |
+ fAtlas = GrTextureStripAtlas::GetAtlas(desc); |
+ SkASSERT(NULL != 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->getVerticalScaleFactor(); |
+ fTextureAccess.reset(fAtlas->getTexture(), params); |
+ } else { |
+ GrTexture* texture = GrLockAndRefCachedBitmapTexture(ctx, bitmap, ¶ms); |
+ fTextureAccess.reset(texture, params); |
+ fYCoord = SK_ScalarHalf; |
+ |
+ // Unlock immediately, this is not great, but we don't have a way of |
+ // knowing when else to unlock it currently, so it may get purged from |
+ // the cache, but it'll still be ref'd until it's no longer being used. |
+ GrUnlockAndUnrefCachedBitmapTexture(texture); |
+ } |
+ this->addTextureAccess(&fTextureAccess); |
} |
- this->addTextureAccess(&fTextureAccess); |
} |
GrGradientEffect::~GrGradientEffect() { |
@@ -939,12 +1092,31 @@ GrGradientEffect::~GrGradientEffect() { |
bool GrGradientEffect::onIsEqual(const GrEffect& effect) const { |
const GrGradientEffect& s = CastEffect<GrGradientEffect>(effect); |
- return fTextureAccess.getTexture() == s.fTextureAccess.getTexture() && |
- fTextureAccess.getParams().getTileModeX() == |
+ |
+ if (this->fColorType == s.getColorType()){ |
+ |
+ if (kTwo_ColorType == fColorType) { |
+ if (*this->getColors(0) != *s.getColors(0) || |
+ *this->getColors(1) != *s.getColors(1)) { |
+ return false; |
+ } |
+ } else if (kThree_ColorType == fColorType) { |
+ if (*this->getColors(0) != *s.getColors(0) || |
+ *this->getColors(1) != *s.getColors(1) || |
+ *this->getColors(2) != *s.getColors(2)) { |
+ return false; |
+ } |
+ } |
+ |
+ return fTextureAccess.getTexture() == s.fTextureAccess.getTexture() && |
+ fTextureAccess.getParams().getTileModeX() == |
s.fTextureAccess.getParams().getTileModeX() && |
- this->useAtlas() == s.useAtlas() && |
- fYCoord == s.getYCoord() && |
- fMatrix.cheapEqualTo(s.getMatrix()); |
+ this->useAtlas() == s.useAtlas() && |
+ fYCoord == s.getYCoord() && |
+ fMatrix.cheapEqualTo(s.getMatrix()); |
+ } |
+ |
+ return false; |
} |
void GrGradientEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { |