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
This commit is contained in:
twiz@google.com 2012-07-18 21:41:50 +00:00
parent 855cd7aa5e
commit 5807116946
9 changed files with 215 additions and 41 deletions

View File

@ -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',

View File

@ -24,7 +24,7 @@
class GrPaint {
public:
enum {
kMaxTextures = 1,
kMaxTextures = 2,
kMaxMasks = 1,
};

View File

@ -182,7 +182,19 @@ bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) {
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;
}

View File

@ -44,7 +44,7 @@ public:
* GrPathRenderer-derived classes.
*/
enum {
kNumStages = 4,
kNumStages = 5,
kMaxTexCoords = kNumStages
};

View File

@ -67,19 +67,22 @@ void gen_globals() {
}
/* 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));

View File

@ -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 @@ namespace {
// 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 @@ inline bool skPaint2GrPaintNoShader(const SkPaint& skPaint,
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 @@ inline bool skPaint2GrPaintNoShader(const SkPaint& skPaint,
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 skPaint2GrPaintNoShader(const SkPaint& skPaint,
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 @@ inline bool skPaint2GrPaintShader(SkGpuDevice* dev,
// 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 @@ void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
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 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
}
GrPaint grPaint;
SkAutoCachedTexture act;
SkAutoCachedTexture textures[GrPaint::kMaxTextures];
if (!skPaint2GrPaintShader(this,
paint,
true,
&act,
textures,
&grPaint)) {
return;
}
@ -732,11 +750,11 @@ void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
}
GrPaint grPaint;
SkAutoCachedTexture act;
SkAutoCachedTexture textures[GrPaint::kMaxTextures];
if (!skPaint2GrPaintShader(this,
paint,
true,
&act,
textures,
&grPaint)) {
return;
}
@ -1011,11 +1029,11 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
bool doFill = true;
GrPaint grPaint;
SkAutoCachedTexture act;
SkAutoCachedTexture textures[GrPaint::kMaxTextures];
if (!skPaint2GrPaintShader(this,
paint,
true,
&act,
textures,
&grPaint)) {
return;
}
@ -1249,7 +1267,8 @@ void SkGpuDevice::drawBitmap(const SkDraw& draw,
}
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 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
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 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,
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 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
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 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
if (!skPaint2GrPaintShader(this,
paint,
NULL == colors,
&act,
textures,
&grPaint)) {
return;
}
@ -1795,12 +1818,11 @@ void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
SkDraw myDraw(draw);
GrPaint grPaint;
SkAutoCachedTexture act;
SkAutoCachedTexture textures[GrPaint::kMaxTextures];
if (!skPaint2GrPaintShader(this,
paint,
true,
&act,
textures,
&grPaint)) {
return;
}
@ -1824,11 +1846,11 @@ void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
SkDraw myDraw(draw);
GrPaint grPaint;
SkAutoCachedTexture act;
SkAutoCachedTexture textures[GrPaint::kMaxTextures];
if (!skPaint2GrPaintShader(this,
paint,
true,
&act,
textures,
&grPaint)) {
return;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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 @@ GrCustomStage* create_random_effect(StageDesc* stageDesc,
kSpecularPoint_EffectType,
kSpecularSpot_EffectType,
kSweepGradient_EffectType,
kColorTable_EffectType,
kEffectCount
};
@ -207,6 +209,9 @@ GrCustomStage* create_random_effect(StageDesc* stageDesc,
SkASSERT(ok);
return stage;
}
case kColorTable_EffectType: {
return SkNEW_ARGS(GrColorTableEffect, (NULL));
}
default:
GrCrash("Unexpected custom effect type");
}