start on 2pt conical gradients
Couple ways to do this masking, but since we basically need the same for decal, seems easiest to send it up to the common code and handle it all together. Change-Id: Idf806d7feab12a9caf339febd30dd3a2432ec038 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/267244 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
dcc8c5431b
commit
caf5ee4451
@ -431,20 +431,32 @@ bool SkGradientShaderBase::onProgram(skvm::Builder* p,
|
||||
inv.normalizePerspective();
|
||||
|
||||
SkShaderBase::ApplyMatrix(p, inv, &x,&y,uniforms);
|
||||
skvm::F32 t;
|
||||
if (!this->transformT(p,uniforms, x,y, &t)) { // Hook into subclasses for linear, radial, etc.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Most tiling happens here, with kDecal doing its work at the end.
|
||||
// Perhaps unexpectedly, all clamping is handled by our search, so
|
||||
// we don't explicitly clamp t to [0,1]. That clamp would break
|
||||
// hard stops right at 0 or 1 boundaries in kClamp mode.
|
||||
// (kRepeat and kMirror always produce values in [0,1].)
|
||||
skvm::I32 keep;
|
||||
skvm::F32 t;
|
||||
switch (this->transformT(p,uniforms, x,y, &t)) {
|
||||
case MaskNeeded::None: keep = p->splat(~0); break;
|
||||
case MaskNeeded::NaNs: keep = p->eq(t,t); break;
|
||||
default: return false;
|
||||
}
|
||||
t = p->bit_cast(p->bit_and(keep, p->bit_cast(t))); // if (!keep) t = 0
|
||||
|
||||
// Perhaps unexpectedly, clamping is handled naturally by our search, so we
|
||||
// don't explicitly clamp t to [0,1]. That clamp would break hard stops
|
||||
// right at 0 or 1 boundaries in kClamp mode. (kRepeat and kMirror always
|
||||
// produce values in [0,1].)
|
||||
switch(fTileMode) {
|
||||
case SkTileMode::kDecal: break;
|
||||
case SkTileMode::kClamp: break;
|
||||
case SkTileMode::kRepeat: t = p->sub(t, p->floor(t)); break;
|
||||
case SkTileMode::kClamp:
|
||||
break;
|
||||
|
||||
case SkTileMode::kDecal:
|
||||
keep = p->bit_and(keep, p->eq(t, p->clamp(t, p->splat(0.0f), p->splat(1.0f))));
|
||||
break;
|
||||
|
||||
case SkTileMode::kRepeat:
|
||||
t = p->sub(t, p->floor(t));
|
||||
break;
|
||||
|
||||
case SkTileMode::kMirror: {
|
||||
// t = | (t-1) - 2*(floor( (t-1)*0.5 )) - 1 |
|
||||
// {-A-} {--------B-------}
|
||||
@ -578,15 +590,10 @@ bool SkGradientShaderBase::onProgram(skvm::Builder* p,
|
||||
p->premul(r,g,b,*a);
|
||||
}
|
||||
|
||||
// Mask away any pixels that we tried to sample outside the bounds in kDecal.
|
||||
if (fTileMode == SkTileMode::kDecal) {
|
||||
skvm::I32 in_bounds = p->eq(t, p->clamp(t, p->splat(0.0f), p->splat(1.0f)));
|
||||
*r = p->bit_cast(p->bit_and(in_bounds, p->bit_cast(*r)));
|
||||
*g = p->bit_cast(p->bit_and(in_bounds, p->bit_cast(*g)));
|
||||
*b = p->bit_cast(p->bit_and(in_bounds, p->bit_cast(*b)));
|
||||
*a = p->bit_cast(p->bit_and(in_bounds, p->bit_cast(*a)));
|
||||
}
|
||||
|
||||
*r = p->bit_cast(p->bit_and(keep, p->bit_cast(*r)));
|
||||
*g = p->bit_cast(p->bit_and(keep, p->bit_cast(*g)));
|
||||
*b = p->bit_cast(p->bit_and(keep, p->bit_cast(*b)));
|
||||
*a = p->bit_cast(p->bit_and(keep, p->bit_cast(*a)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -89,8 +89,9 @@ protected:
|
||||
virtual void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
||||
SkRasterPipeline* postPipeline) const = 0;
|
||||
|
||||
virtual bool transformT(skvm::Builder*, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const { return false; }
|
||||
enum class MaskNeeded { None, NaNs, Degens, NotYetImplemented };
|
||||
virtual MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const = 0;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
|
||||
|
@ -75,11 +75,12 @@ void SkLinearGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline*,
|
||||
// No extra stage needed for linear gradients.
|
||||
}
|
||||
|
||||
bool SkLinearGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
|
||||
SkGradientShaderBase::MaskNeeded
|
||||
SkLinearGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
|
||||
// We've baked getting t in x into the matrix, so this is pretty trivial.
|
||||
*t = x;
|
||||
return true;
|
||||
return MaskNeeded::None;
|
||||
}
|
||||
|
||||
SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {
|
||||
|
@ -29,8 +29,8 @@ protected:
|
||||
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
||||
SkRasterPipeline* postPipeline) const final;
|
||||
|
||||
bool transformT(skvm::Builder*, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
||||
MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
||||
|
||||
|
||||
private:
|
||||
|
@ -63,10 +63,11 @@ void SkRadialGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline* p,
|
||||
p->append(SkRasterPipeline::xy_to_radius);
|
||||
}
|
||||
|
||||
bool SkRadialGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
|
||||
SkGradientShaderBase::MaskNeeded
|
||||
SkRadialGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
|
||||
*t = p->sqrt(p->mad(x,x, p->mul(y,y)));
|
||||
return true;
|
||||
return MaskNeeded::None;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
@ -26,8 +26,8 @@ protected:
|
||||
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
||||
SkRasterPipeline* postPipeline) const override;
|
||||
|
||||
bool transformT(skvm::Builder*, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
||||
MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
||||
|
||||
private:
|
||||
SK_FLATTENABLE_HOOKS(SkRadialGradient)
|
||||
|
@ -68,8 +68,9 @@ void SkSweepGradient::appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline
|
||||
SkMatrix::MakeTrans(fTBias , 0)));
|
||||
}
|
||||
|
||||
bool SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
|
||||
SkGradientShaderBase::MaskNeeded
|
||||
SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
|
||||
skvm::F32 xabs = p->abs(x),
|
||||
yabs = p->abs(y),
|
||||
slope = p->div(p->min(xabs, yabs),
|
||||
@ -101,7 +102,7 @@ bool SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
|
||||
*t = p->mad(*t, p->uniformF(uniforms->pushF(fTScale))
|
||||
, p->uniformF(uniforms->pushF(fTScale*fTBias)));
|
||||
}
|
||||
return true;
|
||||
return MaskNeeded::None;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
@ -29,8 +29,9 @@ protected:
|
||||
|
||||
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
||||
SkRasterPipeline* postPipeline) const override;
|
||||
bool transformT(skvm::Builder*, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
||||
|
||||
MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
||||
|
||||
private:
|
||||
SK_FLATTENABLE_HOOKS(SkSweepGradient)
|
||||
|
@ -234,6 +234,34 @@ void SkTwoPointConicalGradient::appendGradientStages(SkArenaAlloc* alloc, SkRast
|
||||
}
|
||||
}
|
||||
|
||||
SkGradientShaderBase::MaskNeeded
|
||||
SkTwoPointConicalGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
|
||||
// See https://skia.org/dev/design/conical, and onAppendStages() above.
|
||||
|
||||
if (fType == Type::kRadial) {
|
||||
// As if ordinary radial for [0,r2].
|
||||
skvm::F32 r = p->sqrt(p->mad(x,x, p->mul(y,y)));
|
||||
|
||||
// Rescale to [r1,r2]
|
||||
float denom = 1.0f / (fRadius2 - fRadius1),
|
||||
scale = SkTMax(fRadius1, fRadius2) * denom,
|
||||
bias = -fRadius1 * denom;
|
||||
*t = p->mad(r, p->uniformF(uniforms->pushF(scale))
|
||||
, p->uniformF(uniforms->pushF(bias )));
|
||||
return MaskNeeded::None;
|
||||
}
|
||||
|
||||
if (fType == Type::kStrip) {
|
||||
float r = fRadius1 / this->getCenterX1();
|
||||
*t = p->add(x, p->sqrt(p->sub(p->splat(r*r),
|
||||
p->mul(y,y))));
|
||||
return MaskNeeded::NaNs;
|
||||
}
|
||||
|
||||
return MaskNeeded::NotYetImplemented;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
@ -69,6 +69,9 @@ protected:
|
||||
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
||||
SkRasterPipeline* postPipeline) const override;
|
||||
|
||||
MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
|
||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
||||
|
||||
private:
|
||||
SK_FLATTENABLE_HOOKS(SkTwoPointConicalGradient)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user