diff options
author | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-01-03 20:51:57 +0000 |
---|---|---|
committer | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-01-03 20:51:57 +0000 |
commit | 50bdad85db2fe6be4d0bf0c5b6473f712b1bdd32 (patch) | |
tree | dd25219722719bd57f8e13336d960e5cd18afeea /src/gpu | |
parent | 31bab3934c773c2bd4c1e5e9ba8eb87c1c623b09 (diff) |
Implement the color matrix filter in Ganesh. Also, fix and enable the color
matrix test slide. This was basically implemented in the same places where
the blending-based color filter was being done. The shader simply does a mat4
matrix multiply and a vec4 add.
Review URL: http://codereview.appspot.com/5489107/
git-svn-id: http://skia.googlecode.com/svn/trunk@2948 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrContext.cpp | 6 | ||||
-rw-r--r-- | src/gpu/GrDrawState.h | 22 | ||||
-rw-r--r-- | src/gpu/GrGLProgram.cpp | 37 | ||||
-rw-r--r-- | src/gpu/GrGLProgram.h | 6 | ||||
-rw-r--r-- | src/gpu/GrGLShaderVar.h | 3 | ||||
-rw-r--r-- | src/gpu/GrGpuGLShaders.cpp | 27 | ||||
-rw-r--r-- | src/gpu/GrGpuGLShaders.h | 3 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 15 |
8 files changed, 113 insertions, 6 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index be3b7bebef..a4066299ed 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -1938,8 +1938,14 @@ void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) { } else { drawState->disableState(GrDrawState::kHWAntialias_StateBit); } + if (paint.fColorMatrixEnabled) { + drawState->enableState(GrDrawState::kColorMatrix_StateBit); + } else { + drawState->disableState(GrDrawState::kColorMatrix_StateBit); + } drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff); drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode); + drawState->setColorMatrix(paint.fColorMatrix); if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) { GrPrintf("Partial pixel coverage will be incorrectly blended.\n"); diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h index a1191152f5..dfe0d4b04f 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -455,6 +455,22 @@ struct GrDrawState { /// @} /////////////////////////////////////////////////////////////////////////// + /// @name Color Matrix + //// + + /** + * Sets the color matrix to use for the next draw. + * @param matrix the 5x4 matrix to apply to the incoming color + */ + void setColorMatrix(const float matrix[20]) { + memcpy(fColorMatrix, matrix, sizeof(fColorMatrix)); + } + + const float* getColorMatrix() const { return fColorMatrix; } + + /// @} + + /////////////////////////////////////////////////////////////////////////// // @name Edge AA // There are two ways to perform antialiasing using edge equations. One // is to specify an (linear or quadratic) edge eq per-vertex. This requires @@ -569,6 +585,11 @@ struct GrDrawState { * source polygon is non-convex. */ kEdgeAAConcave_StateBit = 0x10, + /** + * Draws will apply the color matrix, otherwise the color matrix is + * ignored. + */ + kColorMatrix_StateBit = 0x20, // Users of the class may add additional bits to the vector kDummyStateBit, @@ -703,6 +724,7 @@ private: GrRenderTarget* fRenderTarget; GrColor fColor; GrColor fColorFilterColor; + float fColorMatrix[20]; GrStencilSettings fStencilSettings; GrMatrix fViewMatrix; // @{ Data for GrTesselatedPathRenderer diff --git a/src/gpu/GrGLProgram.cpp b/src/gpu/GrGLProgram.cpp index b7e902d83f..ce87b857af 100644 --- a/src/gpu/GrGLProgram.cpp +++ b/src/gpu/GrGLProgram.cpp @@ -94,6 +94,8 @@ typedef GrGLProgram::ProgramDesc::StageDesc StageDesc; #define COL_UNI_NAME "uColor" #define EDGES_UNI_NAME "uEdges" #define COL_FILTER_UNI_NAME "uColorFilter" +#define COL_MATRIX_UNI_NAME "uColorMatrix" +#define COL_MATRIX_VEC_UNI_NAME "uColorMatrixVec" namespace { inline void tex_attr_name(int coordIdx, GrStringBuilder* s) { @@ -365,6 +367,14 @@ static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar, add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode); } +/** + * Adds code to the fragment shader code which modifies the color by + * the specified color matrix. + */ +static void addColorMatrix(GrStringBuilder* fsCode, const char * outputVar, + const char* inColor) { + fsCode->appendf("%s = %s * %s + %s;\n", outputVar, COL_MATRIX_UNI_NAME, inColor, COL_MATRIX_VEC_UNI_NAME); +} namespace { @@ -798,10 +808,10 @@ bool GrGLProgram::genProgram(const GrGLInterface* gl, COL_FILTER_UNI_NAME); programData->fUniLocations.fColorFilterUni = kUseUniform; } - bool wroteFragColorZero = false; if (SkXfermode::kZero_Coeff == uniformCoeff && - SkXfermode::kZero_Coeff == colorCoeff) { + SkXfermode::kZero_Coeff == colorCoeff && + !fProgramDesc.fColorMatrixEnabled) { segments.fFSCode.appendf("\t%s = %s;\n", fsColorOutput, all_zeros_vec(4)); @@ -822,6 +832,19 @@ bool GrGLProgram::genProgram(const GrGLInterface* gl, colorCoeff, color); inColor = "filteredColor"; } + if (fProgramDesc.fColorMatrixEnabled) { + segments.fFSUnis.push_back().set(GrGLShaderVar::kMat44f_Type, + GrGLShaderVar::kUniform_TypeModifier, + COL_MATRIX_UNI_NAME); + segments.fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type, + GrGLShaderVar::kUniform_TypeModifier, + COL_MATRIX_VEC_UNI_NAME); + programData->fUniLocations.fColorMatrixUni = kUseUniform; + programData->fUniLocations.fColorMatrixVecUni = kUseUniform; + segments.fFSCode.appendf("\tvec4 matrixedColor;\n"); + addColorMatrix(&segments.fFSCode, "matrixedColor", inColor.c_str()); + inColor = "matrixedColor"; + } /////////////////////////////////////////////////////////////////////////// // compute the partial coverage (coverage stages and edge aa) @@ -1243,6 +1266,16 @@ void GrGLProgram::getUniformLocationsAndInitCache(const GrGLInterface* gl, GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni); } + if (kUseUniform == programData->fUniLocations.fColorMatrixUni) { + GR_GL_CALL_RET(gl, programData->fUniLocations.fColorMatrixUni, + GetUniformLocation(progID, COL_MATRIX_UNI_NAME)); + } + + if (kUseUniform == programData->fUniLocations.fColorMatrixVecUni) { + GR_GL_CALL_RET(gl, programData->fUniLocations.fColorMatrixVecUni, + GetUniformLocation(progID, COL_MATRIX_VEC_UNI_NAME)); + } + if (kUseUniform == programData->fUniLocations.fEdgesUni) { GR_GL_CALL_RET(gl, programData->fUniLocations.fEdgesUni, GetUniformLocation(progID, EDGES_UNI_NAME)); diff --git a/src/gpu/GrGLProgram.h b/src/gpu/GrGLProgram.h index 450da05ca1..7d19f7ad54 100644 --- a/src/gpu/GrGLProgram.h +++ b/src/gpu/GrGLProgram.h @@ -216,9 +216,11 @@ public: int8_t fFirstCoverageStage; SkBool8 fEmitsPointSize; SkBool8 fEdgeAAConcave; + SkBool8 fColorMatrixEnabled; int8_t fEdgeAANumEdges; uint8_t fColorFilterXfermode; // casts to enum SkXfermode::Mode + int8_t fPadding[3]; } fProgramDesc; GR_STATIC_ASSERT(!(sizeof(ProgramDesc) % 4)); @@ -260,12 +262,16 @@ public: GrGLint fColorUni; GrGLint fEdgesUni; GrGLint fColorFilterUni; + GrGLint fColorMatrixUni; + GrGLint fColorMatrixVecUni; StageUniLocations fStages[GrDrawState::kNumStages]; void reset() { fViewMatrixUni = kUnusedUniform; fColorUni = kUnusedUniform; fEdgesUni = kUnusedUniform; fColorFilterUni = kUnusedUniform; + fColorMatrixUni = kUnusedUniform; + fColorMatrixVecUni = kUnusedUniform; for (int s = 0; s < GrDrawState::kNumStages; ++s) { fStages[s].reset(); } diff --git a/src/gpu/GrGLShaderVar.h b/src/gpu/GrGLShaderVar.h index 5f1ba03efb..1d5d7cad5d 100644 --- a/src/gpu/GrGLShaderVar.h +++ b/src/gpu/GrGLShaderVar.h @@ -27,6 +27,7 @@ public: kVec3f_Type, kVec4f_Type, kMat33f_Type, + kMat44f_Type, kSampler2D_Type, }; @@ -242,6 +243,8 @@ public: return "vec4"; case kMat33f_Type: return "mat3"; + case kMat44f_Type: + return "mat4"; case kSampler2D_Type: return "sampler2D"; default: diff --git a/src/gpu/GrGpuGLShaders.cpp b/src/gpu/GrGpuGLShaders.cpp index 98ac1bfe2e..e9aea2abfa 100644 --- a/src/gpu/GrGpuGLShaders.cpp +++ b/src/gpu/GrGpuGLShaders.cpp @@ -234,6 +234,8 @@ bool GrGpuGLShaders::programUnitTest() { pdesc.fEdgeAANumEdges = 0; } + pdesc.fColorMatrixEnabled = random_bool(&random); + if (this->getCaps().fDualSourceBlendingSupport) { pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt); } else { @@ -612,6 +614,28 @@ void GrGpuGLShaders::flushEdgeAAData() { } } +void GrGpuGLShaders::flushColorMatrix() { + const ProgramDesc& desc = fCurrentProgram.getDesc(); + int matrixUni = fProgramData->fUniLocations.fColorMatrixUni; + int vecUni = fProgramData->fUniLocations.fColorMatrixVecUni; + if (GrGLProgram::kUnusedUniform != matrixUni + && GrGLProgram::kUnusedUniform != vecUni) { + const float* m = this->getDrawState().getColorMatrix(); + GrGLfloat mt[] = { + m[0], m[5], m[10], m[15], + m[1], m[6], m[11], m[16], + m[2], m[7], m[12], m[17], + m[3], m[8], m[13], m[18], + }; + static float scale = 1.0f / 255.0f; + GrGLfloat vec[] = { + m[4] * scale, m[9] * scale, m[14] * scale, m[19] * scale, + }; + GL_CALL(UniformMatrix4fv(matrixUni, 1, false, mt)); + GL_CALL(Uniform4fv(vecUni, 1, vec)); + } +} + static const float ONE_OVER_255 = 1.f / 255.f; #define GR_COLOR_TO_VEC4(color) {\ @@ -731,6 +755,7 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { } } this->flushEdgeAAData(); + this->flushColorMatrix(); resetDirtyFlags(); return true; } @@ -910,6 +935,8 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type, SkXfermode::kDst_Mode : drawState.getColorFilterMode(); + desc.fColorMatrixEnabled = drawState.isStateFlagEnabled(GrDrawState::kColorMatrix_StateBit); + // no reason to do edge aa or look at per-vertex coverage if coverage is // ignored if (skipCoverage) { diff --git a/src/gpu/GrGpuGLShaders.h b/src/gpu/GrGpuGLShaders.h index 36712963e8..4b972b5f47 100644 --- a/src/gpu/GrGpuGLShaders.h +++ b/src/gpu/GrGpuGLShaders.h @@ -75,6 +75,9 @@ private: // flushes the edges for edge AA void flushEdgeAAData(); + // flushes the color matrix + void flushColorMatrix(); + static void DeleteProgram(const GrGLInterface* gl, CachedData* programData); diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index b80d3a6063..6e9b3661f2 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -441,16 +441,23 @@ bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint, SkColorFilter* colorFilter = skPaint.getColorFilter(); SkColor color; SkXfermode::Mode filterMode; + SkScalar matrix[20]; if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) { + grPaint->fColorMatrixEnabled = false; if (!constantColor) { grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color); grPaint->fColorFilterXfermode = filterMode; - return true; + } else { + SkColor filtered = colorFilter->filterColor(skPaint.getColor()); + grPaint->fColor = SkGr::SkColor2GrColor(filtered); } - SkColor filtered = colorFilter->filterColor(skPaint.getColor()); - grPaint->fColor = SkGr::SkColor2GrColor(filtered); + } else if (colorFilter != NULL && colorFilter->asColorMatrix(matrix)) { + grPaint->fColorMatrixEnabled = true; + memcpy(grPaint->fColorMatrix, matrix, sizeof(matrix)); + grPaint->fColorFilterXfermode = SkXfermode::kDst_Mode; + } else { + grPaint->resetColorFilter(); } - grPaint->resetColorFilter(); return true; } |