gfx/skia/trunk/src/effects/SkArithmeticMode.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial