1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/effects/SkArithmeticMode.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,417 @@ 1.4 +/* 1.5 + * Copyright 2013 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkArithmeticMode.h" 1.12 +#include "SkColorPriv.h" 1.13 +#include "SkReadBuffer.h" 1.14 +#include "SkWriteBuffer.h" 1.15 +#include "SkString.h" 1.16 +#include "SkUnPreMultiply.h" 1.17 +#if SK_SUPPORT_GPU 1.18 +#include "GrContext.h" 1.19 +#include "GrCoordTransform.h" 1.20 +#include "gl/GrGLEffect.h" 1.21 +#include "GrTBackendEffectFactory.h" 1.22 +#endif 1.23 + 1.24 +static const bool gUseUnpremul = false; 1.25 + 1.26 +class SkArithmeticMode_scalar : public SkXfermode { 1.27 +public: 1.28 + static SkArithmeticMode_scalar* Create(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4) { 1.29 + return SkNEW_ARGS(SkArithmeticMode_scalar, (k1, k2, k3, k4)); 1.30 + } 1.31 + 1.32 + virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, 1.33 + const SkAlpha aa[]) const SK_OVERRIDE; 1.34 + 1.35 + SK_TO_STRING_OVERRIDE() 1.36 + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar) 1.37 + 1.38 +#if SK_SUPPORT_GPU 1.39 + virtual bool asNewEffect(GrEffectRef** effect, GrTexture* background) const SK_OVERRIDE; 1.40 +#endif 1.41 + 1.42 +private: 1.43 + SkArithmeticMode_scalar(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4) { 1.44 + fK[0] = k1; 1.45 + fK[1] = k2; 1.46 + fK[2] = k3; 1.47 + fK[3] = k4; 1.48 + } 1.49 + 1.50 + SkArithmeticMode_scalar(SkReadBuffer& buffer) : INHERITED(buffer) { 1.51 + fK[0] = buffer.readScalar(); 1.52 + fK[1] = buffer.readScalar(); 1.53 + fK[2] = buffer.readScalar(); 1.54 + fK[3] = buffer.readScalar(); 1.55 + } 1.56 + 1.57 + virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE { 1.58 + INHERITED::flatten(buffer); 1.59 + buffer.writeScalar(fK[0]); 1.60 + buffer.writeScalar(fK[1]); 1.61 + buffer.writeScalar(fK[2]); 1.62 + buffer.writeScalar(fK[3]); 1.63 + } 1.64 + SkScalar fK[4]; 1.65 + 1.66 + typedef SkXfermode INHERITED; 1.67 +}; 1.68 + 1.69 +static int pinToByte(int value) { 1.70 + if (value < 0) { 1.71 + value = 0; 1.72 + } else if (value > 255) { 1.73 + value = 255; 1.74 + } 1.75 + return value; 1.76 +} 1.77 + 1.78 +static int arith(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, 1.79 + int src, int dst) { 1.80 + SkScalar result = SkScalarMul(k1, src * dst) + 1.81 + SkScalarMul(k2, src) + 1.82 + SkScalarMul(k3, dst) + 1.83 + k4; 1.84 + int res = SkScalarRoundToInt(result); 1.85 + return pinToByte(res); 1.86 +} 1.87 + 1.88 +static int blend(int src, int dst, int scale) { 1.89 + return dst + ((src - dst) * scale >> 8); 1.90 +} 1.91 + 1.92 +static bool needsUnpremul(int alpha) { 1.93 + return 0 != alpha && 0xFF != alpha; 1.94 +} 1.95 + 1.96 +void SkArithmeticMode_scalar::xfer32(SkPMColor dst[], const SkPMColor src[], 1.97 + int count, const SkAlpha aaCoverage[]) const { 1.98 + SkScalar k1 = fK[0] / 255; 1.99 + SkScalar k2 = fK[1]; 1.100 + SkScalar k3 = fK[2]; 1.101 + SkScalar k4 = fK[3] * 255; 1.102 + 1.103 + for (int i = 0; i < count; ++i) { 1.104 + if ((NULL == aaCoverage) || aaCoverage[i]) { 1.105 + SkPMColor sc = src[i]; 1.106 + SkPMColor dc = dst[i]; 1.107 + 1.108 + int a, r, g, b; 1.109 + 1.110 + if (gUseUnpremul) { 1.111 + int sa = SkGetPackedA32(sc); 1.112 + int da = SkGetPackedA32(dc); 1.113 + 1.114 + int srcNeedsUnpremul = needsUnpremul(sa); 1.115 + int dstNeedsUnpremul = needsUnpremul(da); 1.116 + 1.117 + if (!srcNeedsUnpremul && !dstNeedsUnpremul) { 1.118 + a = arith(k1, k2, k3, k4, sa, da); 1.119 + r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc)); 1.120 + g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc)); 1.121 + b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc)); 1.122 + } else { 1.123 + int sr = SkGetPackedR32(sc); 1.124 + int sg = SkGetPackedG32(sc); 1.125 + int sb = SkGetPackedB32(sc); 1.126 + if (srcNeedsUnpremul) { 1.127 + SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(sa); 1.128 + sr = SkUnPreMultiply::ApplyScale(scale, sr); 1.129 + sg = SkUnPreMultiply::ApplyScale(scale, sg); 1.130 + sb = SkUnPreMultiply::ApplyScale(scale, sb); 1.131 + } 1.132 + 1.133 + int dr = SkGetPackedR32(dc); 1.134 + int dg = SkGetPackedG32(dc); 1.135 + int db = SkGetPackedB32(dc); 1.136 + if (dstNeedsUnpremul) { 1.137 + SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(da); 1.138 + dr = SkUnPreMultiply::ApplyScale(scale, dr); 1.139 + dg = SkUnPreMultiply::ApplyScale(scale, dg); 1.140 + db = SkUnPreMultiply::ApplyScale(scale, db); 1.141 + } 1.142 + 1.143 + a = arith(k1, k2, k3, k4, sa, da); 1.144 + r = arith(k1, k2, k3, k4, sr, dr); 1.145 + g = arith(k1, k2, k3, k4, sg, dg); 1.146 + b = arith(k1, k2, k3, k4, sb, db); 1.147 + } 1.148 + } else { 1.149 + a = arith(k1, k2, k3, k4, SkGetPackedA32(sc), SkGetPackedA32(dc)); 1.150 + r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc)); 1.151 + r = SkMin32(r, a); 1.152 + g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc)); 1.153 + g = SkMin32(g, a); 1.154 + b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc)); 1.155 + b = SkMin32(b, a); 1.156 + } 1.157 + 1.158 + // apply antialias coverage if necessary 1.159 + if (aaCoverage && 0xFF != aaCoverage[i]) { 1.160 + int scale = aaCoverage[i] + (aaCoverage[i] >> 7); 1.161 + a = blend(a, SkGetPackedA32(sc), scale); 1.162 + r = blend(r, SkGetPackedR32(sc), scale); 1.163 + g = blend(g, SkGetPackedG32(sc), scale); 1.164 + b = blend(b, SkGetPackedB32(sc), scale); 1.165 + } 1.166 + 1.167 + // turn the result back into premul 1.168 + if (gUseUnpremul && (0xFF != a)) { 1.169 + int scale = a + (a >> 7); 1.170 + r = SkAlphaMul(r, scale); 1.171 + g = SkAlphaMul(g, scale); 1.172 + b = SkAlphaMul(b, scale); 1.173 + } 1.174 + dst[i] = SkPackARGB32(a, r, g, b); 1.175 + } 1.176 + } 1.177 +} 1.178 + 1.179 +#ifndef SK_IGNORE_TO_STRING 1.180 +void SkArithmeticMode_scalar::toString(SkString* str) const { 1.181 + str->append("SkArithmeticMode_scalar: "); 1.182 + for (int i = 0; i < 4; ++i) { 1.183 + str->appendScalar(fK[i]); 1.184 + if (i < 3) { 1.185 + str->append(" "); 1.186 + } 1.187 + } 1.188 +} 1.189 +#endif 1.190 + 1.191 +/////////////////////////////////////////////////////////////////////////////// 1.192 + 1.193 +static bool fitsInBits(SkScalar x, int bits) { 1.194 + return SkScalarAbs(x) < (1 << (bits - 1)); 1.195 +} 1.196 + 1.197 +#if 0 // UNUSED 1.198 +static int32_t toDot8(SkScalar x) { 1.199 + return (int32_t)(x * 256); 1.200 +} 1.201 +#endif 1.202 + 1.203 +SkXfermode* SkArithmeticMode::Create(SkScalar k1, SkScalar k2, 1.204 + SkScalar k3, SkScalar k4) { 1.205 + if (fitsInBits(k1, 8) && fitsInBits(k2, 16) && 1.206 + fitsInBits(k2, 16) && fitsInBits(k2, 24)) { 1.207 + 1.208 +#if 0 // UNUSED 1.209 + int32_t i1 = toDot8(k1); 1.210 + int32_t i2 = toDot8(k2); 1.211 + int32_t i3 = toDot8(k3); 1.212 + int32_t i4 = toDot8(k4); 1.213 + if (i1) { 1.214 + return SkNEW_ARGS(SkArithmeticMode_quad, (i1, i2, i3, i4)); 1.215 + } 1.216 + if (0 == i2) { 1.217 + return SkNEW_ARGS(SkArithmeticMode_dst, (i3, i4)); 1.218 + } 1.219 + if (0 == i3) { 1.220 + return SkNEW_ARGS(SkArithmeticMode_src, (i2, i4)); 1.221 + } 1.222 + return SkNEW_ARGS(SkArithmeticMode_linear, (i2, i3, i4)); 1.223 +#endif 1.224 + } 1.225 + return SkArithmeticMode_scalar::Create(k1, k2, k3, k4); 1.226 +} 1.227 + 1.228 + 1.229 +////////////////////////////////////////////////////////////////////////////// 1.230 + 1.231 +#if SK_SUPPORT_GPU 1.232 + 1.233 +class GrGLArithmeticEffect : public GrGLEffect { 1.234 +public: 1.235 + GrGLArithmeticEffect(const GrBackendEffectFactory&, const GrDrawEffect&); 1.236 + virtual ~GrGLArithmeticEffect(); 1.237 + 1.238 + virtual void emitCode(GrGLShaderBuilder*, 1.239 + const GrDrawEffect&, 1.240 + EffectKey, 1.241 + const char* outputColor, 1.242 + const char* inputColor, 1.243 + const TransformedCoordsArray&, 1.244 + const TextureSamplerArray&) SK_OVERRIDE; 1.245 + 1.246 + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; 1.247 + 1.248 +private: 1.249 + GrGLUniformManager::UniformHandle fKUni; 1.250 + 1.251 + typedef GrGLEffect INHERITED; 1.252 +}; 1.253 + 1.254 +/////////////////////////////////////////////////////////////////////////////// 1.255 + 1.256 +class GrArithmeticEffect : public GrEffect { 1.257 +public: 1.258 + static GrEffectRef* Create(float k1, float k2, float k3, float k4, GrTexture* background) { 1.259 + AutoEffectUnref effect(SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4, background))); 1.260 + return CreateEffectRef(effect); 1.261 + } 1.262 + 1.263 + virtual ~GrArithmeticEffect(); 1.264 + 1.265 + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; 1.266 + 1.267 + typedef GrGLArithmeticEffect GLEffect; 1.268 + static const char* Name() { return "Arithmetic"; } 1.269 + GrTexture* backgroundTexture() const { return fBackgroundAccess.getTexture(); } 1.270 + 1.271 + virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; 1.272 + 1.273 + float k1() const { return fK1; } 1.274 + float k2() const { return fK2; } 1.275 + float k3() const { return fK3; } 1.276 + float k4() const { return fK4; } 1.277 + 1.278 +private: 1.279 + virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; 1.280 + 1.281 + GrArithmeticEffect(float k1, float k2, float k3, float k4, GrTexture* background); 1.282 + float fK1, fK2, fK3, fK4; 1.283 + GrCoordTransform fBackgroundTransform; 1.284 + GrTextureAccess fBackgroundAccess; 1.285 + 1.286 + GR_DECLARE_EFFECT_TEST; 1.287 + typedef GrEffect INHERITED; 1.288 + 1.289 +}; 1.290 + 1.291 +/////////////////////////////////////////////////////////////////////////////// 1.292 + 1.293 +GrArithmeticEffect::GrArithmeticEffect(float k1, float k2, float k3, float k4, 1.294 + GrTexture* background) 1.295 + : fK1(k1), fK2(k2), fK3(k3), fK4(k4) { 1.296 + if (background) { 1.297 + fBackgroundTransform.reset(kLocal_GrCoordSet, background); 1.298 + this->addCoordTransform(&fBackgroundTransform); 1.299 + fBackgroundAccess.reset(background); 1.300 + this->addTextureAccess(&fBackgroundAccess); 1.301 + } else { 1.302 + this->setWillReadDstColor(); 1.303 + } 1.304 +} 1.305 + 1.306 +GrArithmeticEffect::~GrArithmeticEffect() { 1.307 +} 1.308 + 1.309 +bool GrArithmeticEffect::onIsEqual(const GrEffect& sBase) const { 1.310 + const GrArithmeticEffect& s = CastEffect<GrArithmeticEffect>(sBase); 1.311 + return fK1 == s.fK1 && 1.312 + fK2 == s.fK2 && 1.313 + fK3 == s.fK3 && 1.314 + fK4 == s.fK4 && 1.315 + backgroundTexture() == s.backgroundTexture(); 1.316 +} 1.317 + 1.318 +const GrBackendEffectFactory& GrArithmeticEffect::getFactory() const { 1.319 + return GrTBackendEffectFactory<GrArithmeticEffect>::getInstance(); 1.320 +} 1.321 + 1.322 +void GrArithmeticEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 1.323 + // TODO: optimize this 1.324 + *validFlags = 0; 1.325 +} 1.326 + 1.327 +/////////////////////////////////////////////////////////////////////////////// 1.328 + 1.329 +GrGLArithmeticEffect::GrGLArithmeticEffect(const GrBackendEffectFactory& factory, 1.330 + const GrDrawEffect& drawEffect) 1.331 + : INHERITED(factory) { 1.332 +} 1.333 + 1.334 +GrGLArithmeticEffect::~GrGLArithmeticEffect() { 1.335 +} 1.336 + 1.337 +void GrGLArithmeticEffect::emitCode(GrGLShaderBuilder* builder, 1.338 + const GrDrawEffect& drawEffect, 1.339 + EffectKey key, 1.340 + const char* outputColor, 1.341 + const char* inputColor, 1.342 + const TransformedCoordsArray& coords, 1.343 + const TextureSamplerArray& samplers) { 1.344 + 1.345 + GrTexture* backgroundTex = drawEffect.castEffect<GrArithmeticEffect>().backgroundTexture(); 1.346 + const char* dstColor; 1.347 + if (backgroundTex) { 1.348 + builder->fsCodeAppend("\t\tvec4 bgColor = "); 1.349 + builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type()); 1.350 + builder->fsCodeAppendf(";\n"); 1.351 + dstColor = "bgColor"; 1.352 + } else { 1.353 + dstColor = builder->dstColor(); 1.354 + } 1.355 + 1.356 + SkASSERT(NULL != dstColor); 1.357 + fKUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 1.358 + kVec4f_GrSLType, "k"); 1.359 + const char* kUni = builder->getUniformCStr(fKUni); 1.360 + 1.361 + // We don't try to optimize for this case at all 1.362 + if (NULL == inputColor) { 1.363 + builder->fsCodeAppendf("\t\tconst vec4 src = vec4(1);\n"); 1.364 + } else { 1.365 + builder->fsCodeAppendf("\t\tvec4 src = %s;\n", inputColor); 1.366 + if (gUseUnpremul) { 1.367 + builder->fsCodeAppendf("\t\tsrc.rgb = clamp(src.rgb / src.a, 0.0, 1.0);\n"); 1.368 + } 1.369 + } 1.370 + 1.371 + builder->fsCodeAppendf("\t\tvec4 dst = %s;\n", dstColor); 1.372 + if (gUseUnpremul) { 1.373 + builder->fsCodeAppendf("\t\tdst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);\n"); 1.374 + } 1.375 + 1.376 + builder->fsCodeAppendf("\t\t%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;\n", outputColor, kUni, kUni, kUni, kUni); 1.377 + builder->fsCodeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor); 1.378 + if (gUseUnpremul) { 1.379 + builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor); 1.380 + } else { 1.381 + builder->fsCodeAppendf("\t\t%s.rgb = min(%s.rgb, %s.a);\n", outputColor, outputColor, outputColor); 1.382 + } 1.383 +} 1.384 + 1.385 +void GrGLArithmeticEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { 1.386 + const GrArithmeticEffect& arith = drawEffect.castEffect<GrArithmeticEffect>(); 1.387 + uman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); 1.388 +} 1.389 + 1.390 +GrEffectRef* GrArithmeticEffect::TestCreate(SkRandom* rand, 1.391 + GrContext*, 1.392 + const GrDrawTargetCaps&, 1.393 + GrTexture*[]) { 1.394 + float k1 = rand->nextF(); 1.395 + float k2 = rand->nextF(); 1.396 + float k3 = rand->nextF(); 1.397 + float k4 = rand->nextF(); 1.398 + 1.399 + AutoEffectUnref gEffect(SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4, NULL))); 1.400 + return CreateEffectRef(gEffect); 1.401 +} 1.402 + 1.403 +GR_DEFINE_EFFECT_TEST(GrArithmeticEffect); 1.404 + 1.405 +bool SkArithmeticMode_scalar::asNewEffect(GrEffectRef** effect, GrTexture* background) const { 1.406 + if (effect) { 1.407 + *effect = GrArithmeticEffect::Create(SkScalarToFloat(fK[0]), 1.408 + SkScalarToFloat(fK[1]), 1.409 + SkScalarToFloat(fK[2]), 1.410 + SkScalarToFloat(fK[3]), 1.411 + background); 1.412 + } 1.413 + return true; 1.414 +} 1.415 + 1.416 +#endif 1.417 + 1.418 +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkArithmeticMode) 1.419 + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArithmeticMode_scalar) 1.420 +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END