This CL implements the Ganesh path for the SkTable_ColorFilter color transformation.
A new texture stage dedicated to color transforms has been added, along with the new custom stage implementing the LUT.
Review URL: https://codereview.appspot.com/6351081
git-svn-id: http://skia.googlecode.com/svn/trunk@4663 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/gpu.gyp b/gyp/gpu.gyp
index 523ba52..cff89d3 100644
--- a/gyp/gpu.gyp
+++ b/gyp/gpu.gyp
@@ -287,6 +287,8 @@
'../src/gpu/gr_unittests.cpp',
'../src/gpu/effects/Gr1DKernelEffect.h',
+ '../src/gpu/effects/GrColorTableEffect.cpp',
+ '../src/gpu/effects/GrColorTableEffect.h',
'../src/gpu/effects/GrConvolutionEffect.cpp',
'../src/gpu/effects/GrConvolutionEffect.h',
'../src/gpu/effects/GrGradientEffects.cpp',
diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h
index 8b1bf2c..fc2fce5 100644
--- a/include/gpu/GrPaint.h
+++ b/include/gpu/GrPaint.h
@@ -24,7 +24,7 @@
class GrPaint {
public:
enum {
- kMaxTextures = 1,
+ kMaxTextures = 2,
kMaxMasks = 1,
};
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index c709dd4..ab42031 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -182,7 +182,19 @@
fBitmap = new SkBitmap;
fBitmap->setConfig(SkBitmap::kA8_Config, 256, 4, 256);
fBitmap->allocPixels();
- memcpy(fBitmap->getAddr8(0, 0), fStorage, 256 * 4);
+ uint8_t* bitmapPixels = fBitmap->getAddr8(0, 0);
+ int offset = 0;
+ static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
+
+ for (int x = 0; x < 4; ++x) {
+ if (!(fFlags & kFlags[x])) {
+ memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
+ } else {
+ memcpy(bitmapPixels, fStorage + offset, 256);
+ offset += 256;
+ }
+ bitmapPixels += 256;
+ }
}
*table = *fBitmap;
}
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index b5c3482..de47182 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -44,7 +44,7 @@
* GrPathRenderer-derived classes.
*/
enum {
- kNumStages = 4,
+ kNumStages = 5,
kMaxTexCoords = kNumStages
};
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index bd922fe..d3d4e45 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -67,19 +67,22 @@
}
/* These values were generated by the above function */
+
const GrVertexLayout gStageTexCoordMasks[] = {
- 0x1111,
- 0x2222,
- 0x4444,
- 0x8888,
+ 0x108421,
+ 0x210842,
+ 0x421084,
+ 0x842108,
+ 0x1084210,
};
GR_STATIC_ASSERT(GrDrawState::kNumStages == GR_ARRAY_COUNT(gStageTexCoordMasks));
const GrVertexLayout gTexCoordMasks[] = {
- 0xf,
- 0xf0,
- 0xf00,
- 0xf000,
+ 0x1f,
+ 0x3e0,
+ 0x7c00,
+ 0xf8000,
+ 0x1f00000,
};
GR_STATIC_ASSERT(GrDrawState::kMaxTexCoords == GR_ARRAY_COUNT(gTexCoordMasks));
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 5e4d8936..ed52848 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -8,6 +8,7 @@
#include "SkGpuDevice.h"
#include "effects/GrGradientEffects.h"
+#include "effects/GrColorTableEffect.h"
#include "effects/GrTextureDomainEffect.h"
#include "GrContext.h"
@@ -41,7 +42,8 @@
// (since drawBitmap, drawSprite, and drawDevice ignore skia's shader)
enum {
kBitmapTextureIdx = 0,
- kShaderTextureIdx = 0
+ kShaderTextureIdx = 0,
+ kColorFilterTextureIdx = 1
};
@@ -448,10 +450,12 @@
// Callers may subsequently modify the GrPaint. Setting constantColor indicates
// that the final paint will draw the same color at every pixel. This allows
// an optimization where the the color filter can be applied to the skPaint's
-// color once while converting to GrPain and then ignored.
-inline bool skPaint2GrPaintNoShader(const SkPaint& skPaint,
+// color once while converting to GrPaint and then ignored.
+inline bool skPaint2GrPaintNoShader(SkGpuDevice* dev,
+ const SkPaint& skPaint,
bool justAlpha,
bool constantColor,
+ SkGpuDevice::SkAutoCachedTexture* act,
GrPaint* grPaint) {
grPaint->fDither = skPaint.isDither();
@@ -487,6 +491,7 @@
SkColor color;
SkXfermode::Mode filterMode;
SkScalar matrix[20];
+ SkBitmap colorTransformTable;
if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
grPaint->fColorMatrixEnabled = false;
if (!constantColor) {
@@ -501,6 +506,17 @@
grPaint->fColorMatrixEnabled = true;
memcpy(grPaint->fColorMatrix, matrix, sizeof(matrix));
grPaint->fColorFilterXfermode = SkXfermode::kDst_Mode;
+ } else if (colorFilter != NULL && colorFilter->asComponentTable(
+ &colorTransformTable)) {
+ grPaint->resetColorFilter();
+
+ GrSamplerState* colorSampler = grPaint->textureSampler(kColorFilterTextureIdx);
+ GrTexture* texture = act->set(dev, colorTransformTable, colorSampler);
+
+ colorSampler->setCustomStage(SkNEW_ARGS(GrColorTableEffect, (texture)))->unref();
+ colorSampler->setFilter(GrSamplerState::kNearest_Filter);
+ colorSampler->setWrapX(GrSamplerState::kClamp_WrapMode);
+ colorSampler->setWrapY(GrSamplerState::kClamp_WrapMode);
} else {
grPaint->resetColorFilter();
}
@@ -514,18 +530,18 @@
inline bool skPaint2GrPaintShader(SkGpuDevice* dev,
const SkPaint& skPaint,
bool constantColor,
- SkGpuDevice::SkAutoCachedTexture* act,
+ SkGpuDevice::SkAutoCachedTexture textures[GrPaint::kMaxTextures],
GrPaint* grPaint) {
-
- SkASSERT(NULL != act);
-
SkShader* shader = skPaint.getShader();
if (NULL == shader) {
- return skPaint2GrPaintNoShader(skPaint,
+ return skPaint2GrPaintNoShader(dev,
+ skPaint,
false,
constantColor,
+ &textures[kColorFilterTextureIdx],
grPaint);
- } else if (!skPaint2GrPaintNoShader(skPaint, true, false, grPaint)) {
+ } else if (!skPaint2GrPaintNoShader(dev, skPaint, true, false,
+ &textures[kColorFilterTextureIdx], grPaint)) {
return false;
}
@@ -549,16 +565,18 @@
// modulate the paint alpha by the shader's solid color alpha
U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
copy.setColor(SkColorSetA(color, newA));
- return skPaint2GrPaintNoShader(copy,
+ return skPaint2GrPaintNoShader(dev,
+ copy,
false,
constantColor,
+ &textures[kColorFilterTextureIdx],
grPaint);
}
return false;
}
GrSamplerState* sampler = grPaint->textureSampler(kShaderTextureIdx);
- GrTexture* texture = act->set(dev, bitmap, sampler);
+ GrTexture* texture = textures[kShaderTextureIdx].set(dev, bitmap, sampler);
if (NULL == texture) {
SkDebugf("Couldn't convert bitmap to texture.\n");
return false;
@@ -634,11 +652,11 @@
CHECK_SHOULD_DRAW(draw);
GrPaint grPaint;
- SkAutoCachedTexture act;
+ SkAutoCachedTexture textures[GrPaint::kMaxTextures];
if (!skPaint2GrPaintShader(this,
paint,
true,
- &act,
+ textures,
&grPaint)) {
return;
}
@@ -670,11 +688,11 @@
}
GrPaint grPaint;
- SkAutoCachedTexture act;
+ SkAutoCachedTexture textures[GrPaint::kMaxTextures];
if (!skPaint2GrPaintShader(this,
paint,
true,
- &act,
+ textures,
&grPaint)) {
return;
}
@@ -732,11 +750,11 @@
}
GrPaint grPaint;
- SkAutoCachedTexture act;
+ SkAutoCachedTexture textures[GrPaint::kMaxTextures];
if (!skPaint2GrPaintShader(this,
paint,
true,
- &act,
+ textures,
&grPaint)) {
return;
}
@@ -1011,11 +1029,11 @@
bool doFill = true;
GrPaint grPaint;
- SkAutoCachedTexture act;
+ SkAutoCachedTexture textures[GrPaint::kMaxTextures];
if (!skPaint2GrPaintShader(this,
paint,
true,
- &act,
+ textures,
&grPaint)) {
return;
}
@@ -1249,7 +1267,8 @@
}
GrPaint grPaint;
- if (!skPaint2GrPaintNoShader(paint, true, false, &grPaint)) {
+ SkAutoCachedTexture colorLutTexture;
+ if (!skPaint2GrPaintNoShader(this, paint, true, false, &colorLutTexture, &grPaint)) {
return;
}
GrSamplerState* sampler = grPaint.textureSampler(kBitmapTextureIdx);
@@ -1531,7 +1550,8 @@
int h = bitmap.height();
GrPaint grPaint;
- if(!skPaint2GrPaintNoShader(paint, true, false, &grPaint)) {
+ SkAutoCachedTexture colorLutTexture;
+ if(!skPaint2GrPaintNoShader(this, paint, true, false, &colorLutTexture, &grPaint)) {
return;
}
@@ -1576,8 +1596,9 @@
CHECK_SHOULD_DRAW(draw);
GrPaint grPaint;
+ SkAutoCachedTexture colorLutTexture;
if (!dev->bindDeviceAsTexture(&grPaint) ||
- !skPaint2GrPaintNoShader(paint, true, false, &grPaint)) {
+ !skPaint2GrPaintNoShader(this, paint, true, false, &colorLutTexture, &grPaint)) {
return;
}
@@ -1682,12 +1703,14 @@
CHECK_SHOULD_DRAW(draw);
GrPaint grPaint;
- SkAutoCachedTexture act;
+ SkAutoCachedTexture textures[GrPaint::kMaxTextures];
// we ignore the shader if texs is null.
if (NULL == texs) {
- if (!skPaint2GrPaintNoShader(paint,
+ if (!skPaint2GrPaintNoShader(this,
+ paint,
false,
NULL == colors,
+ &textures[kColorFilterTextureIdx],
&grPaint)) {
return;
}
@@ -1695,7 +1718,7 @@
if (!skPaint2GrPaintShader(this,
paint,
NULL == colors,
- &act,
+ textures,
&grPaint)) {
return;
}
@@ -1795,12 +1818,11 @@
SkDraw myDraw(draw);
GrPaint grPaint;
- SkAutoCachedTexture act;
-
+ SkAutoCachedTexture textures[GrPaint::kMaxTextures];
if (!skPaint2GrPaintShader(this,
paint,
true,
- &act,
+ textures,
&grPaint)) {
return;
}
@@ -1824,11 +1846,11 @@
SkDraw myDraw(draw);
GrPaint grPaint;
- SkAutoCachedTexture act;
+ SkAutoCachedTexture textures[GrPaint::kMaxTextures];
if (!skPaint2GrPaintShader(this,
paint,
true,
- &act,
+ textures,
&grPaint)) {
return;
}
diff --git a/src/gpu/effects/GrColorTableEffect.cpp b/src/gpu/effects/GrColorTableEffect.cpp
new file mode 100644
index 0000000..5901a80
--- /dev/null
+++ b/src/gpu/effects/GrColorTableEffect.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+ #include "GrColorTableEffect.h"
+ #include "gl/GrGLProgramStage.h"
+ #include "GrProgramStageFactory.h"
+ #include "SkString.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrGLColorTableEffect : public GrGLProgramStage {
+public:
+ GrGLColorTableEffect(const GrProgramStageFactory& factory,
+ const GrCustomStage& stage);
+
+ virtual void setupVariables(GrGLShaderBuilder* state,
+ int stage) SK_OVERRIDE {}
+ virtual void emitVS(GrGLShaderBuilder* state,
+ const char* vertexCoords) SK_OVERRIDE {}
+ virtual void emitFS(GrGLShaderBuilder* state,
+ const char* outputColor,
+ const char* inputColor,
+ const char* samplerName) SK_OVERRIDE;
+
+ virtual void initUniforms(const GrGLShaderBuilder*,
+ const GrGLInterface*,
+ int programID) SK_OVERRIDE {}
+
+ virtual void setData(const GrGLInterface*,
+ const GrCustomStage&,
+ const GrRenderTarget*,
+ int stageNum) SK_OVERRIDE {}
+
+ static inline StageKey GenKey(const GrCustomStage&);
+
+private:
+ typedef GrGLProgramStage INHERITED;
+};
+
+GrGLColorTableEffect::GrGLColorTableEffect(
+ const GrProgramStageFactory& factory, const GrCustomStage& stage)
+ : INHERITED(factory) {
+ }
+
+void GrGLColorTableEffect::emitFS(GrGLShaderBuilder* state,
+ const char* outputColor,
+ const char* inputColor,
+ const char* samplerName) {
+ static const float kColorScaleFactor = 255.0f / 256.0f;
+ static const float kColorOffsetFactor = 1.0f / 512.0f;
+ SkString* code = &state->fFSCode;
+ code->appendf("\t\tvec4 coord = vec4(%s.rgb / %s.a, %s.a);\n",
+ inputColor, inputColor, inputColor);
+ code->appendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
+ kColorScaleFactor,
+ kColorOffsetFactor, kColorOffsetFactor, kColorOffsetFactor, kColorOffsetFactor);
+ code->appendf("\t\t%s.a = texture2D(%s, vec2(coord.a, 0.125)).a;\n",
+ outputColor, samplerName);
+ code->appendf("\t\t%s.r = texture2D(%s, vec2(coord.r, 0.375)).a;\n",
+ outputColor, samplerName);
+ code->appendf("\t\t%s.g = texture2D(%s, vec2(coord.g, 0.625)).a;\n",
+ outputColor, samplerName);
+ code->appendf("\t\t%s.b = texture2D(%s, vec2(coord.b, 0.875)).a;\n",
+ outputColor, samplerName);
+ code->appendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
+}
+
+GrGLProgramStage::StageKey GrGLColorTableEffect::GenKey(
+ const GrCustomStage& s) {
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrColorTableEffect::GrColorTableEffect(GrTexture* texture)
+ : INHERITED(texture) {
+}
+
+GrColorTableEffect::~GrColorTableEffect() {
+}
+
+const GrProgramStageFactory& GrColorTableEffect::getFactory() const {
+ return GrTProgramStageFactory<GrColorTableEffect>::getInstance();
+}
+
+bool GrColorTableEffect::isEqual(const GrCustomStage& sBase) const {
+ return INHERITED::isEqual(sBase);
+}
\ No newline at end of file
diff --git a/src/gpu/effects/GrColorTableEffect.h b/src/gpu/effects/GrColorTableEffect.h
new file mode 100644
index 0000000..f371633
--- /dev/null
+++ b/src/gpu/effects/GrColorTableEffect.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrColorTableEffect_DEFINED
+#define GrColorTableEffect_DEFINED
+
+#include "GrSingleTextureEffect.h"
+#include "GrTexture.h"
+
+class GrGLColorTableEffect;
+
+/**
+ * LUT-based color transformation effect. This class implements the Gr
+ * counterpart to the SkTable_ColorFilter effect. A 256 * 4 (single-channel)
+ * LUT is used to transform the input colors of the image.
+ */
+class GrColorTableEffect : public GrSingleTextureEffect {
+
+public:
+
+ GrColorTableEffect(GrTexture* texture);
+ virtual ~GrColorTableEffect();
+
+ static const char* Name() { return "ColorTable"; }
+ virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
+ virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
+
+ typedef GrGLColorTableEffect GLProgramStage;
+
+private:
+
+ typedef GrSingleTextureEffect INHERITED;
+};
+#endif
\ No newline at end of file
diff --git a/src/gpu/gl/GrGpuGL_unittest.cpp b/src/gpu/gl/GrGpuGL_unittest.cpp
index e0aa5b5..d15e087 100644
--- a/src/gpu/gl/GrGpuGL_unittest.cpp
+++ b/src/gpu/gl/GrGpuGL_unittest.cpp
@@ -1,5 +1,6 @@
#include "GrGpuGL.h"
+#include "effects/GrColorTableEffect.h"
#include "effects/GrConvolutionEffect.h"
#include "effects/GrGradientEffects.h"
#include "effects/GrMorphologyEffect.h"
@@ -47,6 +48,7 @@
kSpecularPoint_EffectType,
kSpecularSpot_EffectType,
kSweepGradient_EffectType,
+ kColorTable_EffectType,
kEffectCount
};
@@ -207,6 +209,9 @@
SkASSERT(ok);
return stage;
}
+ case kColorTable_EffectType: {
+ return SkNEW_ARGS(GrColorTableEffect, (NULL));
+ }
default:
GrCrash("Unexpected custom effect type");
}