Add color filters to gpu path.

git-svn-id: http://skia.googlecode.com/svn/trunk@1297 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Scroggo 2011-05-11 14:05:25 +00:00
parent 0faac1e857
commit 97c88c255c
10 changed files with 174 additions and 14 deletions

View File

@ -26,6 +26,8 @@
#include "GrTexture.h" #include "GrTexture.h"
#include "GrStencil.h" #include "GrStencil.h"
#include "SkXfermode.h"
class GrTexture; class GrTexture;
class GrClipIterator; class GrClipIterator;
class GrVertexBuffer; class GrVertexBuffer;
@ -131,6 +133,9 @@ protected:
// all DrState members should default to something // all DrState members should default to something
// valid by the memset // valid by the memset
memset(this, 0, sizeof(DrState)); memset(this, 0, sizeof(DrState));
// This is an exception to our memset, since it will
// result in no change.
fColorFilterXfermode = SkXfermode::kDstIn_Mode;
GrAssert((intptr_t)(void*)NULL == 0LL); GrAssert((intptr_t)(void*)NULL == 0LL);
GrAssert(fStencilSettings.isDisabled()); GrAssert(fStencilSettings.isDisabled());
} }
@ -144,6 +149,8 @@ protected:
GrRenderTarget* fRenderTarget; GrRenderTarget* fRenderTarget;
GrColor fColor; GrColor fColor;
DrawFace fDrawFace; DrawFace fDrawFace;
GrColor fColorFilterColor;
SkXfermode::Mode fColorFilterXfermode;
GrStencilSettings fStencilSettings; GrStencilSettings fStencilSettings;
GrMatrix fViewMatrix; GrMatrix fViewMatrix;
@ -311,6 +318,11 @@ public:
*/ */
void setColor(GrColor); void setColor(GrColor);
/**
* Add a color filter that can be represented by a color and a mode.
*/
void setColorFilter(GrColor, SkXfermode::Mode);
/** /**
* Sets the color to be used for the next draw to be * Sets the color to be used for the next draw to be
* (r,g,b,a) = (alpha, alpha, alpha, alpha). * (r,g,b,a) = (alpha, alpha, alpha, alpha).

View File

@ -21,6 +21,8 @@
#include "GrColor.h" #include "GrColor.h"
#include "GrSamplerState.h" #include "GrSamplerState.h"
#include "SkXfermode.h"
/** /**
* The paint describes how pixels are colored when the context draws to * The paint describes how pixels are colored when the context draws to
* them. * them.
@ -38,6 +40,9 @@ public:
GrSamplerState fSampler; GrSamplerState fSampler;
GrColor fColorFilterColor;
SkXfermode::Mode fColorFilterXfermode;
void setTexture(GrTexture* texture) { void setTexture(GrTexture* texture) {
GrSafeRef(texture); GrSafeRef(texture);
GrSafeUnref(fTexture); GrSafeUnref(fTexture);
@ -59,6 +64,9 @@ public:
fColor = paint.fColor; fColor = paint.fColor;
fColorFilterColor = paint.fColorFilterColor;
fColorFilterXfermode = paint.fColorFilterXfermode;
fSampler = paint.fSampler; fSampler = paint.fSampler;
fTexture = paint.fTexture; fTexture = paint.fTexture;
GrSafeRef(fTexture); GrSafeRef(fTexture);
@ -74,6 +82,12 @@ public:
resetOptions(); resetOptions();
resetColor(); resetColor();
resetTexture(); resetTexture();
resetColorFilter();
}
void resetColorFilter() {
fColorFilterXfermode = SkXfermode::kDst_Mode;
fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
} }
private: private:

View File

@ -1335,6 +1335,7 @@ void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
target->disableState(GrDrawTarget::kAntialias_StateBit); target->disableState(GrDrawTarget::kAntialias_StateBit);
} }
target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff); target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
} }
GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint, GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,

View File

@ -380,6 +380,11 @@ void GrDrawTarget::setColor(GrColor c) {
fCurrDrawState.fColor = c; fCurrDrawState.fColor = c;
} }
void GrDrawTarget::setColorFilter(GrColor c, SkXfermode::Mode mode) {
fCurrDrawState.fColorFilterColor = c;
fCurrDrawState.fColorFilterXfermode = mode;
}
void GrDrawTarget::setAlpha(uint8_t a) { void GrDrawTarget::setAlpha(uint8_t a) {
this->setColor((a << 24) | (a << 16) | (a << 8) | a); this->setColor((a << 24) | (a << 16) | (a << 8) | a);
} }

View File

@ -21,6 +21,8 @@
#include "GrGLEffect.h" #include "GrGLEffect.h"
#include "GrMemory.h" #include "GrMemory.h"
#include "SkXfermode.h"
namespace { namespace {
const char* GrPrecision() { const char* GrPrecision() {
@ -52,6 +54,7 @@ const char* GrShaderPrecision() {
#define POS_ATTR_NAME "aPosition" #define POS_ATTR_NAME "aPosition"
#define COL_ATTR_NAME "aColor" #define COL_ATTR_NAME "aColor"
#define COL_UNI_NAME "uColor" #define COL_UNI_NAME "uColor"
#define COL_FILTER_UNI_NAME "uColorFilter"
static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) { static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
*s = "aTexCoord"; *s = "aTexCoord";
@ -174,6 +177,57 @@ void GrGLProgram::doGLPost() const {
} }
} }
/**
* Create a text coefficient to be used in fragment shader code.
*/
static void coefficientString(GrStringBuilder& str, SkXfermode::Coeff coeff,
const char* src, const char* dst) {
switch (coeff) {
case SkXfermode::kZero_Coeff: /** 0 */
str = "0.0";
break;
case SkXfermode::kOne_Coeff: /** 1 */
str = "1.0";
break;
case SkXfermode::kSA_Coeff: /** src alpha */
str.appendf("%s.a", src);
break;
case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
str.appendf("(1.0 - %s.a)", src);
break;
case SkXfermode::kDA_Coeff: /** dst alpha */
str.appendf("%s.a", dst);
break;
case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
str.appendf("(1.0 - %s.a)", dst);
break;
case SkXfermode::kSC_Coeff:
str.append(src);
break;
default:
break;
}
}
/**
* Adds a line to the fragment shader code which modifies the color by
* the specified color filter.
*/
static void addColorFilter(GrStringBuilder& FSCode, const char * outputVar,
SkXfermode::Mode colorFilterXfermode, const char* dstColor) {
SkXfermode::Coeff srcCoeff, dstCoeff;
bool success = SkXfermode::ModeAsCoeff(colorFilterXfermode,
&srcCoeff, &dstCoeff);
// We currently do not handle modes that cannot be represented as
// coefficients.
GrAssert(success);
GrStringBuilder srcCoeffStr, dstCoeffStr;
coefficientString(srcCoeffStr, srcCoeff, COL_FILTER_UNI_NAME, dstColor);
coefficientString(dstCoeffStr, dstCoeff, COL_FILTER_UNI_NAME, dstColor);
FSCode.appendf("\t%s = %s*%s + %s*%s;\n", outputVar, srcCoeffStr.c_str(),
COL_FILTER_UNI_NAME, dstCoeffStr.c_str(), dstColor);
}
bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const { bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
ShaderCodeSegments segments; ShaderCodeSegments segments;
@ -230,11 +284,26 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
} }
} }
bool useColorFilter =
// The rest of transfer mode color filters have not been implemented
fProgramDesc.fColorFilterXfermode <= SkXfermode::kMultiply_Mode
// This mode has no effect.
&& fProgramDesc.fColorFilterXfermode != SkXfermode::kDst_Mode;
bool onlyUseColorFilter = useColorFilter
&& (fProgramDesc.fColorFilterXfermode == SkXfermode::kClear_Mode
|| fProgramDesc.fColorFilterXfermode == SkXfermode::kSrc_Mode);
if (useColorFilter) {
// Set up a uniform for the color
segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
programData->fUniLocations.fColorFilterUni = kUseUniform;
}
// for each enabled stage figure out what the input coordinates are // for each enabled stage figure out what the input coordinates are
// and count the number of stages in use. // and count the number of stages in use.
const char* stageInCoords[GrDrawTarget::kNumStages]; const char* stageInCoords[GrDrawTarget::kNumStages];
int numActiveStages = 0; int numActiveStages = 0;
if (!onlyUseColorFilter) {
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
if (fProgramDesc.fStages[s].fEnabled) { if (fProgramDesc.fStages[s].fEnabled) {
if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) { if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
@ -249,15 +318,16 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
++numActiveStages; ++numActiveStages;
} }
} }
}
// if we have active stages string them together, feeding the output color // if we have active stages string them together, feeding the output color
// of each to the next and generating code for each stage. // of each to the next and generating code for each stage.
if (numActiveStages) { if (numActiveStages) {
int currActiveStage = 0; int currActiveStage = 0;
GrStringBuilder outColor;
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
if (fProgramDesc.fStages[s].fEnabled) { if (fProgramDesc.fStages[s].fEnabled) {
GrStringBuilder outColor; if (currActiveStage < (numActiveStages - 1) || useColorFilter) {
if (currActiveStage < (numActiveStages - 1)) {
outColor = "color"; outColor = "color";
outColor.appendS32(currActiveStage); outColor.appendS32(currActiveStage);
segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str()); segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
@ -276,9 +346,21 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
inColor = outColor; inColor = outColor;
} }
} }
if (useColorFilter) {
addColorFilter(segments.fFSCode, "gl_FragColor",
fProgramDesc.fColorFilterXfermode, outColor.c_str());
}
} else { } else {
// we may not have any incoming color // we may not have any incoming color
segments.fFSCode.appendf("\tgl_FragColor = %s;\n", (inColor.size() ? inColor.c_str() : "vec4(1,1,1,1);\n")); const char * incomingColor = (inColor.size() ? inColor.c_str()
: "vec4(1,1,1,1)");
if (useColorFilter) {
addColorFilter(segments.fFSCode, "gl_FragColor",
fProgramDesc.fColorFilterXfermode, incomingColor);
} else {
segments.fFSCode.appendf("\tgl_FragColor = %s;\n", incomingColor);
}
} }
segments.fVSCode.append("}\n"); segments.fVSCode.append("}\n");
segments.fFSCode.append("}\n"); segments.fFSCode.append("}\n");
@ -495,6 +577,11 @@ void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const
GR_GL(GetUniformLocation(progID, COL_UNI_NAME)); GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni); GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
} }
if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
programData->fUniLocations.fColorFilterUni =
GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
}
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
StageUniLocations& locations = programData->fUniLocations.fStages[s]; StageUniLocations& locations = programData->fUniLocations.fStages[s];
@ -550,6 +637,7 @@ void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const
} }
programData->fViewMatrix = GrMatrix::InvalidMatrix(); programData->fViewMatrix = GrMatrix::InvalidMatrix();
programData->fColor = GrColor_ILLEGAL; programData->fColor = GrColor_ILLEGAL;
programData->fColorFilterColor = GrColor_ILLEGAL;
} }
//============================================================================ //============================================================================

