diff options
author | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-09-09 15:36:26 +0000 |
---|---|---|
committer | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-09-09 15:36:26 +0000 |
commit | 82d1223aece4703bc9f3a3612cbabaa8c2f2809b (patch) | |
tree | 015b286c683b53ac8c9ee77af93bdc98953384bd | |
parent | a5ed2ae409fae22762014a321e0ea2a334e85830 (diff) |
Two and three color GPU gradients without textures.
R=bsalomon@google.com
Review URL: https://codereview.chromium.org/22854005
git-svn-id: http://skia.googlecode.com/svn/trunk@11158 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | gm/gradients_no_texture.cpp | 130 | ||||
-rw-r--r-- | gyp/gmslides.gypi | 1 | ||||
-rw-r--r-- | include/core/SkShader.h | 1 | ||||
-rw-r--r-- | samplecode/SampleApp.cpp | 2 | ||||
-rw-r--r-- | src/core/SkShader.cpp | 1 | ||||
-rw-r--r-- | src/effects/gradients/SkGradientShader.cpp | 300 | ||||
-rw-r--r-- | src/effects/gradients/SkGradientShaderPriv.h | 86 | ||||
-rw-r--r-- | src/effects/gradients/SkLinearGradient.cpp | 7 | ||||
-rw-r--r-- | src/effects/gradients/SkRadialGradient.cpp | 6 | ||||
-rw-r--r-- | src/effects/gradients/SkSweepGradient.cpp | 7 | ||||
-rw-r--r-- | src/effects/gradients/SkTwoPointConicalGradient.cpp | 13 | ||||
-rw-r--r-- | src/effects/gradients/SkTwoPointRadialGradient.cpp | 9 | ||||
-rw-r--r-- | src/gpu/GrContext.cpp | 2 |
13 files changed, 464 insertions, 101 deletions
diff --git a/gm/gradients_no_texture.cpp b/gm/gradients_no_texture.cpp new file mode 100644 index 0000000000..05481288fc --- /dev/null +++ b/gm/gradients_no_texture.cpp @@ -0,0 +1,130 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "gm.h" +#include "SkGradientShader.h" + +using namespace skiagm; + +struct GradData { + int fCount; + const SkColor* fColors; + const SkScalar* fPos; +}; + +static const SkColor gColors[] = { + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, +}; + +static const GradData gGradData[] = { + { 1, gColors, NULL }, + { 2, gColors, NULL }, + { 3, gColors, NULL }, + { 4, gColors, NULL }, +}; + +static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, SkUnitMapper* mapper) { + return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, + data.fCount, tm, mapper); +} + +static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, SkUnitMapper* mapper) { + SkPoint center; + center.set(SkScalarAve(pts[0].fX, pts[1].fX), + SkScalarAve(pts[0].fY, pts[1].fY)); + return SkGradientShader::CreateRadial(center, center.fX, data.fColors, + data.fPos, data.fCount, tm, mapper); +} + +static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, + SkShader::TileMode, SkUnitMapper* mapper) { + SkPoint center; + center.set(SkScalarAve(pts[0].fX, pts[1].fX), + SkScalarAve(pts[0].fY, pts[1].fY)); + return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, + data.fPos, data.fCount, mapper); +} + +static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, SkUnitMapper* mapper) { + SkPoint center0, center1; + center0.set(SkScalarAve(pts[0].fX, pts[1].fX), + SkScalarAve(pts[0].fY, pts[1].fY)); + center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), + SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); + return SkGradientShader::CreateTwoPointRadial( + center1, (pts[1].fX - pts[0].fX) / 7, + center0, (pts[1].fX - pts[0].fX) / 2, + data.fColors, data.fPos, data.fCount, tm, mapper); +} + +static SkShader* Make2Conical(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, SkUnitMapper* mapper) { + SkPoint center0, center1; + SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 10); + SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3); + center0.set(pts[0].fX + radius0, pts[0].fY + radius0); + center1.set(pts[1].fX - radius1, pts[1].fY - radius1); + return SkGradientShader::CreateTwoPointConical(center1, radius1, + center0, radius0, + data.fColors, data.fPos, + data.fCount, tm, mapper); +} + + +typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, + SkShader::TileMode tm, SkUnitMapper* mapper); +static const GradMaker gGradMakers[] = { + MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical, +}; + +/////////////////////////////////////////////////////////////////////////////// + +class GradientsNoTextureGM : public GM { +public: + GradientsNoTextureGM() { + this->setBGColor(0xFFDDDDDD); + } + +protected: + SkString onShortName() SK_OVERRIDE { return SkString("gradients_no_texture"); } + virtual SkISize onISize() SK_OVERRIDE { return make_isize(640, 615); } + + virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { + static const SkPoint kPts[2] = { { 0, 0 }, + { SkIntToScalar(50), SkIntToScalar(50) } }; + static const SkShader::TileMode kTM = SkShader::kClamp_TileMode; + SkRect kRect = { 0, 0, SkIntToScalar(50), SkIntToScalar(50) }; + SkPaint paint; + paint.setAntiAlias(true); + + canvas->translate(SkIntToScalar(20), SkIntToScalar(20)); + static const uint8_t kAlphas[] = { 0xff, 0x40 }; + for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphas); ++a) { + for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); ++i) { + canvas->save(); + for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); ++j) { + SkShader* shader = gGradMakers[j](kPts, gGradData[i], kTM, NULL); + paint.setShader(shader)->unref(); + paint.setAlpha(kAlphas[a]); + canvas->drawRect(kRect, paint); + canvas->translate(0, SkIntToScalar(kRect.height() + 20)); + } + canvas->restore(); + canvas->translate(SkIntToScalar(kRect.width() + 20), 0); + } + } + } + +private: + typedef GM INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +DEF_GM( return SkNEW(GradientsNoTextureGM)); diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi index e101baf739..2ddb84fcc5 100644 --- a/gyp/gmslides.gypi +++ b/gyp/gmslides.gypi @@ -58,6 +58,7 @@ '../gm/getpostextpath.cpp', '../gm/giantbitmap.cpp', '../gm/gradients.cpp', + '../gm/gradients_no_texture.cpp', '../gm/gradientDirtyLaundry.cpp', '../gm/gradient_matrix.cpp', '../gm/gradtext.cpp', diff --git a/include/core/SkShader.h b/include/core/SkShader.h index 2632830ef0..74f611d3e5 100644 --- a/include/core/SkShader.h +++ b/include/core/SkShader.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp index 5188588706..ee51095de8 100644 --- a/samplecode/SampleApp.cpp +++ b/samplecode/SampleApp.cpp @@ -84,7 +84,7 @@ SkTCPServer gServer; #if SK_ANGLE //#define DEFAULT_TO_ANGLE 1 #else -//#define DEFAULT_TO_GPU 1 +#define DEFAULT_TO_GPU 0 // if 1 default rendering is on GPU #endif #define ANIMATING_EVENTTYPE "nextSample" diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp index d51c2ef530..32f3df4d3c 100644 --- a/src/core/SkShader.cpp +++ b/src/core/SkShader.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp index ca6386acb0..f1b5e58291 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 { diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h index 8e9360429f..451bd2dfee 100644 --- a/src/effects/gradients/SkGradientShaderPriv.h +++ b/src/effects/gradients/SkGradientShaderPriv.h @@ -250,6 +250,27 @@ public: const SkMatrix& getMatrix() const { return fMatrix;} virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; + + enum ColorType { + kTwo_ColorType, + kThree_ColorType, + kTexture_ColorType + }; + + ColorType getColorType() const { return fColorType; } + + enum PremulType { + kBeforeInterp_PremulType, + kAfterInterp_PremulType, + }; + + PremulType getPremulType() const { return fPremulType; } + + const SkColor* getColors(int pos) const { + SkASSERT(fColorType != kTexture_ColorType); + SkASSERT((pos-1) <= fColorType); + return &fColors[pos]; + } protected: @@ -270,13 +291,20 @@ protected: private: + enum { + kMaxAnalyticColors = 3 // if more colors use texture + }; + GrTextureAccess fTextureAccess; SkScalar fYCoord; GrTextureStripAtlas* fAtlas; int fRow; SkMatrix fMatrix; bool fIsOpaque; - + ColorType fColorType; + SkColor fColors[kMaxAnalyticColors]; + PremulType fPremulType; // This only changes behavior for two and three color special cases. + // It is already baked into to the table for texture gradients. typedef GrEffect INHERITED; }; @@ -299,13 +327,42 @@ protected: enum { kMatrixKeyBitCnt = GrGLEffectMatrix::kKeyBits, kMatrixKeyMask = (1 << kMatrixKeyBitCnt) - 1, + + kPremulTypeKeyBitCnt = 1, + kPremulTypeMask = 1 << kMatrixKeyBitCnt, + kPremulBeforeInterpKey = kPremulTypeMask, + + kTwoColorKey = 2 << (kMatrixKeyBitCnt + kPremulTypeKeyBitCnt), + kThreeColorKey = 3 << (kMatrixKeyBitCnt + kPremulTypeKeyBitCnt), + kColorKeyMask = kTwoColorKey | kThreeColorKey, + kColorKeyBitCnt = 2, + + // Subclasses must shift any key bits they produce up by this amount + // and combine with the result of GenBaseGradientKey. + kBaseKeyBitCnt = (kMatrixKeyBitCnt + kPremulTypeKeyBitCnt + kColorKeyBitCnt) }; + static GrGradientEffect::ColorType ColorTypeFromKey(EffectKey key){ + if (kTwoColorKey == (key & kColorKeyMask)) { + return GrGradientEffect::kTwo_ColorType; + } else if (kThreeColorKey == (key & kColorKeyMask)) { + return GrGradientEffect::kThree_ColorType; + } else {return GrGradientEffect::kTexture_ColorType;} + } + + static GrGradientEffect::PremulType PremulTypeFromKey(EffectKey key){ + if (kPremulBeforeInterpKey == (key & kPremulTypeMask)) { + return GrGradientEffect::kBeforeInterp_PremulType; + } else { + return GrGradientEffect::kAfterInterp_PremulType; + } + } + /** - * Subclasses must call this. It will return a value restricted to the lower kMatrixKeyBitCnt + * Subclasses must call this. It will return a value restricted to the lower kBaseKeyBitCnt * bits. */ - static EffectKey GenMatrixKey(const GrDrawEffect&); + static EffectKey GenBaseGradientKey(const GrDrawEffect&); /** * Inserts code to implement the GrGradientEffect's matrix. This should be called before a @@ -323,22 +380,27 @@ protected: // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses // should call this method from their emitCode(). - void emitYCoordUniform(GrGLShaderBuilder* builder); + void emitUniforms(GrGLShaderBuilder* builder, EffectKey key); + - // emit code that gets a fragment's color from an expression for t; for now this always uses the - // texture, but for simpler cases we'll be able to lerp. Subclasses should call this method from - // their emitCode(). - void emitColorLookup(GrGLShaderBuilder* builder, - const char* gradientTValue, - const char* outputColor, - const char* inputColor, - const GrGLShaderBuilder::TextureSampler&); + // emit code that gets a fragment's color from an expression for t; Has branches for 3 separate + // control flows inside -- 2 color gradients, 3 color symmetric gradients (both using + // native GLSL mix), and 4+ color gradients that use the traditional texture lookup. + void emitColor(GrGLShaderBuilder* builder, + const char* gradientTValue, + EffectKey key, + const char* outputColor, + const char* inputColor, + const GrGLShaderBuilder::TextureSamplerArray& samplers); private: static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType; SkScalar fCachedYCoord; GrGLUniformManager::UniformHandle fFSYUni; + GrGLUniformManager::UniformHandle fColorStartUni; + GrGLUniformManager::UniformHandle fColorMidUni; + GrGLUniformManager::UniformHandle fColorEndUni; GrGLEffectMatrix fEffectMatrix; typedef GrGLEffect INHERITED; diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp index 76a44a2695..0b2854e5f9 100644 --- a/src/effects/gradients/SkLinearGradient.cpp +++ b/src/effects/gradients/SkLinearGradient.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2012 Google Inc. * @@ -452,7 +451,7 @@ public: const TextureSamplerArray&) SK_OVERRIDE; static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { - return GenMatrixKey(drawEffect); + return GenBaseGradientKey(drawEffect); } private: @@ -524,13 +523,13 @@ void GrGLLinearGradient::emitCode(GrGLShaderBuilder* builder, const char* outputColor, const char* inputColor, const TextureSamplerArray& samplers) { - this->emitYCoordUniform(builder); + this->emitUniforms(builder, key); SkString coords; this->setupMatrix(builder, key, &coords); SkString t; t.append(coords); t.append(".x"); - this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]); + this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers); } ///////////////////////////////////////////////////////////////////// diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp index 9fcce68fa3..9f3230358e 100644 --- a/src/effects/gradients/SkRadialGradient.cpp +++ b/src/effects/gradients/SkRadialGradient.cpp @@ -484,7 +484,7 @@ public: const TextureSamplerArray&) SK_OVERRIDE; static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { - return GenMatrixKey(drawEffect); + return GenBaseGradientKey(drawEffect); } private: @@ -558,13 +558,13 @@ void GrGLRadialGradient::emitCode(GrGLShaderBuilder* builder, const char* outputColor, const char* inputColor, const TextureSamplerArray& samplers) { - this->emitYCoordUniform(builder); + this->emitUniforms(builder, key); SkString coords; this->setupMatrix(builder, key, &coords); SkString t("length("); t.append(coords); t.append(")"); - this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]); + this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers); } ///////////////////////////////////////////////////////////////////// diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp index 2af20b0bf6..350b20aaee 100644 --- a/src/effects/gradients/SkSweepGradient.cpp +++ b/src/effects/gradients/SkSweepGradient.cpp @@ -405,7 +405,7 @@ public: const TextureSamplerArray&) SK_OVERRIDE; static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { - return GenMatrixKey(drawEffect); + return GenBaseGradientKey(drawEffect); } private: @@ -472,12 +472,13 @@ void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder, const char* outputColor, const char* inputColor, const TextureSamplerArray& samplers) { - this->emitYCoordUniform(builder); + this->emitUniforms(builder, key); SkString coords; this->setupMatrix(builder, key, &coords); SkString t; t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", coords.c_str(), coords.c_str()); - this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]); + this->emitColor(builder, t.c_str(), key, + outputColor, inputColor, samplers); } ///////////////////////////////////////////////////////////////////// diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp index cf9cb98a27..9a23071250 100644 --- a/src/effects/gradients/SkTwoPointConicalGradient.cpp +++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2012 Google Inc. * @@ -495,7 +494,7 @@ void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, GrSLType coordsVaryingType; this->setupMatrix(builder, key, &fsCoords, &vsCoordsVarying, &coordsVaryingType); - this->emitYCoordUniform(builder); + this->emitUniforms(builder, key); // 2 copies of uniform array, 1 for each of vertex & fragment shader, // to work around Xoom bug. Doesn't seem to cause performance decrease // in test apps, but need to keep an eye on it. @@ -617,7 +616,7 @@ void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, p5.c_str(), p3.c_str()); builder->fsCodeAppend("\t\t"); - this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]); + this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers); // otherwise, if r(t) for the larger root was <= 0, try the other root builder->fsCodeAppend("\t\t} else {\n"); @@ -629,7 +628,7 @@ void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, tName.c_str(), p5.c_str(), p3.c_str()); builder->fsCodeAppend("\t\t\t"); - this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]); + this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers); // end if (r(t) > 0) for smaller root builder->fsCodeAppend("\t\t\t}\n"); @@ -647,7 +646,7 @@ void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder, builder->fsCodeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(), p5.c_str(), p3.c_str()); builder->fsCodeAppend("\t"); - this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]); + this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers); builder->fsCodeAppend("\t}\n"); } } @@ -693,10 +692,10 @@ void GrGLConical2Gradient::setData(const GrGLUniformManager& uman, GrGLEffect::EffectKey GrGLConical2Gradient::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { enum { - kIsDegenerate = 1 << kMatrixKeyBitCnt, + kIsDegenerate = 1 << kBaseKeyBitCnt, }; - EffectKey key = GenMatrixKey(drawEffect); + EffectKey key = GenBaseGradientKey(drawEffect); if (drawEffect.castEffect<GrConical2Gradient>().isDegenerate()) { key |= kIsDegenerate; } diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp index e8ec73625b..b4b8402912 100644 --- a/src/effects/gradients/SkTwoPointRadialGradient.cpp +++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp @@ -532,9 +532,10 @@ void GrGLRadial2Gradient::emitCode(GrGLShaderBuilder* builder, const char* inputColor, const TextureSamplerArray& samplers) { - this->emitYCoordUniform(builder); + this->emitUniforms(builder, key); SkString fsCoords; SkString vsCoordsVarying; + GrSLType coordsVaryingType; this->setupMatrix(builder, key, &fsCoords, &vsCoordsVarying, &coordsVaryingType); @@ -632,7 +633,7 @@ void GrGLRadial2Gradient::emitCode(GrGLShaderBuilder* builder, t.printf("-%s / %s", cName.c_str(), bVar.c_str()); } - this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]); + this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers); } } @@ -674,10 +675,10 @@ void GrGLRadial2Gradient::setData(const GrGLUniformManager& uman, GrGLEffect::EffectKey GrGLRadial2Gradient::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { enum { - kIsDegenerate = 1 << kMatrixKeyBitCnt, + kIsDegenerate = 1 << kBaseKeyBitCnt, }; - EffectKey key = GenMatrixKey(drawEffect); + EffectKey key = GenBaseGradientKey(drawEffect); if (drawEffect.castEffect<GrRadial2Gradient>().isDegenerate()) { key |= kIsDegenerate; } diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index d931de5ff1..53b5bf53c2 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -38,7 +38,7 @@ SK_DEFINE_INST_COUNT(GrDrawState) // It can be useful to set this to false to test whether a bug is caused by using the // InOrderDrawBuffer, to compare performance of using/not using InOrderDrawBuffer, or to make // debugging simpler. -SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", true, +SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", false, "Defers rendering in GrContext via GrInOrderDrawBuffer."); #define BUFFERED_DRAW (c_Defer ? kYes_BufferedDraw : kNo_BufferedDraw) |