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