View File

@ -21,6 +21,8 @@
#include "GrStringBuilder.h" #include "GrStringBuilder.h"
#include "GrDrawTarget.h" #include "GrDrawTarget.h"
#include "SkXfermode.h"
class GrBinHashKeyBuilder; class GrBinHashKeyBuilder;
class GrGLEffect; class GrGLEffect;
struct ShaderCodeSegments; struct ShaderCodeSegments;
@ -107,6 +109,9 @@ private:
bool fEmitsPointSize; bool fEmitsPointSize;
GrColor fColorFilterColor;
SkXfermode::Mode fColorFilterXfermode;
struct StageDesc { struct StageDesc {
enum OptFlagBits { enum OptFlagBits {
kNoPerspective_OptFlagBit = 0x1, kNoPerspective_OptFlagBit = 0x1,
@ -159,10 +164,12 @@ public:
struct UniLocations { struct UniLocations {
GrGLint fViewMatrixUni; GrGLint fViewMatrixUni;
GrGLint fColorUni; GrGLint fColorUni;
GrGLint fColorFilterUni;
StageUniLocations fStages[GrDrawTarget::kNumStages]; StageUniLocations fStages[GrDrawTarget::kNumStages];
void reset() { void reset() {
fViewMatrixUni = kUnusedUniform; fViewMatrixUni = kUnusedUniform;
fColorUni = kUnusedUniform; fColorUni = kUnusedUniform;
fColorFilterUni = kUnusedUniform;
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
fStages[s].reset(); fStages[s].reset();
} }
@ -217,6 +224,7 @@ public:
// these reflect the current values of uniforms // these reflect the current values of uniforms
// (GL uniform values travel with program) // (GL uniform values travel with program)
GrColor fColor; GrColor fColor;
GrColor fColorFilterColor;
GrMatrix fTextureMatrices[GrDrawTarget::kNumStages]; GrMatrix fTextureMatrices[GrDrawTarget::kNumStages];
// width and height used for normalized texel size // width and height used for normalized texel size
int fTextureWidth[GrDrawTarget::kNumStages]; int fTextureWidth[GrDrawTarget::kNumStages];

View File

@ -438,6 +438,19 @@ void GrGpuGLShaders::flushColor() {
GrCrash("Unknown color type."); GrCrash("Unknown color type.");
} }
} }
if (fProgramData->fUniLocations.fColorFilterUni
!= GrGLProgram::kUnusedUniform
&& fProgramData->fColorFilterColor
!= fCurrDrawState.fColorFilterColor) {
float c[] = {
GrColorUnpackR(fCurrDrawState.fColorFilterColor) / 255.f,
GrColorUnpackG(fCurrDrawState.fColorFilterColor) / 255.f,
GrColorUnpackB(fCurrDrawState.fColorFilterColor) / 255.f,
GrColorUnpackA(fCurrDrawState.fColorFilterColor) / 255.f
};
GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
}
} }
@ -693,6 +706,8 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
fCurrentProgram.fStageEffects[s] = NULL; fCurrentProgram.fStageEffects[s] = NULL;
} }
} }
desc.fColorFilterColor = fCurrDrawState.fColorFilterColor;
desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
} }

