aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-09-09 15:36:26 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-09-09 15:36:26 +0000
commit82d1223aece4703bc9f3a3612cbabaa8c2f2809b (patch)
tree015b286c683b53ac8c9ee77af93bdc98953384bd
parenta5ed2ae409fae22762014a321e0ea2a334e85830 (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.cpp130
-rw-r--r--gyp/gmslides.gypi1
-rw-r--r--include/core/SkShader.h1
-rw-r--r--samplecode/SampleApp.cpp2
-rw-r--r--src/core/SkShader.cpp1
-rw-r--r--src/effects/gradients/SkGradientShader.cpp300
-rw-r--r--src/effects/gradients/SkGradientShaderPriv.h86
-rw-r--r--src/effects/gradients/SkLinearGradient.cpp7
-rw-r--r--src/effects/gradients/SkRadialGradient.cpp6
-rw-r--r--src/effects/gradients/SkSweepGradient.cpp7
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient.cpp13
-rw-r--r--src/effects/gradients/SkTwoPointRadialGradient.cpp9
-rw-r--r--src/gpu/GrContext.cpp2
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, &params);
- 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, &params);
+ 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)