1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkArithmeticMode.h" 9 #include "SkColorPriv.h" 10 #include "SkReadBuffer.h" 11 #include "SkWriteBuffer.h" 12 #include "SkString.h" 13 #include "SkUnPreMultiply.h" 14 #if SK_SUPPORT_GPU 15 #include "GrContext.h" 16 #include "GrCoordTransform.h" 17 #include "gl/GrGLProcessor.h" 18 #include "gl/builders/GrGLProgramBuilder.h" 19 #include "GrTBackendProcessorFactory.h" 20 #endif 21 22 static const bool gUseUnpremul = false; 23 24 class SkArithmeticMode_scalar : public SkXfermode { 25 public: 26 static SkArithmeticMode_scalar* Create(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, 27 bool enforcePMColor) { 28 return SkNEW_ARGS(SkArithmeticMode_scalar, (k1, k2, k3, k4, enforcePMColor)); 29 } 30 31 virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, 32 const SkAlpha aa[]) const SK_OVERRIDE; 33 34 SK_TO_STRING_OVERRIDE() 35 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar) 36 37 #if SK_SUPPORT_GPU 38 virtual bool asFragmentProcessor(GrFragmentProcessor**, 39 GrTexture* background) const SK_OVERRIDE; 40 #endif 41 42 private: 43 SkArithmeticMode_scalar(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, bool enforcePMColor) { 44 fK[0] = k1; 45 fK[1] = k2; 46 fK[2] = k3; 47 fK[3] = k4; 48 fEnforcePMColor = enforcePMColor; 49 } 50 51 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING 52 SkArithmeticMode_scalar(SkReadBuffer& buffer) : INHERITED(buffer) { 53 fK[0] = buffer.readScalar(); 54 fK[1] = buffer.readScalar(); 55 fK[2] = buffer.readScalar(); 56 fK[3] = buffer.readScalar(); 57 fEnforcePMColor = buffer.readBool(); 58 } 59 #endif 60 61 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE { 62 buffer.writeScalar(fK[0]); 63 buffer.writeScalar(fK[1]); 64 buffer.writeScalar(fK[2]); 65 buffer.writeScalar(fK[3]); 66 buffer.writeBool(fEnforcePMColor); 67 } 68 SkScalar fK[4]; 69 bool fEnforcePMColor; 70 71 friend class SkArithmeticMode; 72 73 typedef SkXfermode INHERITED; 74 }; 75 76 SkFlattenable* SkArithmeticMode_scalar::CreateProc(SkReadBuffer& buffer) { 77 const SkScalar k1 = buffer.readScalar(); 78 const SkScalar k2 = buffer.readScalar(); 79 const SkScalar k3 = buffer.readScalar(); 80 const SkScalar k4 = buffer.readScalar(); 81 const bool enforcePMColor = buffer.readBool(); 82 return Create(k1, k2, k3, k4, enforcePMColor); 83 } 84 85 static int pinToByte(int value) { 86 if (value < 0) { 87 value = 0; 88 } else if (value > 255) { 89 value = 255; 90 } 91 return value; 92 } 93 94 static int arith(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, 95 int src, int dst) { 96 SkScalar result = SkScalarMul(k1, src * dst) + 97 SkScalarMul(k2, src) + 98 SkScalarMul(k3, dst) + 99 k4; 100 int res = SkScalarRoundToInt(result); 101 return pinToByte(res); 102 } 103 104 static int blend(int src, int dst, int scale) { 105 return dst + ((src - dst) * scale >> 8); 106 } 107 108 static bool needsUnpremul(int alpha) { 109 return 0 != alpha && 0xFF != alpha; 110 } 111 112 void SkArithmeticMode_scalar::xfer32(SkPMColor dst[], const SkPMColor src[], 113 int count, const SkAlpha aaCoverage[]) const { 114 SkScalar k1 = fK[0] / 255; 115 SkScalar k2 = fK[1]; 116 SkScalar k3 = fK[2]; 117 SkScalar k4 = fK[3] * 255; 118 119 for (int i = 0; i < count; ++i) { 120 if ((NULL == aaCoverage) || aaCoverage[i]) { 121 SkPMColor sc = src[i]; 122 SkPMColor dc = dst[i]; 123 124 int a, r, g, b; 125 126 if (gUseUnpremul) { 127 int sa = SkGetPackedA32(sc); 128 int da = SkGetPackedA32(dc); 129 130 int srcNeedsUnpremul = needsUnpremul(sa); 131 int dstNeedsUnpremul = needsUnpremul(da); 132 133 if (!srcNeedsUnpremul && !dstNeedsUnpremul) { 134 a = arith(k1, k2, k3, k4, sa, da); 135 r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc)); 136 g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc)); 137 b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc)); 138 } else { 139 int sr = SkGetPackedR32(sc); 140 int sg = SkGetPackedG32(sc); 141 int sb = SkGetPackedB32(sc); 142 if (srcNeedsUnpremul) { 143 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(sa); 144 sr = SkUnPreMultiply::ApplyScale(scale, sr); 145 sg = SkUnPreMultiply::ApplyScale(scale, sg); 146 sb = SkUnPreMultiply::ApplyScale(scale, sb); 147 } 148 149 int dr = SkGetPackedR32(dc); 150 int dg = SkGetPackedG32(dc); 151 int db = SkGetPackedB32(dc); 152 if (dstNeedsUnpremul) { 153 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(da); 154 dr = SkUnPreMultiply::ApplyScale(scale, dr); 155 dg = SkUnPreMultiply::ApplyScale(scale, dg); 156 db = SkUnPreMultiply::ApplyScale(scale, db); 157 } 158 159 a = arith(k1, k2, k3, k4, sa, da); 160 r = arith(k1, k2, k3, k4, sr, dr); 161 g = arith(k1, k2, k3, k4, sg, dg); 162 b = arith(k1, k2, k3, k4, sb, db); 163 } 164 } else { 165 a = arith(k1, k2, k3, k4, SkGetPackedA32(sc), SkGetPackedA32(dc)); 166 r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc)); 167 g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc)); 168 b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc)); 169 if (fEnforcePMColor) { 170 r = SkMin32(r, a); 171 g = SkMin32(g, a); 172 b = SkMin32(b, a); 173 } 174 } 175 176 // apply antialias coverage if necessary 177 if (aaCoverage && 0xFF != aaCoverage[i]) { 178 int scale = aaCoverage[i] + (aaCoverage[i] >> 7); 179 a = blend(a, SkGetPackedA32(sc), scale); 180 r = blend(r, SkGetPackedR32(sc), scale); 181 g = blend(g, SkGetPackedG32(sc), scale); 182 b = blend(b, SkGetPackedB32(sc), scale); 183 } 184 185 // turn the result back into premul 186 if (gUseUnpremul && (0xFF != a)) { 187 int scale = a + (a >> 7); 188 r = SkAlphaMul(r, scale); 189 g = SkAlphaMul(g, scale); 190 b = SkAlphaMul(b, scale); 191 } 192 dst[i] = fEnforcePMColor ? SkPackARGB32(a, r, g, b) : SkPackARGB32NoCheck(a, r, g, b); 193 } 194 } 195 } 196 197 #ifndef SK_IGNORE_TO_STRING 198 void SkArithmeticMode_scalar::toString(SkString* str) const { 199 str->append("SkArithmeticMode_scalar: "); 200 for (int i = 0; i < 4; ++i) { 201 str->appendScalar(fK[i]); 202 str->append(" "); 203 } 204 str->appendS32(fEnforcePMColor ? 1 : 0); 205 } 206 #endif 207 208 /////////////////////////////////////////////////////////////////////////////// 209 210 static bool fitsInBits(SkScalar x, int bits) { 211 return SkScalarAbs(x) < (1 << (bits - 1)); 212 } 213 214 #if 0 // UNUSED 215 static int32_t toDot8(SkScalar x) { 216 return (int32_t)(x * 256); 217 } 218 #endif 219 220 SkXfermode* SkArithmeticMode::Create(SkScalar k1, SkScalar k2, 221 SkScalar k3, SkScalar k4, 222 bool enforcePMColor) { 223 if (fitsInBits(k1, 8) && fitsInBits(k2, 16) && 224 fitsInBits(k2, 16) && fitsInBits(k2, 24)) { 225 226 #if 0 // UNUSED 227 int32_t i1 = toDot8(k1); 228 int32_t i2 = toDot8(k2); 229 int32_t i3 = toDot8(k3); 230 int32_t i4 = toDot8(k4); 231 if (i1) { 232 return SkNEW_ARGS(SkArithmeticMode_quad, (i1, i2, i3, i4)); 233 } 234 if (0 == i2) { 235 return SkNEW_ARGS(SkArithmeticMode_dst, (i3, i4)); 236 } 237 if (0 == i3) { 238 return SkNEW_ARGS(SkArithmeticMode_src, (i2, i4)); 239 } 240 return SkNEW_ARGS(SkArithmeticMode_linear, (i2, i3, i4)); 241 #endif 242 } 243 return SkArithmeticMode_scalar::Create(k1, k2, k3, k4, enforcePMColor); 244 } 245 246 247 ////////////////////////////////////////////////////////////////////////////// 248 249 #if SK_SUPPORT_GPU 250 251 class GrGLArithmeticEffect : public GrGLFragmentProcessor { 252 public: 253 GrGLArithmeticEffect(const GrBackendProcessorFactory&, const GrProcessor&); 254 virtual ~GrGLArithmeticEffect(); 255 256 virtual void emitCode(GrGLProgramBuilder*, 257 const GrFragmentProcessor&, 258 const GrProcessorKey&, 259 const char* outputColor, 260 const char* inputColor, 261 const TransformedCoordsArray&, 262 const TextureSamplerArray&) SK_OVERRIDE; 263 264 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE; 265 266 static void GenKey(const GrProcessor&, const GrGLCaps& caps, GrProcessorKeyBuilder* b); 267 268 private: 269 GrGLProgramDataManager::UniformHandle fKUni; 270 bool fEnforcePMColor; 271 272 typedef GrGLFragmentProcessor INHERITED; 273 }; 274 275 /////////////////////////////////////////////////////////////////////////////// 276 277 class GrArithmeticEffect : public GrFragmentProcessor { 278 public: 279 static GrFragmentProcessor* Create(float k1, float k2, float k3, float k4, bool enforcePMColor, 280 GrTexture* background) { 281 return SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4, enforcePMColor, background)); 282 } 283 284 virtual ~GrArithmeticEffect(); 285 286 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE; 287 288 typedef GrGLArithmeticEffect GLProcessor; 289 static const char* Name() { return "Arithmetic"; } 290 GrTexture* backgroundTexture() const { return fBackgroundAccess.getTexture(); } 291 292 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; 293 294 float k1() const { return fK1; } 295 float k2() const { return fK2; } 296 float k3() const { return fK3; } 297 float k4() const { return fK4; } 298 bool enforcePMColor() const { return fEnforcePMColor; } 299 300 private: 301 virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE; 302 303 GrArithmeticEffect(float k1, float k2, float k3, float k4, bool enforcePMColor, 304 GrTexture* background); 305 float fK1, fK2, fK3, fK4; 306 bool fEnforcePMColor; 307 GrCoordTransform fBackgroundTransform; 308 GrTextureAccess fBackgroundAccess; 309 310 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 311 typedef GrFragmentProcessor INHERITED; 312 313 }; 314 315 /////////////////////////////////////////////////////////////////////////////// 316 317 GrArithmeticEffect::GrArithmeticEffect(float k1, float k2, float k3, float k4, 318 bool enforcePMColor, GrTexture* background) 319 : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) { 320 if (background) { 321 fBackgroundTransform.reset(kLocal_GrCoordSet, background); 322 this->addCoordTransform(&fBackgroundTransform); 323 fBackgroundAccess.reset(background); 324 this->addTextureAccess(&fBackgroundAccess); 325 } else { 326 this->setWillReadDstColor(); 327 } 328 } 329 330 GrArithmeticEffect::~GrArithmeticEffect() { 331 } 332 333 bool GrArithmeticEffect::onIsEqual(const GrProcessor& sBase) const { 334 const GrArithmeticEffect& s = sBase.cast<GrArithmeticEffect>(); 335 return fK1 == s.fK1 && 336 fK2 == s.fK2 && 337 fK3 == s.fK3 && 338 fK4 == s.fK4 && 339 fEnforcePMColor == s.fEnforcePMColor && 340 backgroundTexture() == s.backgroundTexture(); 341 } 342 343 const GrBackendFragmentProcessorFactory& GrArithmeticEffect::getFactory() const { 344 return GrTBackendFragmentProcessorFactory<GrArithmeticEffect>::getInstance(); 345 } 346 347 void GrArithmeticEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 348 // TODO: optimize this 349 *validFlags = 0; 350 } 351 352 /////////////////////////////////////////////////////////////////////////////// 353 354 GrGLArithmeticEffect::GrGLArithmeticEffect(const GrBackendProcessorFactory& factory, 355 const GrProcessor&) 356 : INHERITED(factory), 357 fEnforcePMColor(true) { 358 } 359 360 GrGLArithmeticEffect::~GrGLArithmeticEffect() { 361 } 362 363 void GrGLArithmeticEffect::emitCode(GrGLProgramBuilder* builder, 364 const GrFragmentProcessor& fp, 365 const GrProcessorKey& key, 366 const char* outputColor, 367 const char* inputColor, 368 const TransformedCoordsArray& coords, 369 const TextureSamplerArray& samplers) { 370 371 GrTexture* backgroundTex = fp.cast<GrArithmeticEffect>().backgroundTexture(); 372 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder(); 373 const char* dstColor; 374 if (backgroundTex) { 375 fsBuilder->codeAppend("\t\tvec4 bgColor = "); 376 fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType()); 377 fsBuilder->codeAppendf(";\n"); 378 dstColor = "bgColor"; 379 } else { 380 dstColor = fsBuilder->dstColor(); 381 } 382 383 SkASSERT(dstColor); 384 fKUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 385 kVec4f_GrSLType, "k"); 386 const char* kUni = builder->getUniformCStr(fKUni); 387 388 // We don't try to optimize for this case at all 389 if (NULL == inputColor) { 390 fsBuilder->codeAppendf("\t\tconst vec4 src = vec4(1);\n"); 391 } else { 392 fsBuilder->codeAppendf("\t\tvec4 src = %s;\n", inputColor); 393 if (gUseUnpremul) { 394 fsBuilder->codeAppendf("\t\tsrc.rgb = clamp(src.rgb / src.a, 0.0, 1.0);\n"); 395 } 396 } 397 398 fsBuilder->codeAppendf("\t\tvec4 dst = %s;\n", dstColor); 399 if (gUseUnpremul) { 400 fsBuilder->codeAppendf("\t\tdst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);\n"); 401 } 402 403 fsBuilder->codeAppendf("\t\t%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;\n", outputColor, kUni, kUni, kUni, kUni); 404 fsBuilder->codeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor); 405 if (gUseUnpremul) { 406 fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor); 407 } else if (fEnforcePMColor) { 408 fsBuilder->codeAppendf("\t\t%s.rgb = min(%s.rgb, %s.a);\n", outputColor, outputColor, outputColor); 409 } 410 } 411 412 void GrGLArithmeticEffect::setData(const GrGLProgramDataManager& pdman, 413 const GrProcessor& processor) { 414 const GrArithmeticEffect& arith = processor.cast<GrArithmeticEffect>(); 415 pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); 416 fEnforcePMColor = arith.enforcePMColor(); 417 } 418 419 void GrGLArithmeticEffect::GenKey(const GrProcessor& processor, 420 const GrGLCaps&, GrProcessorKeyBuilder* b) { 421 const GrArithmeticEffect& arith = processor.cast<GrArithmeticEffect>(); 422 uint32_t key = arith.enforcePMColor() ? 1 : 0; 423 if (arith.backgroundTexture()) { 424 key |= 2; 425 } 426 b->add32(key); 427 } 428 429 GrFragmentProcessor* GrArithmeticEffect::TestCreate(SkRandom* rand, 430 GrContext*, 431 const GrDrawTargetCaps&, 432 GrTexture*[]) { 433 float k1 = rand->nextF(); 434 float k2 = rand->nextF(); 435 float k3 = rand->nextF(); 436 float k4 = rand->nextF(); 437 bool enforcePMColor = rand->nextBool(); 438 439 return SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4, enforcePMColor, NULL)); 440 } 441 442 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticEffect); 443 444 bool SkArithmeticMode_scalar::asFragmentProcessor(GrFragmentProcessor** fp, 445 GrTexture* background) const { 446 if (fp) { 447 *fp = GrArithmeticEffect::Create(SkScalarToFloat(fK[0]), 448 SkScalarToFloat(fK[1]), 449 SkScalarToFloat(fK[2]), 450 SkScalarToFloat(fK[3]), 451 fEnforcePMColor, 452 background); 453 } 454 return true; 455 } 456 457 #endif 458 459 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkArithmeticMode) 460 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArithmeticMode_scalar) 461 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 462