/* * Copyright 2019 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "tools/SkVMBuilders.h" // Some parts of this builder code are written less fluently than possible, // to avoid any ambiguity of function argument evaluation order. This lets // our golden tests work portably. In general there's no reason to fear // nesting calls to Builder routines. SrcoverBuilder_F32::SrcoverBuilder_F32(Fmt srcFmt, Fmt dstFmt) { auto load = [&](Fmt fmt, skvm::F32* r, skvm::F32* g, skvm::F32* b, skvm::F32* a) { skvm::Arg ptr; switch (fmt) { case Fmt::A8: { ptr = varying(); *r = *g = *b = splat(0.0f); *a = from_unorm(8, load8(ptr)); } break; case Fmt::G8: { ptr = varying(); *r = *g = *b = from_unorm(8, load8(ptr)); *a = splat(1.0f); } break; case Fmt::RGBA_8888: { ptr = varying(); skvm::I32 rgba = load32(ptr); *r = from_unorm(8, extract(rgba, 0, splat(0xff))); *g = from_unorm(8, extract(rgba, 8, splat(0xff))); *b = from_unorm(8, extract(rgba, 16, splat(0xff))); *a = from_unorm(8, extract(rgba, 24, splat(0xff))); } break; } return ptr; }; skvm::F32 r,g,b,a; (void)load(srcFmt, &r,&g,&b,&a); skvm::F32 dr,dg,db,da; skvm::Arg dst = load(dstFmt, &dr,&dg,&db,&da); skvm::F32 invA = sub(splat(1.0f), a); r = mad(dr, invA, r); g = mad(dg, invA, g); b = mad(db, invA, b); a = mad(da, invA, a); switch (dstFmt) { case Fmt::A8: { store8(dst, to_unorm(8, a)); } break; case Fmt::G8: { skvm::F32 _2126 = splat(0.2126f), _7152 = splat(0.7152f), _0722 = splat(0.0722f); store8(dst, to_unorm(8, mad(r, _2126, mad(g, _7152, mul(b, _0722))))); } break; case Fmt::RGBA_8888: { skvm::I32 R = to_unorm(8, r), G = to_unorm(8, g), B = to_unorm(8, b), A = to_unorm(8, a); R = pack(R, G, 8); B = pack(B, A, 8); R = pack(R, B, 16); store32(dst, R); } break; } } SrcoverBuilder_I32_Naive::SrcoverBuilder_I32_Naive() { skvm::Arg src = varying(), dst = varying(); auto load = [&](skvm::Arg ptr, skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) { skvm::I32 rgba = load32(ptr); *r = extract(rgba, 0, splat(0xff)); *g = extract(rgba, 8, splat(0xff)); *b = extract(rgba, 16, splat(0xff)); *a = extract(rgba, 24, splat(0xff)); }; skvm::I32 r,g,b,a; load(src, &r,&g,&b,&a); skvm::I32 dr,dg,db,da; load(dst, &dr,&dg,&db,&da); // (xy + x)/256 is a good approximation of (xy + 127)/255 // // == (d*(255-a) + d)/256 // == (d*(255-a+1) )/256 // == (d*(256-a ) )/256 skvm::I32 invA = sub(splat(256), a); r = add(r, shr(mul(dr, invA), 8)); g = add(g, shr(mul(dg, invA), 8)); b = add(b, shr(mul(db, invA), 8)); a = add(a, shr(mul(da, invA), 8)); r = pack(r, g, 8); b = pack(b, a, 8); r = pack(r, b, 16); store32(dst, r); }