aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-01-03 20:51:57 +0000
committerGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-01-03 20:51:57 +0000
commit50bdad85db2fe6be4d0bf0c5b6473f712b1bdd32 (patch)
treedd25219722719bd57f8e13336d960e5cd18afeea /src/gpu
parent31bab3934c773c2bd4c1e5e9ba8eb87c1c623b09 (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.cpp6
-rw-r--r--src/gpu/GrDrawState.h22
-rw-r--r--src/gpu/GrGLProgram.cpp37
-rw-r--r--src/gpu/GrGLProgram.h6
-rw-r--r--src/gpu/GrGLShaderVar.h3
-rw-r--r--src/gpu/GrGpuGLShaders.cpp27
-rw-r--r--src/gpu/GrGpuGLShaders.h3
-rw-r--r--src/gpu/SkGpuDevice.cpp15
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;
}