Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit ce9e060

Browse files
Mike KleinSkia Commit-Bot
Mike Klein
authored and
Skia Commit-Bot
committed
finish up 2pt conicals
In the end it turned out best to let the subclasses modify the mask, rather than return how to do it. This gave more flexibility about how to calcualte it. Add negate(x), norm(x,y). Change-Id: Ie17050037f0441becf06897fbe31587d6709009d Reviewed-on: https://skia-review.googlesource.com/c/skia/+/267456 Auto-Submit: Mike Klein <[email protected]> Reviewed-by: Mike Klein <[email protected]> Commit-Queue: Mike Klein <[email protected]>
1 parent 5df08e5 commit ce9e060

11 files changed

+82
-68
lines changed

src/core/SkVM.h

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -427,13 +427,25 @@ namespace skvm {
427427
F32 mad(F32 x, F32 y, F32 z); // x*y+z, often an FMA
428428
F32 sqrt(F32 x);
429429

430+
F32 negate(F32 x) {
431+
return sub(splat(0.0f), x);
432+
}
430433
F32 lerp(F32 lo, F32 hi, F32 t) {
431434
return mad(sub(hi,lo), t, lo);
432435
}
433-
434436
F32 clamp(F32 x, F32 lo, F32 hi) {
435437
return max(lo, min(x, hi));
436438
}
439+
F32 abs(F32 x) {
440+
return bit_cast(bit_and(bit_cast(x),
441+
splat(0x7fffffff)));
442+
}
443+
F32 fract(F32 x) {
444+
return sub(x, floor(x));
445+
}
446+
F32 norm(F32 x, F32 y) {
447+
return sqrt(mad(x,x, mul(y,y)));
448+
}
437449

438450
I32 eq (F32 x, F32 y);
439451
I32 neq(F32 x, F32 y);
@@ -447,15 +459,6 @@ namespace skvm {
447459
I32 round(F32 x);
448460
I32 bit_cast(F32 x) { return {x.id}; }
449461

450-
F32 abs(F32 x) {
451-
return bit_cast(bit_and(bit_cast(x),
452-
splat(0x7fffffff)));
453-
}
454-
455-
F32 fract(F32 x) {
456-
return sub(x, floor(x));
457-
}
458-
459462
// int math, comparisons, etc.
460463
I32 add(I32 x, I32 y);
461464
I32 sub(I32 x, I32 y);

src/shaders/gradients/SkGradientShader.cpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -432,14 +432,8 @@ bool SkGradientShaderBase::onProgram(skvm::Builder* p,
432432

433433
SkShaderBase::ApplyMatrix(p, inv, &x,&y,uniforms);
434434

435-
skvm::I32 keep;
436-
skvm::F32 t;
437-
switch (this->transformT(p,uniforms, x,y, &t)) {
438-
case MaskNeeded::None: keep = p->splat(~0); break;
439-
case MaskNeeded::NaNs: keep = p->eq(t,t); break;
440-
default: return false;
441-
}
442-
t = p->bit_cast(p->bit_and(keep, p->bit_cast(t))); // if (!keep) t = 0
435+
skvm::I32 mask = p->splat(~0);
436+
skvm::F32 t = this->transformT(p,uniforms, x,y, &mask);
443437

444438
// Perhaps unexpectedly, clamping is handled naturally by our search, so we
445439
// don't explicitly clamp t to [0,1]. That clamp would break hard stops
@@ -450,7 +444,7 @@ bool SkGradientShaderBase::onProgram(skvm::Builder* p,
450444
break;
451445

452446
case SkTileMode::kDecal:
453-
keep = p->bit_and(keep, p->eq(t, p->clamp(t, p->splat(0.0f), p->splat(1.0f))));
447+
mask = p->bit_and(mask, p->eq(t, p->clamp(t, p->splat(0.0f), p->splat(1.0f))));
454448
break;
455449

456450
case SkTileMode::kRepeat:
@@ -590,10 +584,10 @@ bool SkGradientShaderBase::onProgram(skvm::Builder* p,
590584
p->premul(r,g,b,*a);
591585
}
592586

593-
*r = p->bit_cast(p->bit_and(keep, p->bit_cast(*r)));
594-
*g = p->bit_cast(p->bit_and(keep, p->bit_cast(*g)));
595-
*b = p->bit_cast(p->bit_and(keep, p->bit_cast(*b)));
596-
*a = p->bit_cast(p->bit_and(keep, p->bit_cast(*a)));
587+
*r = p->bit_cast(p->bit_and(mask, p->bit_cast(*r)));
588+
*g = p->bit_cast(p->bit_and(mask, p->bit_cast(*g)));
589+
*b = p->bit_cast(p->bit_and(mask, p->bit_cast(*b)));
590+
*a = p->bit_cast(p->bit_and(mask, p->bit_cast(*a)));
597591
return true;
598592
}
599593

src/shaders/gradients/SkGradientShaderPriv.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ class SkGradientShaderBase : public SkShaderBase {
8989
virtual void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
9090
SkRasterPipeline* postPipeline) const = 0;
9191

92-
enum class MaskNeeded { None, NaNs, Degens, NotYetImplemented };
93-
virtual MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
94-
skvm::F32 x, skvm::F32 y, skvm::F32* t) const = 0;
92+
// Produce t from (x,y), modifying mask if it should be anything other than ~0.
93+
virtual skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*,
94+
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const = 0;
9595

9696
template <typename T, typename... Args>
9797
static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {

src/shaders/gradients/SkLinearGradient.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,10 @@ void SkLinearGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline*,
7575
// No extra stage needed for linear gradients.
7676
}
7777

78-
SkGradientShaderBase::MaskNeeded
79-
SkLinearGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
80-
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
78+
skvm::F32 SkLinearGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
79+
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const {
8180
// We've baked getting t in x into the matrix, so this is pretty trivial.
82-
*t = x;
83-
return MaskNeeded::None;
81+
return x;
8482
}
8583

8684
SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {

src/shaders/gradients/SkLinearGradient.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ class SkLinearGradient : public SkGradientShaderBase {
2929
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
3030
SkRasterPipeline* postPipeline) const final;
3131

32-
MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
33-
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
34-
32+
skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*,
33+
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final;
3534

3635
private:
3736
SK_FLATTENABLE_HOOKS(SkLinearGradient)

src/shaders/gradients/SkRadialGradient.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,9 @@ void SkRadialGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline* p,
6363
p->append(SkRasterPipeline::xy_to_radius);
6464
}
6565

66-
SkGradientShaderBase::MaskNeeded
67-
SkRadialGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
68-
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
69-
*t = p->sqrt(p->mad(x,x, p->mul(y,y)));
70-
return MaskNeeded::None;
66+
skvm::F32 SkRadialGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
67+
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const {
68+
return p->norm(x,y);
7169
}
7270

7371
/////////////////////////////////////////////////////////////////////

src/shaders/gradients/SkRadialGradient.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ class SkRadialGradient final : public SkGradientShaderBase {
2626
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
2727
SkRasterPipeline* postPipeline) const override;
2828

29-
MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
30-
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
29+
skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*,
30+
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final;
3131

3232
private:
3333
SK_FLATTENABLE_HOOKS(SkRadialGradient)

src/shaders/gradients/SkSweepGradient.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ void SkSweepGradient::appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline
6868
SkMatrix::MakeTrans(fTBias , 0)));
6969
}
7070

