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