View File

@ -1424,6 +1424,7 @@
'../samplecode/SampleCamera.cpp', '../samplecode/SampleCamera.cpp',
'../samplecode/SampleCircle.cpp', '../samplecode/SampleCircle.cpp',
'../samplecode/SampleCode.h', '../samplecode/SampleCode.h',
'../samplecode/SampleColorFilter.cpp',
'../samplecode/SampleComplexClip.cpp', '../samplecode/SampleComplexClip.cpp',
'../samplecode/SampleCull.cpp', '../samplecode/SampleCull.cpp',
'../samplecode/SampleDecode.cpp', '../samplecode/SampleDecode.cpp',

View File

@ -91,14 +91,20 @@ protected:
} }
static const SkXfermode::Mode gModes[] = { static const SkXfermode::Mode gModes[] = {
SkXfermode::kClear_Mode,
SkXfermode::kSrc_Mode, SkXfermode::kSrc_Mode,
SkXfermode::kDst_Mode, SkXfermode::kDst_Mode,
SkXfermode::kSrcOver_Mode,
SkXfermode::kDstOver_Mode,
SkXfermode::kSrcIn_Mode, SkXfermode::kSrcIn_Mode,
SkXfermode::kDstIn_Mode, SkXfermode::kDstIn_Mode,
SkXfermode::kSrcOut_Mode, SkXfermode::kSrcOut_Mode,
SkXfermode::kDstOut_Mode, SkXfermode::kDstOut_Mode,
SkXfermode::kSrcATop_Mode, SkXfermode::kSrcATop_Mode,
SkXfermode::kDstATop_Mode, SkXfermode::kDstATop_Mode,
SkXfermode::kXor_Mode,
SkXfermode::kPlus_Mode,
SkXfermode::kMultiply_Mode,
}; };
static const SkColor gColors[] = { static const SkColor gColors[] = {

View File

@ -22,6 +22,7 @@
#include "SkGpuDeviceFactory.h" #include "SkGpuDeviceFactory.h"
#include "SkGrTexturePixelRef.h" #include "SkGrTexturePixelRef.h"
#include "SkColorFilter.h"
#include "SkDrawProcs.h" #include "SkDrawProcs.h"
#include "SkGlyphCache.h" #include "SkGlyphCache.h"
#include "SkUtils.h" #include "SkUtils.h"
@ -368,6 +369,15 @@ bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor()); grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
grPaint->setTexture(NULL); grPaint->setTexture(NULL);
} }
SkColorFilter* colorFilter = skPaint.getColorFilter();
SkColor color;
SkXfermode::Mode filterMode;
if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
grPaint->fColorFilterXfermode = filterMode;
} else {
grPaint->resetColorFilter();
}
return true; return true;
} }