way more p-> inference
We can infer the builder on any method that's got at least one I32/F32 argument. That's basically everything but splat, uniform??, and load??. This will let us write things like sqrt(x*x + y*y) instead of p->sqrt(x*x + y*y) Previously we had to inherit from skvm::Builder for that... I think we can remove all that inheritance once I fill all this out. To make the impl. terser, give I32/F32 an operator-> for their Builder. Open question about whether to add operator>>? operator<< is unambiguous, but operator>> on I32 is probably just going to be more confusing than sticking with shr and sra. Change-Id: Id7f1334f87e2354c8733a93d510569df38ae861e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/280318 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
c18dad25e4
commit
45c7e70b20
@ -1202,8 +1202,8 @@ namespace skvm {
|
||||
// Map min channel to 0, max channel to s, and scale the middle proportionally.
|
||||
auto scale = [&](auto c) {
|
||||
// TODO: better to divide and check for non-finite result?
|
||||
return p->select(sat == 0.0f, 0.0f
|
||||
, ((c - mn) * s) / sat);
|
||||
return select(sat == 0.0f, 0.0f
|
||||
, ((c - mn) * s) / sat);
|
||||
};
|
||||
*r = scale(*r);
|
||||
*g = scale(*g);
|
||||
@ -1212,9 +1212,9 @@ namespace skvm {
|
||||
|
||||
static void set_lum(skvm::Builder* p, skvm::F32* r, skvm::F32* g, skvm::F32* b, skvm::F32 lu) {
|
||||
auto diff = lu - luminance(p, *r, *g, *b);
|
||||
*r = p->add(*r, diff);
|
||||
*g = p->add(*g, diff);
|
||||
*b = p->add(*b, diff);
|
||||
*r += diff;
|
||||
*g += diff;
|
||||
*b += diff;
|
||||
}
|
||||
|
||||
static void clip_color(skvm::Builder* p,
|
||||
@ -1224,10 +1224,10 @@ namespace skvm {
|
||||
lu = luminance(p, *r, *g, *b);
|
||||
|
||||
auto clip = [&](auto c) {
|
||||
c = p->select(mn >= 0, c
|
||||
, lu + ((c-lu)*( lu)) / (lu-mn));
|
||||
c = p->select(mx > a, lu + ((c-lu)*(a-lu)) / (mx-lu)
|
||||
, c);
|
||||
c = select(mn >= 0, c
|
||||
, lu + ((c-lu)*( lu)) / (lu-mn));
|
||||
c = select(mx > a, lu + ((c-lu)*(a-lu)) / (mx-lu)
|
||||
, c);
|
||||
// Sometimes without this we may dip just a little negative.
|
||||
return max(c, 0.0f);
|
||||
};
|
||||
|
191
src/core/SkVM.h
191
src/core/SkVM.h
@ -349,12 +349,14 @@ namespace skvm {
|
||||
Builder* builder = nullptr;
|
||||
Val id = NA;
|
||||
explicit operator bool() const { return id != NA; }
|
||||
Builder* operator->() const { return builder; }
|
||||
};
|
||||
|
||||
struct F32 {
|
||||
Builder* builder = nullptr;
|
||||
Val id = NA;
|
||||
explicit operator bool() const { return id != NA; }
|
||||
Builder* operator->() const { return builder; }
|
||||
};
|
||||
|
||||
// Some operations make sense with immediate arguments,
|
||||
@ -787,75 +789,75 @@ namespace skvm {
|
||||
// TODO: control flow
|
||||
// TODO: 64-bit values?
|
||||
|
||||
static inline I32 operator+(I32 x, I32a y) { return x.builder->add(x,y); }
|
||||
static inline I32 operator+(int x, I32 y) { return y.builder->add(x,y); }
|
||||
static inline I32 operator+(I32 x, I32a y) { return x->add(x,y); }
|
||||
static inline I32 operator+(int x, I32 y) { return y->add(x,y); }
|
||||
|
||||
static inline I32 operator-(I32 x, I32a y) { return x.builder->sub(x,y); }
|
||||
static inline I32 operator-(int x, I32 y) { return y.builder->sub(x,y); }
|
||||
static inline I32 operator-(I32 x, I32a y) { return x->sub(x,y); }
|
||||
static inline I32 operator-(int x, I32 y) { return y->sub(x,y); }
|
||||
|
||||
static inline I32 operator*(I32 x, I32a y) { return x.builder->mul(x,y); }
|
||||
static inline I32 operator*(int x, I32 y) { return y.builder->mul(x,y); }
|
||||
static inline I32 operator*(I32 x, I32a y) { return x->mul(x,y); }
|
||||
static inline I32 operator*(int x, I32 y) { return y->mul(x,y); }
|
||||
|
||||
static inline I32 min(I32 x, I32a y) { return x.builder->min(x,y); }
|
||||
static inline I32 min(int x, I32 y) { return y.builder->min(x,y); }
|
||||
static inline I32 min(I32 x, I32a y) { return x->min(x,y); }
|
||||
static inline I32 min(int x, I32 y) { return y->min(x,y); }
|
||||
|
||||
static inline I32 max(I32 x, I32a y) { return x.builder->max(x,y); }
|
||||
static inline I32 max(int x, I32 y) { return y.builder->max(x,y); }
|
||||
static inline I32 max(I32 x, I32a y) { return x->max(x,y); }
|
||||
static inline I32 max(int x, I32 y) { return y->max(x,y); }
|
||||
|
||||
static inline I32 operator==(I32 x, I32a y) { return x.builder->eq(x,y); }
|
||||
static inline I32 operator==(int x, I32 y) { return y.builder->eq(x,y); }
|
||||
static inline I32 operator==(I32 x, I32a y) { return x->eq(x,y); }
|
||||
static inline I32 operator==(int x, I32 y) { return y->eq(x,y); }
|
||||
|
||||
static inline I32 operator!=(I32 x, I32a y) { return x.builder->neq(x,y); }
|
||||
static inline I32 operator!=(int x, I32 y) { return y.builder->neq(x,y); }
|
||||
static inline I32 operator!=(I32 x, I32a y) { return x->neq(x,y); }
|
||||
static inline I32 operator!=(int x, I32 y) { return y->neq(x,y); }
|
||||
|
||||
static inline I32 operator< (I32 x, I32a y) { return x.builder->lt(x,y); }
|
||||
static inline I32 operator< (int x, I32 y) { return y.builder->lt(x,y); }
|
||||
static inline I32 operator< (I32 x, I32a y) { return x->lt(x,y); }
|
||||
static inline I32 operator< (int x, I32 y) { return y->lt(x,y); }
|
||||
|
||||
static inline I32 operator<=(I32 x, I32a y) { return x.builder->lte(x,y); }
|
||||
static inline I32 operator<=(int x, I32 y) { return y.builder->lte(x,y); }
|
||||
static inline I32 operator<=(I32 x, I32a y) { return x->lte(x,y); }
|
||||
static inline I32 operator<=(int x, I32 y) { return y->lte(x,y); }
|
||||
|
||||
static inline I32 operator> (I32 x, I32a y) { return x.builder->gt(x,y); }
|
||||
static inline I32 operator> (int x, I32 y) { return y.builder->gt(x,y); }
|
||||
static inline I32 operator> (I32 x, I32a y) { return x->gt(x,y); }
|
||||
static inline I32 operator> (int x, I32 y) { return y->gt(x,y); }
|
||||
|
||||
static inline I32 operator>=(I32 x, I32a y) { return x.builder->gte(x,y); }
|
||||
static inline I32 operator>=(int x, I32 y) { return y.builder->gte(x,y); }
|
||||
static inline I32 operator>=(I32 x, I32a y) { return x->gte(x,y); }
|
||||
static inline I32 operator>=(int x, I32 y) { return y->gte(x,y); }
|
||||
|
||||
|
||||
static inline F32 operator+(F32 x, F32a y) { return x.builder->add(x,y); }
|
||||
static inline F32 operator+(float x, F32 y) { return y.builder->add(x,y); }
|
||||
static inline F32 operator+(F32 x, F32a y) { return x->add(x,y); }
|
||||
static inline F32 operator+(float x, F32 y) { return y->add(x,y); }
|
||||
|
||||
static inline F32 operator-(F32 x, F32a y) { return x.builder->sub(x,y); }
|
||||
static inline F32 operator-(float x, F32 y) { return y.builder->sub(x,y); }
|
||||
static inline F32 operator-(F32 x, F32a y) { return x->sub(x,y); }
|
||||
static inline F32 operator-(float x, F32 y) { return y->sub(x,y); }
|
||||
|
||||
static inline F32 operator*(F32 x, F32a y) { return x.builder->mul(x,y); }
|
||||
static inline F32 operator*(float x, F32 y) { return y.builder->mul(x,y); }
|
||||
static inline F32 operator*(F32 x, F32a y) { return x->mul(x,y); }
|
||||
static inline F32 operator*(float x, F32 y) { return y->mul(x,y); }
|
||||
|
||||
static inline F32 operator/(F32 x, F32 y) { return x.builder->div(x,y); }
|
||||
static inline F32 operator/(float x, F32 y) { return y.builder->div(x,y); }
|
||||
static inline F32 operator/(F32 x, F32 y) { return x->div(x,y); }
|
||||
static inline F32 operator/(float x, F32 y) { return y->div(x,y); }
|
||||
|
||||
static inline F32 min(F32 x, F32a y) { return x.builder->min(x,y); }
|
||||
static inline F32 min(float x, F32 y) { return y.builder->min(x,y); }
|
||||
static inline F32 min(F32 x, F32a y) { return x->min(x,y); }
|
||||
static inline F32 min(float x, F32 y) { return y->min(x,y); }
|
||||
|
||||
static inline F32 max(F32 x, F32a y) { return x.builder->max(x,y); }
|
||||
static inline F32 max(float x, F32 y) { return y.builder->max(x,y); }
|
||||
static inline F32 max(F32 x, F32a y) { return x->max(x,y); }
|
||||
static inline F32 max(float x, F32 y) { return y->max(x,y); }
|
||||
|
||||
static inline I32 operator==(F32 x, F32a y) { return x.builder->eq(x,y); }
|
||||
static inline I32 operator==(float x, F32 y) { return y.builder->eq(x,y); }
|
||||
static inline I32 operator==(F32 x, F32a y) { return x->eq(x,y); }
|
||||
static inline I32 operator==(float x, F32 y) { return y->eq(x,y); }
|
||||
|
||||
static inline I32 operator!=(F32 x, F32a y) { return x.builder->neq(x,y); }
|
||||
static inline I32 operator!=(float x, F32 y) { return y.builder->neq(x,y); }
|
||||
static inline I32 operator!=(F32 x, F32a y) { return x->neq(x,y); }
|
||||
static inline I32 operator!=(float x, F32 y) { return y->neq(x,y); }
|
||||
|
||||
static inline I32 operator< (F32 x, F32a y) { return x.builder->lt(x,y); }
|
||||
static inline I32 operator< (float x, F32 y) { return y.builder->lt(x,y); }
|
||||
static inline I32 operator< (F32 x, F32a y) { return x->lt(x,y); }
|
||||
static inline I32 operator< (float x, F32 y) { return y->lt(x,y); }
|
||||
|
||||
static inline I32 operator<=(F32 x, F32a y) { return x.builder->lte(x,y); }
|
||||
static inline I32 operator<=(float x, F32 y) { return y.builder->lte(x,y); }
|
||||
static inline I32 operator<=(F32 x, F32a y) { return x->lte(x,y); }
|
||||
static inline I32 operator<=(float x, F32 y) { return y->lte(x,y); }
|
||||
|
||||
static inline I32 operator> (F32 x, F32a y) { return x.builder->gt(x,y); }
|
||||
static inline I32 operator> (float x, F32 y) { return y.builder->gt(x,y); }
|
||||
static inline I32 operator> (F32 x, F32a y) { return x->gt(x,y); }
|
||||
static inline I32 operator> (float x, F32 y) { return y->gt(x,y); }
|
||||
|
||||
static inline I32 operator>=(F32 x, F32a y) { return x.builder->gte(x,y); }
|
||||
static inline I32 operator>=(float x, F32 y) { return y.builder->gte(x,y); }
|
||||
static inline I32 operator>=(F32 x, F32a y) { return x->gte(x,y); }
|
||||
static inline I32 operator>=(float x, F32 y) { return y->gte(x,y); }
|
||||
|
||||
|
||||
static inline I32& operator+=(I32& x, I32a y) { return (x = x + y); }
|
||||
@ -869,6 +871,103 @@ namespace skvm {
|
||||
static inline I32 operator-(I32 x) { return 0-x; }
|
||||
static inline F32 operator-(F32 x) { return 0-x; }
|
||||
|
||||
static inline void assert_true(I32 cond, I32 debug) { cond->assert_true(cond,debug); }
|
||||
static inline void assert_true(I32 cond, F32 debug) { cond->assert_true(cond,debug); }
|
||||
static inline void assert_true(I32 cond) { cond->assert_true(cond); }
|
||||
|
||||
static inline void store8 (Arg ptr, I32 val) { val->store8 (ptr, val); }
|
||||
static inline void store16(Arg ptr, I32 val) { val->store16(ptr, val); }
|
||||
static inline void store32(Arg ptr, I32 val) { val->store32(ptr, val); }
|
||||
static inline void storeF (Arg ptr, F32 val) { val->storeF (ptr, val); }
|
||||
|
||||
static inline I32 gather8 (Arg ptr, int off, I32 ix) { return ix->gather8 (ptr, off, ix); }
|
||||
static inline I32 gather16(Arg ptr, int off, I32 ix) { return ix->gather16(ptr, off, ix); }
|
||||
static inline I32 gather32(Arg ptr, int off, I32 ix) { return ix->gather32(ptr, off, ix); }
|
||||
static inline F32 gatherF (Arg ptr, int off, I32 ix) { return ix->gatherF (ptr, off, ix); }
|
||||
|
||||
static inline I32 gather8 (Builder::Uniform u, I32 ix) { return ix->gather8 (u, ix); }
|
||||
static inline I32 gather16(Builder::Uniform u, I32 ix) { return ix->gather16(u, ix); }
|
||||
static inline I32 gather32(Builder::Uniform u, I32 ix) { return ix->gather32(u, ix); }
|
||||
static inline F32 gatherF (Builder::Uniform u, I32 ix) { return ix->gatherF (u, ix); }
|
||||
|
||||
static inline F32 sqrt(F32 x) { return x-> sqrt(x); }
|
||||
static inline F32 approx_log2(F32 x) { return x->approx_log2(x); }
|
||||
static inline F32 approx_pow2(F32 x) { return x->approx_pow2(x); }
|
||||
static inline F32 approx_log (F32 x) { return x->approx_log (x); }
|
||||
static inline F32 approx_exp (F32 x) { return x->approx_exp (x); }
|
||||
|
||||
static inline F32 approx_powf(F32 base, F32a exp) { return base->approx_powf(base, exp); }
|
||||
static inline F32 approx_powf(float base, F32 exp) { return exp->approx_powf(base, exp); }
|
||||
|
||||
static inline F32 clamp01(F32 x) { return x->clamp01(x); }
|
||||
static inline F32 abs(F32 x) { return x-> abs(x); }
|
||||
static inline F32 fract(F32 x) { return x-> fract(x); }
|
||||
static inline F32 floor(F32 x) { return x-> floor(x); }
|
||||
|
||||
static inline I32 trunc(F32 x) { return x-> trunc(x); }
|
||||
static inline I32 round(F32 x) { return x-> round(x); }
|
||||
static inline I32 bit_cast(F32 x) { return x->bit_cast(x); }
|
||||
static inline F32 bit_cast(I32 x) { return x->bit_cast(x); }
|
||||
static inline F32 to_f32(I32 x) { return x-> to_f32(x); }
|
||||
|
||||
static inline F32 lerp(F32 lo, F32a hi, F32a t) { return lo->lerp(lo,hi,t); }
|
||||
static inline F32 lerp(float lo, F32 hi, F32a t) { return hi->lerp(lo,hi,t); }
|
||||
static inline F32 lerp(float lo, float hi, F32 t) { return t->lerp(lo,hi,t); }
|
||||
|
||||
static inline F32 clamp(F32 x, F32a lo, F32a hi) { return x->clamp(x,lo,hi); }
|
||||
static inline F32 clamp(float x, F32 lo, F32a hi) { return lo->clamp(x,lo,hi); }
|
||||
static inline F32 clamp(float x, float lo, F32 hi) { return hi->clamp(x,lo,hi); }
|
||||
|
||||
static inline F32 norm(F32 x, F32a y) { return x->norm(x,y); }
|
||||
static inline F32 norm(float x, F32 y) { return y->norm(x,y); }
|
||||
|
||||
static inline I32 operator<<(I32 x, int bits) { return x->shl(x, bits); }
|
||||
static inline I32 shl(I32 x, int bits) { return x->shl(x, bits); }
|
||||
static inline I32 shr(I32 x, int bits) { return x->shr(x, bits); }
|
||||
static inline I32 sra(I32 x, int bits) { return x->sra(x, bits); }
|
||||
|
||||
static inline I32 operator&(I32 x, I32a y) { return x->bit_and(x,y); }
|
||||
static inline I32 operator&(int x, I32 y) { return y->bit_and(x,y); }
|
||||
|
||||
static inline I32 operator|(I32 x, I32a y) { return x->bit_or (x,y); }
|
||||
static inline I32 operator|(int x, I32 y) { return y->bit_or (x,y); }
|
||||
|
||||
static inline I32 operator^(I32 x, I32a y) { return x->bit_xor(x,y); }
|
||||
static inline I32 operator^(int x, I32 y) { return y->bit_xor(x,y); }
|
||||
|
||||
static inline I32& operator&=(I32& x, I32a y) { return (x = x & y); }
|
||||
static inline I32& operator|=(I32& x, I32a y) { return (x = x | y); }
|
||||
static inline I32& operator^=(I32& x, I32a y) { return (x = x ^ y); }
|
||||
|
||||
static inline I32 select(I32 cond, I32a t, I32a f) { return cond->select(cond,t,f); }
|
||||
static inline F32 select(I32 cond, F32a t, F32a f) { return cond->select(cond,t,f); }
|
||||
|
||||
static inline I32 bytes(I32 x, int control) { return x->bytes(x,control); }
|
||||
|
||||
static inline I32 extract(I32 x, int bits, I32a z) { return x->extract(x,bits,z); }
|
||||
static inline I32 extract(int x, int bits, I32 z) { return z->extract(x,bits,z); }
|
||||
static inline I32 pack (I32 x, I32a y, int bits) { return x->pack (x,y,bits); }
|
||||
static inline I32 pack (int x, I32 y, int bits) { return y->pack (x,y,bits); }
|
||||
|
||||
static inline F32 from_unorm(int bits, I32 x) { return x->from_unorm(bits,x); }
|
||||
static inline I32 to_unorm(int bits, F32 x) { return x-> to_unorm(bits,x); }
|
||||
|
||||
static inline Color unpack_1010102(I32 rgba) { return rgba->unpack_1010102(rgba); }
|
||||
static inline Color unpack_8888 (I32 rgba) { return rgba->unpack_8888 (rgba); }
|
||||
static inline Color unpack_565 (I32 bgr ) { return bgr ->unpack_565 (bgr ); }
|
||||
|
||||
static inline void premul(F32* r, F32* g, F32* b, F32 a) { a->premul(r,g,b,a); }
|
||||
static inline void unpremul(F32* r, F32* g, F32* b, F32 a) { a->premul(r,g,b,a); }
|
||||
|
||||
static inline Color premul(Color c) { premul(&c.r, &c.g, &c.b, c.a); return c; }
|
||||
static inline Color unpremul(Color c) { unpremul(&c.r, &c.g, &c.b, c.a); return c; }
|
||||
|
||||
static inline Color lerp(Color lo, Color hi, F32 t) { return t->lerp(lo,hi,t); }
|
||||
|
||||
static inline Color blend(SkBlendMode m, Color s, Color d) { return s.a->blend(m,s,d); }
|
||||
|
||||
static inline HSLA to_hsla(Color c) { return c.a->to_hsla(c); }
|
||||
static inline Color to_rgba(HSLA c) { return c.a->to_rgba(c); }
|
||||
}
|
||||
|
||||
#endif//SkVM_DEFINED
|
||||
|
@ -117,11 +117,11 @@ namespace {
|
||||
const SkShaderBase* sb = as_SB(shader);
|
||||
skvm::Builder p;
|
||||
|
||||
skvm::I32 dx = p.sub(p.uniform32(uniforms->base, offsetof(BlitterUniforms, right)),
|
||||
p.index()),
|
||||
skvm::I32 dx = p.uniform32(uniforms->base, offsetof(BlitterUniforms, right))
|
||||
- p.index(),
|
||||
dy = p.uniform32(uniforms->base, offsetof(BlitterUniforms, y));
|
||||
skvm::F32 x = p.add(p.to_f32(dx), 0.5f),
|
||||
y = p.add(p.to_f32(dy), 0.5f);
|
||||
skvm::F32 x = p.to_f32(dx) + 0.5f,
|
||||
y = p.to_f32(dy) + 0.5f;
|
||||
|
||||
skvm::Color paint = {
|
||||
p.uniformF(uniforms->base, offsetof(BlitterUniforms, paint.fR)),
|
||||
@ -196,11 +196,11 @@ namespace {
|
||||
// - MaskLCD16: 565 coverage varying
|
||||
// - UniformA8: 8-bit coverage uniform
|
||||
|
||||
skvm::I32 dx = sub(uniform32(uniforms->base, offsetof(BlitterUniforms, right)),
|
||||
index()),
|
||||
skvm::I32 dx = uniform32(uniforms->base, offsetof(BlitterUniforms, right))
|
||||
- index(),
|
||||
dy = uniform32(uniforms->base, offsetof(BlitterUniforms, y));
|
||||
skvm::F32 x = add(to_f32(dx), 0.5f),
|
||||
y = add(to_f32(dy), 0.5f);
|
||||
skvm::F32 x = to_f32(dx) + 0.5f,
|
||||
y = to_f32(dy) + 0.5f;
|
||||
|
||||
skvm::Color paint = {
|
||||
uniformF(uniforms->base, offsetof(BlitterUniforms, paint.fR)),
|
||||
@ -270,8 +270,8 @@ namespace {
|
||||
case Coverage::MaskLCD16:
|
||||
SkASSERT(dst_loaded);
|
||||
*cov = unpack_565(load16(varying<uint16_t>()));
|
||||
cov->a = select(lt(src.a, dst.a), min(cov->r, min(cov->g, cov->b))
|
||||
, max(cov->r, max(cov->g, cov->b)));
|
||||
cov->a = select(src.a < dst.a, min(cov->r, min(cov->g, cov->b))
|
||||
, max(cov->r, max(cov->g, cov->b)));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -281,10 +281,10 @@ namespace {
|
||||
params.quality, params.dst,
|
||||
uniforms, alloc);
|
||||
SkAssertResult(clip);
|
||||
cov->r = mul(cov->r, clip.a); // We use the alpha channel of clip for all four.
|
||||
cov->g = mul(cov->g, clip.a);
|
||||
cov->b = mul(cov->b, clip.a);
|
||||
cov->a = mul(cov->a, clip.a);
|
||||
cov->r *= clip.a; // We use the alpha channel of clip for all four.
|
||||
cov->g *= clip.a;
|
||||
cov->b *= clip.a;
|
||||
cov->a *= clip.a;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -299,10 +299,10 @@ namespace {
|
||||
params.coverage == Coverage::MaskLCD16)) {
|
||||
skvm::Color cov;
|
||||
if (load_coverage(&cov)) {
|
||||
src.r = mul(src.r, cov.r);
|
||||
src.g = mul(src.g, cov.g);
|
||||
src.b = mul(src.b, cov.b);
|
||||
src.a = mul(src.a, cov.a);
|
||||
src.r *= cov.r;
|
||||
src.g *= cov.g;
|
||||
src.b *= cov.b;
|
||||
src.a *= cov.a;
|
||||
}
|
||||
lerp_coverage_post_blend = false;
|
||||
}
|
||||
@ -337,23 +337,23 @@ namespace {
|
||||
if (params.dst.isOpaque()) {
|
||||
dst.a = splat(1.0f);
|
||||
} else if (params.dst.alphaType() == kUnpremul_SkAlphaType) {
|
||||
premul(&dst.r, &dst.g, &dst.b, dst.a);
|
||||
dst = premul(dst);
|
||||
}
|
||||
|
||||
src = this->blend(params.blendMode, src, dst);
|
||||
|
||||
// Lerp with coverage post-blend if needed.
|
||||
if (skvm::Color cov; lerp_coverage_post_blend && load_coverage(&cov)) {
|
||||
src.r = mad(sub(src.r, dst.r), cov.r, dst.r);
|
||||
src.g = mad(sub(src.g, dst.g), cov.g, dst.g);
|
||||
src.b = mad(sub(src.b, dst.b), cov.b, dst.b);
|
||||
src.a = mad(sub(src.a, dst.a), cov.a, dst.a);
|
||||
src.r = lerp(dst.r, src.r, cov.r);
|
||||
src.g = lerp(dst.g, src.g, cov.g);
|
||||
src.b = lerp(dst.b, src.b, cov.b);
|
||||
src.a = lerp(dst.a, src.a, cov.a);
|
||||
}
|
||||
|
||||
if (params.dst.isOpaque()) {
|
||||
src.a = splat(1.0f);
|
||||
} else if (params.dst.alphaType() == kUnpremul_SkAlphaType) {
|
||||
unpremul(&src.r, &src.g, &src.b, src.a);
|
||||
src = unpremul(src);
|
||||
}
|
||||
|
||||
// Clamp to fit destination color format if needed.
|
||||
@ -363,10 +363,10 @@ namespace {
|
||||
// We allow one ulp error above 1.0f, and about that much (~1.2e-7) below 0.
|
||||
skvm::F32 lo = bit_cast(splat(0xb400'0000)),
|
||||
hi = bit_cast(splat(0x3f80'0001));
|
||||
assert_true(eq(src.r, clamp(src.r, lo, hi)), src.r);
|
||||
assert_true(eq(src.g, clamp(src.g, lo, hi)), src.g);
|
||||
assert_true(eq(src.b, clamp(src.b, lo, hi)), src.b);
|
||||
assert_true(eq(src.a, clamp(src.a, lo, hi)), src.a);
|
||||
assert_true(src.r == clamp(src.r, lo, hi), src.r);
|
||||
assert_true(src.g == clamp(src.g, lo, hi), src.g);
|
||||
assert_true(src.b == clamp(src.b, lo, hi), src.b);
|
||||
assert_true(src.a == clamp(src.a, lo, hi), src.a);
|
||||
} else if (SkColorTypeIsNormalized(params.dst.colorType())) {
|
||||
src.r = clamp01(src.r);
|
||||
src.g = clamp01(src.g);
|
||||
@ -469,17 +469,17 @@ namespace {
|
||||
|
||||
// See SkRasterPipeline dither stage.
|
||||
// This is 8x8 ordered dithering. From here we'll only need dx and dx^dy.
|
||||
skvm::I32 X = p->trunc(p->sub(x, 0.5f)),
|
||||
Y = p->bit_xor(X, p->trunc(p->sub(y, 0.5f)));
|
||||
skvm::I32 X = trunc(x - 0.5f),
|
||||
Y = X ^ trunc(y - 0.5f);
|
||||
|
||||
// If X's low bits are abc and Y's def, M is fcebda,
|
||||
// 6 bits producing all values [0,63] shuffled over an 8x8 grid.
|
||||
skvm::I32 M = p->bit_or(p->shl(p->bit_and(Y, 1), 5),
|
||||
p->bit_or(p->shl(p->bit_and(X, 1), 4),
|
||||
p->bit_or(p->shl(p->bit_and(Y, 2), 2),
|
||||
p->bit_or(p->shl(p->bit_and(X, 2), 1),
|
||||
p->bit_or(p->shr(p->bit_and(Y, 4), 1),
|
||||
p->shr(p->bit_and(X, 4), 2))))));
|
||||
skvm::I32 M = shl(Y & 1, 5)
|
||||
| shl(X & 1, 4)
|
||||
| shl(Y & 2, 2)
|
||||
| shl(X & 2, 1)
|
||||
| shr(Y & 4, 1)
|
||||
| shr(X & 4, 2);
|
||||
|
||||
// Scale to [0,1) by /64, then to (-0.5,0.5) using 63/128 (~0.492) as 0.5-ε,
|
||||
// and finally scale all that by rate. We keep dither strength strictly
|
||||
@ -489,15 +489,14 @@ namespace {
|
||||
// we can bake it in without hurting the cache hit rate.
|
||||
float scale = rate * ( 2/128.0f),
|
||||
bias = rate * (-63/128.0f);
|
||||
skvm::F32 dither = p->mad(p->to_f32(M), scale, bias);
|
||||
skvm::F32 dither = to_f32(M) * scale + bias;
|
||||
c.r += dither;
|
||||
c.g += dither;
|
||||
c.b += dither;
|
||||
|
||||
c.r = p->add(c.r, dither);
|
||||
c.g = p->add(c.g, dither);
|
||||
c.b = p->add(c.b, dither);
|
||||
|
||||
c.r = p->clamp(c.r, 0.0f, c.a);
|
||||
c.g = p->clamp(c.g, 0.0f, c.a);
|
||||
c.b = p->clamp(c.b, 0.0f, c.a);
|
||||
c.r = clamp(c.r, 0.0f, c.a);
|
||||
c.g = clamp(c.g, 0.0f, c.a);
|
||||
c.b = clamp(c.b, 0.0f, c.a);
|
||||
return c;
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user