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;
'../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',
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);
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]);
void resetColorFilter() {
fColorFilterXfermode = SkXfermode::kDst_Mode;
fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
+ memset(fColorMatrix, 0, sizeof(fColorMatrix));
+ fColorMatrixEnabled = false;
}
bool hasTexture() const {
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;
}
} 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");
/// @}
+ ///////////////////////////////////////////////////////////////////////////
+ /// @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
* 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,
GrRenderTarget* fRenderTarget;
GrColor fColor;
GrColor fColorFilterColor;
+ float fColorMatrix[20];
GrStencilSettings fStencilSettings;
GrMatrix fViewMatrix;
// @{ Data for GrTesselatedPathRenderer
#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) {
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 {
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));
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)
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));
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));
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();
}
kVec3f_Type,
kVec4f_Type,
kMat33f_Type,
+ kMat44f_Type,
kSampler2D_Type,
};
return "vec4";
case kMat33f_Type:
return "mat3";
+ case kMat44f_Type:
+ return "mat4";
case kSampler2D_Type:
return "sampler2D";
default:
pdesc.fEdgeAANumEdges = 0;
}
+ pdesc.fColorMatrixEnabled = random_bool(&random);
+
if (this->getCaps().fDualSourceBlendingSupport) {
pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
} else {
}
}
+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) {\
}
}
this->flushEdgeAAData();
+ this->flushColorMatrix();
resetDirtyFlags();
return true;
}
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) {
// flushes the edges for edge AA
void flushEdgeAAData();
+ // flushes the color matrix
+ void flushColorMatrix();
+
static void DeleteProgram(const GrGLInterface* gl,
CachedData* programData);
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;
}