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 (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 SkASSERT(sizeof(fMatrix.fMat)/sizeof(SkScalar) == 20); 307 buffer.writeScalarArray(fMatrix.fMat, 20); 308} 309 310#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING 311SkColorMatrixFilter::SkColorMatrixFilter(SkReadBuffer& buffer) : INHERITED(buffer) { 312 SkASSERT(buffer.getArrayCount() == 20); 313 if (buffer.readScalarArray(fMatrix.fMat, 20)) { 314 this->initState(fMatrix.fMat); 315 } 316} 317#endif 318 319SkFlattenable* SkColorMatrixFilter::CreateProc(SkReadBuffer& buffer) { 320 SkColorMatrix matrix; 321 if (buffer.readScalarArray(matrix.fMat, 20)) { 322 return Create(matrix); 323 } 324 return NULL; 325} 326 327bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) const { 328 if (matrix) { 329 memcpy(matrix, fMatrix.fMat, 20 * sizeof(SkScalar)); 330 } 331 return true; 332} 333 334#if SK_SUPPORT_GPU 335#include "GrProcessor.h" 336#include "GrTBackendProcessorFactory.h" 337#include "gl/GrGLProcessor.h" 338#include "gl/builders/GrGLProgramBuilder.h" 339 340class ColorMatrixEffect : public GrFragmentProcessor { 341public: 342 static GrFragmentProcessor* Create(const SkColorMatrix& matrix) { 343 return SkNEW_ARGS(ColorMatrixEffect, (matrix)); 344 } 345 346 static const char* Name() { return "Color Matrix"; } 347 348 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE { 349 return GrTBackendFragmentProcessorFactory<ColorMatrixEffect>::getInstance(); 350 } 351 352 virtual void getConstantColorComponents(GrColor* color, 353 uint32_t* validFlags) const SK_OVERRIDE { 354 // We only bother to check whether the alpha channel will be constant. If SkColorMatrix had 355 // type flags it might be worth checking the other components. 356 357 // The matrix is defined such the 4th row determines the output alpha. The first four 358 // columns of that row multiply the input r, g, b, and a, respectively, and the last column 359 // is the "translation". 360 static const uint32_t kRGBAFlags[] = { 361 kR_GrColorComponentFlag, 362 kG_GrColorComponentFlag, 363 kB_GrColorComponentFlag, 364 kA_GrColorComponentFlag 365 }; 366 static const int kShifts[] = { 367 GrColor_SHIFT_R, GrColor_SHIFT_G, GrColor_SHIFT_B, GrColor_SHIFT_A, 368 }; 369 enum { 370 kAlphaRowStartIdx = 15, 371 kAlphaRowTranslateIdx = 19, 372 }; 373 374 SkScalar outputA = 0; 375 for (int i = 0; i < 4; ++i) { 376 // If any relevant component of the color to be passed through the matrix is non-const 377 // then we can't know the final result. 378 if (0 != fMatrix.fMat[kAlphaRowStartIdx + i]) { 379 if (!(*validFlags & kRGBAFlags[i])) { 380 *validFlags = 0; 381 return; 382 } else { 383 uint32_t component = (*color >> kShifts[i]) & 0xFF; 384 outputA += fMatrix.fMat[kAlphaRowStartIdx + i] * component; 385 } 386 } 387 } 388 outputA += fMatrix.fMat[kAlphaRowTranslateIdx]; 389 *validFlags = kA_GrColorComponentFlag; 390 // We pin the color to [0,1]. This would happen to the *final* color output from the frag 391 // shader but currently the effect does not pin its own output. So in the case of over/ 392 // underflow this may deviate from the actual result. Maybe the effect should pin its 393 // result if the matrix could over/underflow for any component? 394 *color = static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A; 395 } 396 397 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 398 399 class GLProcessor : public GrGLFragmentProcessor { 400 public: 401 // this class always generates the same code. 402 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b) {} 403 404 GLProcessor(const GrBackendProcessorFactory& factory, 405 const GrProcessor&) 406 : INHERITED(factory) { 407 } 408 409 virtual void emitCode(GrGLProgramBuilder* builder, 410 const GrFragmentProcessor&, 411 const GrProcessorKey&, 412 const char* outputColor, 413 const char* inputColor, 414 const TransformedCoordsArray&, 415 const TextureSamplerArray&) SK_OVERRIDE { 416 fMatrixHandle = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 417 kMat44f_GrSLType, 418 "ColorMatrix"); 419 fVectorHandle = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 420 kVec4f_GrSLType, 421 "ColorMatrixVector"); 422 423 if (NULL == inputColor) { 424 // could optimize this case, but we aren't for now. 425 inputColor = "vec4(1)"; 426 } 427 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder(); 428 // The max() is to guard against 0 / 0 during unpremul when the incoming color is 429 // transparent black. 430 fsBuilder->codeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor); 431 fsBuilder->codeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n", 432 outputColor, 433 builder->getUniformCStr(fMatrixHandle), 434 inputColor, 435 builder->getUniformCStr(fVectorHandle)); 436 fsBuilder->codeAppendf("\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor); 437 fsBuilder->codeAppendf("\t%s.rgb *= %s.a;\n", outputColor, outputColor); 438 } 439 440 virtual void setData(const GrGLProgramDataManager& uniManager, 441 const GrProcessor& proc) SK_OVERRIDE { 442 const ColorMatrixEffect& cme = proc.cast<ColorMatrixEffect>(); 443 const float* m = cme.fMatrix.fMat; 444 // The GL matrix is transposed from SkColorMatrix. 445 GrGLfloat mt[] = { 446 m[0], m[5], m[10], m[15], 447 m[1], m[6], m[11], m[16], 448 m[2], m[7], m[12], m[17], 449 m[3], m[8], m[13], m[18], 450 }; 451 static const float kScale = 1.0f / 255.0f; 452 GrGLfloat vec[] = { 453 m[4] * kScale, m[9] * kScale, m[14] * kScale, m[19] * kScale, 454 }; 455 uniManager.setMatrix4fv(fMatrixHandle, 1, mt); 456 uniManager.set4fv(fVectorHandle, 1, vec); 457 } 458 459 private: 460 GrGLProgramDataManager::UniformHandle fMatrixHandle; 461 GrGLProgramDataManager::UniformHandle fVectorHandle; 462 463 typedef GrGLFragmentProcessor INHERITED; 464 }; 465 466private: 467 ColorMatrixEffect(const SkColorMatrix& matrix) : fMatrix(matrix) {} 468 469 virtual bool onIsEqual(const GrProcessor& s) const { 470 const ColorMatrixEffect& cme = s.cast<ColorMatrixEffect>(); 471 return cme.fMatrix == fMatrix; 472 } 473 474 SkColorMatrix fMatrix; 475 476 typedef GrFragmentProcessor INHERITED; 477}; 478 479GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorMatrixEffect); 480 481GrFragmentProcessor* ColorMatrixEffect::TestCreate(SkRandom* random, 482 GrContext*, 483 const GrDrawTargetCaps&, 484 GrTexture* dummyTextures[2]) { 485 SkColorMatrix colorMatrix; 486 for (size_t i = 0; i < SK_ARRAY_COUNT(colorMatrix.fMat); ++i) { 487 colorMatrix.fMat[i] = random->nextSScalar1(); 488 } 489 return ColorMatrixEffect::Create(colorMatrix); 490} 491 492GrFragmentProcessor* SkColorMatrixFilter::asFragmentProcessor(GrContext*) const { 493 return ColorMatrixEffect::Create(fMatrix); 494} 495 496#endif 497 498#ifndef SK_IGNORE_TO_STRING 499void SkColorMatrixFilter::toString(SkString* str) const { 500 str->append("SkColorMatrixFilter: "); 501 502 str->append("matrix: ("); 503 for (int i = 0; i < 20; ++i) { 504 str->appendScalar(fMatrix.fMat[i]); 505 if (i < 19) { 506 str->append(", "); 507 } 508 } 509 str->append(")"); 510} 511#endif 512