From 97c88c255cff3dbb8343c5d090526fdbedad6dd6 Mon Sep 17 00:00:00 2001 From: Scroggo Date: Wed, 11 May 2011 14:05:25 +0000 Subject: [PATCH] Add color filters to gpu path. git-svn-id: http://skia.googlecode.com/svn/trunk@1297 2bbb7eff-a529-9590-31e7-b0007b416f81 --- gpu/include/GrDrawTarget.h | 12 ++++ gpu/include/GrPaint.h | 14 ++++ gpu/src/GrContext.cpp | 1 + gpu/src/GrDrawTarget.cpp | 5 ++ gpu/src/GrGLProgram.cpp | 116 +++++++++++++++++++++++++++---- gpu/src/GrGLProgram.h | 8 +++ gpu/src/GrGpuGLShaders.cpp | 15 ++++ gyp/skia.gyp | 1 + samplecode/SampleColorFilter.cpp | 6 ++ src/gpu/SkGpuDevice.cpp | 10 +++ 10 files changed, 174 insertions(+), 14 deletions(-) diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h index 6c92071322..e8f1793759 100644 --- a/gpu/include/GrDrawTarget.h +++ b/gpu/include/GrDrawTarget.h @@ -26,6 +26,8 @@ #include "GrTexture.h" #include "GrStencil.h" +#include "SkXfermode.h" + class GrTexture; class GrClipIterator; class GrVertexBuffer; @@ -131,6 +133,9 @@ protected: // all DrState members should default to something // valid by the memset 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(fStencilSettings.isDisabled()); } @@ -144,6 +149,8 @@ protected: GrRenderTarget* fRenderTarget; GrColor fColor; DrawFace fDrawFace; + GrColor fColorFilterColor; + SkXfermode::Mode fColorFilterXfermode; GrStencilSettings fStencilSettings; GrMatrix fViewMatrix; @@ -311,6 +318,11 @@ public: */ 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 * (r,g,b,a) = (alpha, alpha, alpha, alpha). diff --git a/gpu/include/GrPaint.h b/gpu/include/GrPaint.h index 9402209780..3035ca1b67 100644 --- a/gpu/include/GrPaint.h +++ b/gpu/include/GrPaint.h @@ -21,6 +21,8 @@ #include "GrColor.h" #include "GrSamplerState.h" +#include "SkXfermode.h" + /** * The paint describes how pixels are colored when the context draws to * them. @@ -38,6 +40,9 @@ public: GrSamplerState fSampler; + GrColor fColorFilterColor; + SkXfermode::Mode fColorFilterXfermode; + void setTexture(GrTexture* texture) { GrSafeRef(texture); GrSafeUnref(fTexture); @@ -59,6 +64,9 @@ public: fColor = paint.fColor; + fColorFilterColor = paint.fColorFilterColor; + fColorFilterXfermode = paint.fColorFilterXfermode; + fSampler = paint.fSampler; fTexture = paint.fTexture; GrSafeRef(fTexture); @@ -74,6 +82,12 @@ public: resetOptions(); resetColor(); resetTexture(); + resetColorFilter(); + } + + void resetColorFilter() { + fColorFilterXfermode = SkXfermode::kDst_Mode; + fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff); } private: diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp index 2d93e4bbd6..8cb932b2c4 100644 --- a/gpu/src/GrContext.cpp +++ b/gpu/src/GrContext.cpp @@ -1335,6 +1335,7 @@ void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) { target->disableState(GrDrawTarget::kAntialias_StateBit); } target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff); + target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode); } GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint, diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp index 3810043f5e..695a2abdbb 100644 --- a/gpu/src/GrDrawTarget.cpp +++ b/gpu/src/GrDrawTarget.cpp @@ -380,6 +380,11 @@ void GrDrawTarget::setColor(GrColor c) { fCurrDrawState.fColor = c; } +void GrDrawTarget::setColorFilter(GrColor c, SkXfermode::Mode mode) { + fCurrDrawState.fColorFilterColor = c; + fCurrDrawState.fColorFilterXfermode = mode; +} + void GrDrawTarget::setAlpha(uint8_t a) { this->setColor((a << 24) | (a << 16) | (a << 8) | a); } diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp index abed043735..f89de9b5da 100644 --- a/gpu/src/GrGLProgram.cpp +++ b/gpu/src/GrGLProgram.cpp @@ -21,6 +21,8 @@ #include "GrGLEffect.h" #include "GrMemory.h" +#include "SkXfermode.h" + namespace { const char* GrPrecision() { @@ -52,6 +54,7 @@ const char* GrShaderPrecision() { #define POS_ATTR_NAME "aPosition" #define COL_ATTR_NAME "aColor" #define COL_UNI_NAME "uColor" +#define COL_FILTER_UNI_NAME "uColorFilter" static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) { *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 { ShaderCodeSegments segments; @@ -230,23 +284,39 @@ 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 // and count the number of stages in use. const char* stageInCoords[GrDrawTarget::kNumStages]; int numActiveStages = 0; - for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { - if (fProgramDesc.fStages[s].fEnabled) { - if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) { - stageInCoords[s] = POS_ATTR_NAME; - } else { - int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout); - // we better have input tex coordinates if stage is enabled. - GrAssert(tcIdx >= 0); - GrAssert(texCoordAttrs[tcIdx].size()); - stageInCoords[s] = texCoordAttrs[tcIdx].c_str(); + if (!onlyUseColorFilter) { + for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { + if (fProgramDesc.fStages[s].fEnabled) { + if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) { + stageInCoords[s] = POS_ATTR_NAME; + } else { + int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout); + // we better have input tex coordinates if stage is enabled. + GrAssert(tcIdx >= 0); + GrAssert(texCoordAttrs[tcIdx].size()); + stageInCoords[s] = texCoordAttrs[tcIdx].c_str(); + } + ++numActiveStages; } - ++numActiveStages; } } @@ -254,10 +324,10 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const { // of each to the next and generating code for each stage. if (numActiveStages) { int currActiveStage = 0; + GrStringBuilder outColor; for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { if (fProgramDesc.fStages[s].fEnabled) { - GrStringBuilder outColor; - if (currActiveStage < (numActiveStages - 1)) { + if (currActiveStage < (numActiveStages - 1) || useColorFilter) { outColor = "color"; outColor.appendS32(currActiveStage); segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str()); @@ -276,9 +346,21 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const { inColor = outColor; } } + if (useColorFilter) { + addColorFilter(segments.fFSCode, "gl_FragColor", + fProgramDesc.fColorFilterXfermode, outColor.c_str()); + } + } else { // 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.fFSCode.append("}\n"); @@ -495,6 +577,11 @@ void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const GR_GL(GetUniformLocation(progID, COL_UNI_NAME)); 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) { StageUniLocations& locations = programData->fUniLocations.fStages[s]; @@ -550,6 +637,7 @@ void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const } programData->fViewMatrix = GrMatrix::InvalidMatrix(); programData->fColor = GrColor_ILLEGAL; + programData->fColorFilterColor = GrColor_ILLEGAL; } //============================================================================ diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h index 54818ec9d0..3b926a78c4 100644 --- a/gpu/src/GrGLProgram.h +++ b/gpu/src/GrGLProgram.h @@ -21,6 +21,8 @@ #include "GrStringBuilder.h" #include "GrDrawTarget.h" +#include "SkXfermode.h" + class GrBinHashKeyBuilder; class GrGLEffect; struct ShaderCodeSegments; @@ -107,6 +109,9 @@ private: bool fEmitsPointSize; + GrColor fColorFilterColor; + SkXfermode::Mode fColorFilterXfermode; + struct StageDesc { enum OptFlagBits { kNoPerspective_OptFlagBit = 0x1, @@ -159,10 +164,12 @@ public: struct UniLocations { GrGLint fViewMatrixUni; GrGLint fColorUni; + GrGLint fColorFilterUni; StageUniLocations fStages[GrDrawTarget::kNumStages]; void reset() { fViewMatrixUni = kUnusedUniform; fColorUni = kUnusedUniform; + fColorFilterUni = kUnusedUniform; for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { fStages[s].reset(); } @@ -217,6 +224,7 @@ public: // these reflect the current values of uniforms // (GL uniform values travel with program) GrColor fColor; + GrColor fColorFilterColor; GrMatrix fTextureMatrices[GrDrawTarget::kNumStages]; // width and height used for normalized texel size int fTextureWidth[GrDrawTarget::kNumStages]; diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp index 3ce6e55d69..2487563122 100644 --- a/gpu/src/GrGpuGLShaders.cpp +++ b/gpu/src/GrGpuGLShaders.cpp @@ -438,6 +438,19 @@ void GrGpuGLShaders::flushColor() { 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; } } + desc.fColorFilterColor = fCurrDrawState.fColorFilterColor; + desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode; } diff --git a/gyp/skia.gyp b/gyp/skia.gyp index 8f228c9241..c37d567aee 100644 --- a/gyp/skia.gyp +++ b/gyp/skia.gyp @@ -1424,6 +1424,7 @@ '../samplecode/SampleCamera.cpp', '../samplecode/SampleCircle.cpp', '../samplecode/SampleCode.h', + '../samplecode/SampleColorFilter.cpp', '../samplecode/SampleComplexClip.cpp', '../samplecode/SampleCull.cpp', '../samplecode/SampleDecode.cpp', diff --git a/samplecode/SampleColorFilter.cpp b/samplecode/SampleColorFilter.cpp index 8b1c317e1d..77b64a898b 100644 --- a/samplecode/SampleColorFilter.cpp +++ b/samplecode/SampleColorFilter.cpp @@ -91,14 +91,20 @@ protected: } static const SkXfermode::Mode gModes[] = { + SkXfermode::kClear_Mode, SkXfermode::kSrc_Mode, SkXfermode::kDst_Mode, + SkXfermode::kSrcOver_Mode, + SkXfermode::kDstOver_Mode, SkXfermode::kSrcIn_Mode, SkXfermode::kDstIn_Mode, SkXfermode::kSrcOut_Mode, SkXfermode::kDstOut_Mode, SkXfermode::kSrcATop_Mode, SkXfermode::kDstATop_Mode, + SkXfermode::kXor_Mode, + SkXfermode::kPlus_Mode, + SkXfermode::kMultiply_Mode, }; static const SkColor gColors[] = { diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 8818dc0b06..563dde74e2 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -22,6 +22,7 @@ #include "SkGpuDeviceFactory.h" #include "SkGrTexturePixelRef.h" +#include "SkColorFilter.h" #include "SkDrawProcs.h" #include "SkGlyphCache.h" #include "SkUtils.h" @@ -368,6 +369,15 @@ bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint, grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor()); 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; }