aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/colormatrix.cpp1
-rw-r--r--gyp/gmslides.gypi4
-rw-r--r--include/gpu/GrPaint.h6
-rw-r--r--src/effects/SkColorMatrixFilter.cpp13
-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
12 files changed, 128 insertions, 15 deletions
diff --git a/gm/colormatrix.cpp b/gm/colormatrix.cpp
index 2c6e44c1f2..7d57b3278b 100644
--- a/gm/colormatrix.cpp
+++ b/gm/colormatrix.cpp
@@ -34,6 +34,7 @@ protected:
bm.setConfig(SkBitmap::kARGB_8888_Config, width, height);
bm.allocPixels();
SkCanvas canvas(bm);
+ canvas.clear(0x0);
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
SkPaint paint;
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index 953699de7e..c4a88d3e7e 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -8,9 +8,7 @@
'../gm/bitmapfilters.cpp',
'../gm/bitmapscroll.cpp',
'../gm/blurs.cpp',
- #Disabling this test until premult issues can be worked out.
- #See http://code.google.com/p/skia/issues/detail?id=423
- #'../gm/colormatrix.cpp',
+ '../gm/colormatrix.cpp',
'../gm/complexclip.cpp',
'../gm/complexclip2.cpp',
'../gm/cubicpaths.cpp',
diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h
index ace11cc074..f1d74b2860 100644
--- a/include/gpu/GrPaint.h
+++ b/include/gpu/GrPaint.h
@@ -33,11 +33,13 @@ public:
GrBlendCoeff fDstBlendCoeff;
bool fAntiAlias;
bool fDither;
+ bool fColorMatrixEnabled;
GrColor fColor;
GrColor fColorFilterColor;
SkXfermode::Mode fColorFilterXfermode;
+ float fColorMatrix[20];
void setTexture(int i, GrTexture* texture) {
GrAssert((unsigned)i < kMaxTextures);
@@ -127,6 +129,8 @@ public:
fColorFilterColor = paint.fColorFilterColor;
fColorFilterXfermode = paint.fColorFilterXfermode;
+ memcpy(fColorMatrix, paint.fColorMatrix, sizeof(fColorMatrix));
+ fColorMatrixEnabled = paint.fColorMatrixEnabled;
for (int i = 0; i < kMaxTextures; ++i) {
GrSafeUnref(fTextures[i]);
@@ -165,6 +169,8 @@ public:
void resetColorFilter() {
fColorFilterXfermode = SkXfermode::kDst_Mode;
fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
+ memset(fColorMatrix, 0, sizeof(fColorMatrix));
+ fColorMatrixEnabled = false;
}
bool hasTexture() const {
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index 5ed86981a2..95f4b0bac4 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -335,16 +335,17 @@ SkColorMatrixFilter::SkColorMatrixFilter(SkFlattenableReadBuffer& buffer)
bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) {
int32_t* SK_RESTRICT array = fState.fArray;
+ int unshift = 16 - fState.fShift;
for (int i = 0; i < 20; i++) {
- matrix[i] = SkFixedToScalar(array[i]);
+ matrix[i] = SkFixedToScalar(array[i] << unshift);
}
if (NULL != fProc) {
// Undo the offset applied to the constant column in setup().
- SkScalar offset = SkFixedToScalar(1 << (fState.fShift - 1));
- matrix[4] -= offset;
- matrix[9] -= offset;
- matrix[14] -= offset;
- matrix[19] -= offset;
+ SkFixed offset = 1 << (fState.fShift - 1);
+ matrix[4] = SkFixedToScalar((array[4] - offset) << unshift);
+ matrix[9] = SkFixedToScalar((array[9] - offset) << unshift);
+ matrix[14] = SkFixedToScalar((array[14] - offset) << unshift);
+ matrix[19] = SkFixedToScalar((array[19] - offset) << unshift);
}
return true;
}
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;
}