71-
SkGradientShaderBase::MaskNeeded
72-
SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
73-
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
71+
72+
skvm::F32 SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
73+
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const {
7474
skvm::F32 xabs = p->abs(x),
7575
yabs = p->abs(y),
7676
slope = p->div(p->min(xabs, yabs),
@@ -95,14 +95,14 @@ SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
9595
phi = p->select(p->lt (x, p->splat(0.0f)), p->sub(p->splat(1/2.0f), phi), phi);
9696
phi = p->select(p->lt (y, p->splat(0.0f)), p->sub(p->splat(1/1.0f), phi), phi);
9797

98-
*t = p->bit_cast(p->bit_and(p->bit_cast(phi), // t = phi if phi != NaN
99-
p->eq(phi, phi)));
98+
skvm::F32 t = p->bit_cast(p->bit_and(p->bit_cast(phi), // t = phi if phi != NaN
99+
p->eq(phi, phi)));
100100

101101
if (fTScale != 1.0f || fTBias != 0.0f) {
102-
*t = p->mad(*t, p->uniformF(uniforms->pushF(fTScale))
103-
, p->uniformF(uniforms->pushF(fTScale*fTBias)));
102+
t = p->mad(t, p->uniformF(uniforms->pushF(fTScale))
103+
, p->uniformF(uniforms->pushF(fTScale*fTBias)));
104104
}
105-
return MaskNeeded::None;
105+
return t;
106106
}
107107

108108
/////////////////////////////////////////////////////////////////////

src/shaders/gradients/SkSweepGradient.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,8 @@ class SkSweepGradient final : public SkGradientShaderBase {
3030
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
3131
SkRasterPipeline* postPipeline) const override;
3232

33-
MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
34-
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
35-
33+
skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*,
34+
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final;
3635
private:
3736
SK_FLATTENABLE_HOOKS(SkSweepGradient)
3837

src/shaders/gradients/SkTwoPointConicalGradient.cpp

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -234,32 +234,55 @@ void SkTwoPointConicalGradient::appendGradientStages(SkArenaAlloc* alloc, SkRast
234234
}
235235
}
236236

