1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "SkColorMatrixFilter.h" 9 #include "SkColorMatrix.h" 10 #include "SkColorPriv.h" 11 #include "SkFlattenableBuffers.h" 12 #include "SkUnPreMultiply.h" 13 #include "SkString.h" 14 15 static int32_t rowmul4(const int32_t array[], unsigned r, unsigned g, 16 unsigned b, unsigned a) { 17 return array[0] * r + array[1] * g + array[2] * b + array[3] * a + array[4]; 18 } 19 20 static int32_t rowmul3(const int32_t array[], unsigned r, unsigned g, 21 unsigned b) { 22 return array[0] * r + array[1] * g + array[2] * b + array[4]; 23 } 24 25 static void General(const SkColorMatrixFilter::State& state, 26 unsigned r, unsigned g, unsigned b, unsigned a, 27 int32_t* SK_RESTRICT result) { 28 const int32_t* SK_RESTRICT array = state.fArray; 29 const int shift = state.fShift; 30 31 result[0] = rowmul4(&array[0], r, g, b, a) >> shift; 32 result[1] = rowmul4(&array[5], r, g, b, a) >> shift; 33 result[2] = rowmul4(&array[10], r, g, b, a) >> shift; 34 result[3] = rowmul4(&array[15], r, g, b, a) >> shift; 35 } 36 37 static void General16(const SkColorMatrixFilter::State& state, 38 unsigned r, unsigned g, unsigned b, unsigned a, 39 int32_t* SK_RESTRICT result) { 40 const int32_t* SK_RESTRICT array = state.fArray; 41 42 result[0] = rowmul4(&array[0], r, g, b, a) >> 16; 43 result[1] = rowmul4(&array[5], r, g, b, a) >> 16; 44 result[2] = rowmul4(&array[10], r, g, b, a) >> 16; 45 result[3] = rowmul4(&array[15], r, g, b, a) >> 16; 46 } 47 48 static void AffineAdd(const SkColorMatrixFilter::State& state, 49 unsigned r, unsigned g, unsigned b, unsigned a, 50 int32_t* SK_RESTRICT result) { 51 const int32_t* SK_RESTRICT array = state.fArray; 52 const int shift = state.fShift; 53 54 result[0] = rowmul3(&array[0], r, g, b) >> shift; 55 result[1] = rowmul3(&array[5], r, g, b) >> shift; 56 result[2] = rowmul3(&array[10], r, g, b) >> shift; 57 result[3] = a; 58 } 59 60 static void AffineAdd16(const SkColorMatrixFilter::State& state, 61 unsigned r, unsigned g, unsigned b, unsigned a, 62 int32_t* SK_RESTRICT result) { 63 const int32_t* SK_RESTRICT array = state.fArray; 64 65 result[0] = rowmul3(&array[0], r, g, b) >> 16; 66 result[1] = rowmul3(&array[5], r, g, b) >> 16; 67 result[2] = rowmul3(&array[10], r, g, b) >> 16; 68 result[3] = a; 69 } 70 71 static void ScaleAdd(const SkColorMatrixFilter::State& state, 72 unsigned r, unsigned g, unsigned b, unsigned a, 73 int32_t* SK_RESTRICT result) { 74 const int32_t* SK_RESTRICT array = state.fArray; 75 const int shift = state.fShift; 76 77 // cast to (int) to keep the expression signed for the shift 78 result[0] = (array[0] * (int)r + array[4]) >> shift; 79 result[1] = (array[6] * (int)g + array[9]) >> shift; 80 result[2] = (array[12] * (int)b + array[14]) >> shift; 81 result[3] = a; 82 } 83 84 static void ScaleAdd16(const SkColorMatrixFilter::State& state, 85 unsigned r, unsigned g, unsigned b, unsigned a, 86 int32_t* SK_RESTRICT result) { 87 const int32_t* SK_RESTRICT array = state.fArray; 88 89 // cast to (int) to keep the expression signed for the shift 90 result[0] = (array[0] * (int)r + array[4]) >> 16; 91 result[1] = (array[6] * (int)g + array[9]) >> 16; 92 result[2] = (array[12] * (int)b + array[14]) >> 16; 93 result[3] = a; 94 } 95 96 static void Add(const SkColorMatrixFilter::State& state, 97 unsigned r, unsigned g, unsigned b, unsigned a, 98 int32_t* SK_RESTRICT result) { 99 const int32_t* SK_RESTRICT array = state.fArray; 100 const int shift = state.fShift; 101 102 result[0] = r + (array[4] >> shift); 103 result[1] = g + (array[9] >> shift); 104 result[2] = b + (array[14] >> shift); 105 result[3] = a; 106 } 107 108 static void Add16(const SkColorMatrixFilter::State& state, 109 unsigned r, unsigned g, unsigned b, unsigned a, 110 int32_t* SK_RESTRICT result) { 111 const int32_t* SK_RESTRICT array = state.fArray; 112 113 result[0] = r + (array[4] >> 16); 114 result[1] = g + (array[9] >> 16); 115 result[2] = b + (array[14] >> 16); 116 result[3] = a; 117 } 118 119 #define kNO_ALPHA_FLAGS (SkColorFilter::kAlphaUnchanged_Flag | \ 120 SkColorFilter::kHasFilter16_Flag) 121 122 // src is [20] but some compilers won't accept __restrict__ on anything 123 // but an raw pointer or reference 124 void SkColorMatrixFilter::initState(const SkScalar* SK_RESTRICT src) { 125 int32_t* array = fState.fArray; 126 SkFixed max = 0; 127 for (int i = 0; i < 20; i++) { 128 SkFixed value = SkScalarToFixed(src[i]); 129 array[i] = value; 130 value = SkAbs32(value); 131 max = SkMax32(max, value); 132 } 133 134 /* All of fArray[] values must fit in 23 bits, to safely allow me to 135 multiply them by 8bit unsigned values, and get a signed answer without 136 overflow. This means clz needs to be 9 or bigger 137 */ 138 int bits = SkCLZ(max); 139 int32_t one = SK_Fixed1; 140 141 fState.fShift = 16; // we are starting out as fixed 16.16 142 if (bits < 9) { 143 bits = 9 - bits; 144 fState.fShift -= bits; 145 for (int i = 0; i < 20; i++) { 146 array[i] >>= bits; 147 } 148 one >>= bits; 149 } 150 151 // check if we have to munge Alpha 152 int32_t changesAlpha = (array[15] | array[16] | array[17] | 153 (array[18] - one) | array[19]); 154 int32_t usesAlpha = (array[3] | array[8] | array[13]); 155 bool shiftIs16 = (16 == fState.fShift); 156 157 if (changesAlpha | usesAlpha) { 158 fProc = shiftIs16 ? General16 : General; 159 fFlags = changesAlpha ? 0 : SkColorFilter::kAlphaUnchanged_Flag; 160 } else { 161 fFlags = kNO_ALPHA_FLAGS; 162 163 int32_t needsScale = (array[0] - one) | // red axis 164 (array[6] - one) | // green axis 165 (array[12] - one); // blue axis 166 167 int32_t needs3x3 = array[1] | array[2] | // red off-axis 168 array[5] | array[7] | // green off-axis 169 array[10] | array[11]; // blue off-axis 170 171 if (needs3x3) { 172 fProc = shiftIs16 ? AffineAdd16 : AffineAdd; 173 } else if (needsScale) { 174 fProc = shiftIs16 ? ScaleAdd16 : ScaleAdd; 175 } else if (array[4] | array[9] | array[14]) { // needs add 176 fProc = shiftIs16 ? Add16 : Add; 177 } else { 178 fProc = NULL; // identity 179 } 180 } 181 182 /* preround our add values so we get a rounded shift. We do this after we 183 analyze the array, so we don't miss the case where the caller has zeros 184 which could make us accidentally take the General or Add case. 185 */ 186 if (NULL != fProc) { 187 int32_t add = 1 << (fState.fShift - 1); 188 array[4] += add; 189 array[9] += add; 190 array[14] += add; 191 array[19] += add; 192 } 193 } 194 195 /////////////////////////////////////////////////////////////////////////////// 196 197 static int32_t pin(int32_t value, int32_t max) { 198 if (value < 0) { 199 value = 0; 200 } 201 if (value > max) { 202 value = max; 203 } 204 return value; 205 } 206 207 SkColorMatrixFilter::SkColorMatrixFilter(const SkColorMatrix& cm) : fMatrix(cm) { 208 this->initState(cm.fMat); 209 } 210 211 SkColorMatrixFilter::SkColorMatrixFilter(const SkScalar array[20]) { 212 memcpy(fMatrix.fMat, array, 20 * sizeof(SkScalar)); 213 this->initState(array); 214 } 215 216 uint32_t SkColorMatrixFilter::getFlags() const { 217 return this->INHERITED::getFlags() | fFlags; 218 } 219 220 void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count, 221 SkPMColor dst[]) const { 222 Proc proc = fProc; 223 const State& state = fState; 224 int32_t result[4]; 225 226 if (NULL == proc) { 227 if (src != dst) { 228 memcpy(dst, src, count * sizeof(SkPMColor)); 229 } 230 return; 231 } 232 233 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); 234 235 for (int i = 0; i < count; i++) { 236 SkPMColor c = src[i]; 237 238 unsigned r = SkGetPackedR32(c); 239 unsigned g = SkGetPackedG32(c); 240 unsigned b = SkGetPackedB32(c); 241 unsigned a = SkGetPackedA32(c); 242 243 // need our components to be un-premultiplied 244 if (255 != a) { 245 SkUnPreMultiply::Scale scale = table[a]; 246 r = SkUnPreMultiply::ApplyScale(scale, r); 247 g = SkUnPreMultiply::ApplyScale(scale, g); 248 b = SkUnPreMultiply::ApplyScale(scale, b); 249 250 SkASSERT(r <= 255); 251 SkASSERT(g <= 255); 252 SkASSERT(b <= 255); 253 } 254 255 proc(state, r, g, b, a, result); 256 257 r = pin(result[0], SK_R32_MASK); 258 g = pin(result[1], SK_G32_MASK); 259 b = pin(result[2], SK_B32_MASK); 260 a = pin(result[3], SK_A32_MASK); 261 // re-prepremultiply if needed 262 dst[i] = SkPremultiplyARGBInline(a, r, g, b); 263 } 264 } 265 266 void SkColorMatrixFilter::filterSpan16(const uint16_t src[], int count, 267 uint16_t dst[]) const { 268 SkASSERT(fFlags & SkColorFilter::kHasFilter16_Flag); 269 270 Proc proc = fProc; 271 const State& state = fState; 272 int32_t result[4]; 273 274 if (NULL == proc) { 275 if (src != dst) { 276 memcpy(dst, src, count * sizeof(uint16_t)); 277 } 278 return; 279 } 280 281 for (int i = 0; i < count; i++) { 282 uint16_t c = src[i]; 283 284 // expand to 8bit components (since our matrix translate is 8bit biased 285 unsigned r = SkPacked16ToR32(c); 286 unsigned g = SkPacked16ToG32(c); 287 unsigned b = SkPacked16ToB32(c); 288 289 proc(state, r, g, b, 0, result); 290 291 r = pin(result[0], SK_R32_MASK); 292 g = pin(result[1], SK_G32_MASK); 293 b = pin(result[2], SK_B32_MASK); 294 295 // now packed it back down to 16bits (hmmm, could dither...) 296 dst[i] = SkPack888ToRGB16(r, g, b); 297 } 298 } 299 300 /////////////////////////////////////////////////////////////////////////////// 301 302 void SkColorMatrixFilter::flatten(SkFlattenableWriteBuffer& buffer) const { 303 this->INHERITED::flatten(buffer); 304 SkASSERT(sizeof(fMatrix.fMat)/sizeof(SkScalar) == 20); 305 buffer.writeScalarArray(fMatrix.fMat, 20); 306 } 307 308 SkColorMatrixFilter::SkColorMatrixFilter(SkFlattenableReadBuffer& buffer) 309 : INHERITED(buffer) { 310 SkASSERT(buffer.getArrayCount() == 20); 311 buffer.readScalarArray(fMatrix.fMat); 312 this->initState(fMatrix.fMat); 313 } 314 315 bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) const { 316 if (matrix) { 317 memcpy(matrix, fMatrix.fMat, 20 * sizeof(SkScalar)); 318 } 319 return true; 320 } 321 322 #if SK_SUPPORT_GPU 323 #include "GrEffect.h" 324 #include "GrTBackendEffectFactory.h" 325 #include "gl/GrGLEffect.h" 326 327 class ColorMatrixEffect : public GrEffect { 328 public: 329 static GrEffectRef* Create(const SkColorMatrix& matrix) { 330 AutoEffectUnref effect(SkNEW_ARGS(ColorMatrixEffect, (matrix))); 331 return CreateEffectRef(effect); 332 } 333 334 static const char* Name() { return "Color Matrix"; } 335 336 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 337 return GrTBackendEffectFactory<ColorMatrixEffect>::getInstance(); 338 } 339 340 virtual void getConstantColorComponents(GrColor* color, 341 uint32_t* validFlags) const SK_OVERRIDE { 342 // We only bother to check whether the alpha channel will be constant. If SkColorMatrix had 343 // type flags it might be worth checking the other components. 344 345 // The matrix is defined such the 4th row determines the output alpha. The first four 346 // columns of that row multiply the input r, g, b, and a, respectively, and the last column 347 // is the "translation". 348 static const uint32_t kRGBAFlags[] = { 349 kR_GrColorComponentFlag, 350 kG_GrColorComponentFlag, 351 kB_GrColorComponentFlag, 352 kA_GrColorComponentFlag 353 }; 354 static const int kShifts[] = { 355 GrColor_SHIFT_R, GrColor_SHIFT_G, GrColor_SHIFT_B, GrColor_SHIFT_A, 356 }; 357 enum { 358 kAlphaRowStartIdx = 15, 359 kAlphaRowTranslateIdx = 19, 360 }; 361 362 SkScalar outputA = 0; 363 for (int i = 0; i < 4; ++i) { 364 // If any relevant component of the color to be passed through the matrix is non-const 365 // then we can't know the final result. 366 if (0 != fMatrix.fMat[kAlphaRowStartIdx + i]) { 367 if (!(*validFlags & kRGBAFlags[i])) { 368 *validFlags = 0; 369 return; 370 } else { 371 uint32_t component = (*color >> kShifts[i]) & 0xFF; 372 outputA += fMatrix.fMat[kAlphaRowStartIdx + i] * component; 373 } 374 } 375 } 376 outputA += fMatrix.fMat[kAlphaRowTranslateIdx]; 377 *validFlags = kA_GrColorComponentFlag; 378 // We pin the color to [0,1]. This would happen to the *final* color output from the frag 379 // shader but currently the effect does not pin its own output. So in the case of over/ 380 // underflow this may deviate from the actual result. Maybe the effect should pin its 381 // result if the matrix could over/underflow for any component? 382 *color = static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A; 383 } 384 385 GR_DECLARE_EFFECT_TEST; 386 387 class GLEffect : public GrGLEffect { 388 public: 389 // this class always generates the same code. 390 static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) { return 0; } 391 392 GLEffect(const GrBackendEffectFactory& factory, 393 const GrDrawEffect&) 394 : INHERITED(factory) 395 , fMatrixHandle(GrGLUniformManager::kInvalidUniformHandle) 396 , fVectorHandle(GrGLUniformManager::kInvalidUniformHandle) {} 397 398 virtual void emitCode(GrGLShaderBuilder* builder, 399 const GrDrawEffect&, 400 EffectKey, 401 const char* outputColor, 402 const char* inputColor, 403 const TextureSamplerArray&) SK_OVERRIDE { 404 fMatrixHandle = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, 405 kMat44f_GrSLType, 406 "ColorMatrix"); 407 fVectorHandle = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, 408 kVec4f_GrSLType, 409 "ColorMatrixVector"); 410 411 if (NULL == inputColor) { 412 // could optimize this case, but we aren't for now. 413 inputColor = GrGLSLOnesVecf(4); 414 } 415 // The max() is to guard against 0 / 0 during unpremul when the incoming color is 416 // transparent black. 417 builder->fsCodeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor); 418 builder->fsCodeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n", 419 outputColor, 420 builder->getUniformCStr(fMatrixHandle), 421 inputColor, 422 builder->getUniformCStr(fVectorHandle)); 423 builder->fsCodeAppendf("\t%s.rgb *= %s.a;\n", outputColor, outputColor); 424 } 425 426 virtual void setData(const GrGLUniformManager& uniManager, 427 const GrDrawEffect& drawEffect) SK_OVERRIDE { 428 const ColorMatrixEffect& cme = drawEffect.castEffect<ColorMatrixEffect>(); 429 const float* m = cme.fMatrix.fMat; 430 // The GL matrix is transposed from SkColorMatrix. 431 GrGLfloat mt[] = { 432 m[0], m[5], m[10], m[15], 433 m[1], m[6], m[11], m[16], 434 m[2], m[7], m[12], m[17], 435 m[3], m[8], m[13], m[18], 436 }; 437 static const float kScale = 1.0f / 255.0f; 438 GrGLfloat vec[] = { 439 m[4] * kScale, m[9] * kScale, m[14] * kScale, m[19] * kScale, 440 }; 441 uniManager.setMatrix4fv(fMatrixHandle, 0, 1, mt); 442 uniManager.set4fv(fVectorHandle, 0, 1, vec); 443 } 444 445 private: 446 GrGLUniformManager::UniformHandle fMatrixHandle; 447 GrGLUniformManager::UniformHandle fVectorHandle; 448 }; 449 450 private: 451 ColorMatrixEffect(const SkColorMatrix& matrix) : fMatrix(matrix) {} 452 453 virtual bool onIsEqual(const GrEffect& s) const { 454 const ColorMatrixEffect& cme = CastEffect<ColorMatrixEffect>(s); 455 return cme.fMatrix == fMatrix; 456 } 457 458 SkColorMatrix fMatrix; 459 460 typedef GrGLEffect INHERITED; 461 }; 462 463 GR_DEFINE_EFFECT_TEST(ColorMatrixEffect); 464 465 GrEffectRef* ColorMatrixEffect::TestCreate(SkMWCRandom* random, 466 GrContext*, 467 const GrDrawTargetCaps&, 468 GrTexture* dummyTextures[2]) { 469 SkColorMatrix colorMatrix; 470 for (size_t i = 0; i < SK_ARRAY_COUNT(colorMatrix.fMat); ++i) { 471 colorMatrix.fMat[i] = random->nextSScalar1(); 472 } 473 return ColorMatrixEffect::Create(colorMatrix); 474 } 475 476 GrEffectRef* SkColorMatrixFilter::asNewEffect(GrContext*) const { 477 return ColorMatrixEffect::Create(fMatrix); 478 } 479 480 #endif 481 482 #ifdef SK_DEVELOPER 483 void SkColorMatrixFilter::toString(SkString* str) const { 484 str->append("SkColorMatrixFilter: "); 485 486 str->append("matrix: ("); 487 for (int i = 0; i < 20; ++i) { 488 str->appendScalar(fMatrix.fMat[i]); 489 if (i < 19) { 490 str->append(", "); 491 } 492 } 493 str->append(")"); 494 } 495 #endif 496