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