237-
SkGradientShaderBase::MaskNeeded
238-
SkTwoPointConicalGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
239-
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
237+
skvm::F32 SkTwoPointConicalGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
238+
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const {
240239
// See https://skia.org/dev/design/conical, and onAppendStages() above.
240+
// There's a lot going on here, and I'm not really sure what's independent
241+
// or disjoint, what can be reordered, simplified, etc. Tweak carefully.
241242

242243
if (fType == Type::kRadial) {
243-
// As if ordinary radial for [0,r2].
244-
skvm::F32 r = p->sqrt(p->mad(x,x, p->mul(y,y)));
245-
246-
// Rescale to [r1,r2]
247244
float denom = 1.0f / (fRadius2 - fRadius1),
248245
scale = SkTMax(fRadius1, fRadius2) * denom,
249246
bias = -fRadius1 * denom;
250-
*t = p->mad(r, p->uniformF(uniforms->pushF(scale))
251-
, p->uniformF(uniforms->pushF(bias )));
252-
return MaskNeeded::None;
247+
return p->mad(p->norm(x,y), p->uniformF(uniforms->pushF(scale))
248+
, p->uniformF(uniforms->pushF(bias )));
253249
}
254250

255251
if (fType == Type::kStrip) {
256252
float r = fRadius1 / this->getCenterX1();
257-
*t = p->add(x, p->sqrt(p->sub(p->splat(r*r),
258-
p->mul(y,y))));
259-
return MaskNeeded::NaNs;
253+
skvm::F32 t = p->add(x, p->sqrt(p->sub(p->splat(r*r),
254+
p->mul(y,y))));
255+
256+
*mask = p->eq(t,t); // t != NaN
257+
return t;
258+
}
259+
260+
const skvm::F32 invR1 = p->uniformF(uniforms->pushF(1 / fFocalData.fR1));
261+
262+
skvm::F32 t;
263+
if (fFocalData.isFocalOnCircle()) {
264+
t = p->mad(p->div(y,x),y,x); // (x^2 + y^2) / x ~~> x + y^2/x ~~> y/x * y + x
265+
} else if (fFocalData.isWellBehaved()) {
266+
t = p->sub(p->norm(x,y), p->mul(x, invR1));
267+
} else {
268+
skvm::F32 k = p->sqrt(p->sub(p->mul(x,x),
269+
p->mul(y,y)));
270+
if (fFocalData.isSwapped() || 1 - fFocalData.fFocalX < 0) {
271+
k = p->negate(k);
272+
}
273+
t = p->sub(k, p->mul(x, invR1));
274+
}
275+
276+
if (!fFocalData.isWellBehaved()) {
277+
// TODO: not sure why we consider t == 0 degenerate
278+
*mask = p->gt(t, p->splat(0.0f)); // t > 0 and implicitly, t != NaN
260279
}
261280

262-
return MaskNeeded::NotYetImplemented;
281+
const skvm::F32 focalX = p->uniformF(uniforms->pushF(fFocalData.fFocalX));
282+
if (1 - fFocalData.fFocalX < 0) { t = p->negate(t); }
283+
if (!fFocalData.isNativelyFocal()) { t = p->add(t, focalX); }
284+
if (fFocalData.isSwapped()) { t = p->sub(p->splat(1.0f), t); }
285+
return t;
263286
}
264287

265288
/////////////////////////////////////////////////////////////////////

src/shaders/gradients/SkTwoPointConicalGradient.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ class SkTwoPointConicalGradient final : public SkGradientShaderBase {
6969
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
7070
SkRasterPipeline* postPipeline) const override;
7171

72-
MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
73-
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
72+
skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*,
73+
skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final;
7474

7575
private:
7676
SK_FLATTENABLE_HOOKS(SkTwoPointConicalGradient)

0 commit comments

Comments
 (0)