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();
|
inv.normalizePerspective();
|
||||||
|
|
||||||
SkShaderBase::ApplyMatrix(p, inv, &x,&y,uniforms);
|
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.
|
skvm::I32 keep;
|
||||||
// Perhaps unexpectedly, all clamping is handled by our search, so
|
skvm::F32 t;
|
||||||
// we don't explicitly clamp t to [0,1]. That clamp would break
|
switch (this->transformT(p,uniforms, x,y, &t)) {
|
||||||
// hard stops right at 0 or 1 boundaries in kClamp mode.
|
case MaskNeeded::None: keep = p->splat(~0); break;
|
||||||
// (kRepeat and kMirror always produce values in [0,1].)
|
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) {
|
switch(fTileMode) {
|
||||||
case SkTileMode::kDecal: break;
|
case SkTileMode::kClamp:
|
||||||
case SkTileMode::kClamp: break;
|
break;
|
||||||
case SkTileMode::kRepeat: t = p->sub(t, p->floor(t)); 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: {
|
case SkTileMode::kMirror: {
|
||||||
// t = | (t-1) - 2*(floor( (t-1)*0.5 )) - 1 |
|
// t = | (t-1) - 2*(floor( (t-1)*0.5 )) - 1 |
|
||||||
// {-A-} {--------B-------}
|
// {-A-} {--------B-------}
|
||||||
@ -578,15 +590,10 @@ bool SkGradientShaderBase::onProgram(skvm::Builder* p,
|
|||||||
p->premul(r,g,b,*a);
|
p->premul(r,g,b,*a);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mask away any pixels that we tried to sample outside the bounds in kDecal.
|
*r = p->bit_cast(p->bit_and(keep, p->bit_cast(*r)));
|
||||||
if (fTileMode == SkTileMode::kDecal) {
|
*g = p->bit_cast(p->bit_and(keep, p->bit_cast(*g)));
|
||||||
skvm::I32 in_bounds = p->eq(t, p->clamp(t, p->splat(0.0f), p->splat(1.0f)));
|
*b = p->bit_cast(p->bit_and(keep, p->bit_cast(*b)));
|
||||||
*r = p->bit_cast(p->bit_and(in_bounds, p->bit_cast(*r)));
|
*a = p->bit_cast(p->bit_and(keep, p->bit_cast(*a)));
|
||||||
*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)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,8 +89,9 @@ protected:
|
|||||||
virtual void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
virtual void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
||||||
SkRasterPipeline* postPipeline) const = 0;
|
SkRasterPipeline* postPipeline) const = 0;
|
||||||
|
|
||||||
virtual bool transformT(skvm::Builder*, skvm::Uniforms*,
|
enum class MaskNeeded { None, NaNs, Degens, NotYetImplemented };
|
||||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const { return false; }
|
virtual MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
|
||||||
|
skvm::F32 x, skvm::F32 y, skvm::F32* t) const = 0;
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
|
static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
|
||||||
|
@ -75,11 +75,12 @@ void SkLinearGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline*,
|
|||||||
// No extra stage needed for linear gradients.
|
// No extra stage needed for linear gradients.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkLinearGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
|
SkGradientShaderBase::MaskNeeded
|
||||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
|
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.
|
// We've baked getting t in x into the matrix, so this is pretty trivial.
|
||||||
*t = x;
|
*t = x;
|
||||||
return true;
|
return MaskNeeded::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {
|
SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {
|
||||||
|
@ -29,8 +29,8 @@ protected:
|
|||||||
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
||||||
SkRasterPipeline* postPipeline) const final;
|
SkRasterPipeline* postPipeline) const final;
|
||||||
|
|
||||||
bool transformT(skvm::Builder*, skvm::Uniforms*,
|
MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
|
||||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -63,10 +63,11 @@ void SkRadialGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline* p,
|
|||||||
p->append(SkRasterPipeline::xy_to_radius);
|
p->append(SkRasterPipeline::xy_to_radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkRadialGradient::transformT(skvm::Builder* p, skvm::Uniforms*,
|
SkGradientShaderBase::MaskNeeded
|
||||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
|
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)));
|
*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,
|
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
||||||
SkRasterPipeline* postPipeline) const override;
|
SkRasterPipeline* postPipeline) const override;
|
||||||
|
|
||||||
bool transformT(skvm::Builder*, skvm::Uniforms*,
|
MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
|
||||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SK_FLATTENABLE_HOOKS(SkRadialGradient)
|
SK_FLATTENABLE_HOOKS(SkRadialGradient)
|
||||||
|
@ -68,8 +68,9 @@ void SkSweepGradient::appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline
|
|||||||
SkMatrix::MakeTrans(fTBias , 0)));
|
SkMatrix::MakeTrans(fTBias , 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
|
SkGradientShaderBase::MaskNeeded
|
||||||
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
|
SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms,
|
||||||
|
skvm::F32 x, skvm::F32 y, skvm::F32* t) const {
|
||||||
skvm::F32 xabs = p->abs(x),
|
skvm::F32 xabs = p->abs(x),
|
||||||
yabs = p->abs(y),
|
yabs = p->abs(y),
|
||||||
slope = p->div(p->min(xabs, yabs),
|
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))
|
*t = p->mad(*t, p->uniformF(uniforms->pushF(fTScale))
|
||||||
, p->uniformF(uniforms->pushF(fTScale*fTBias)));
|
, p->uniformF(uniforms->pushF(fTScale*fTBias)));
|
||||||
}
|
}
|
||||||
return true;
|
return MaskNeeded::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
@ -29,8 +29,9 @@ protected:
|
|||||||
|
|
||||||
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
||||||
SkRasterPipeline* postPipeline) const override;
|
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:
|
private:
|
||||||
SK_FLATTENABLE_HOOKS(SkSweepGradient)
|
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
|
#if SK_SUPPORT_GPU
|
||||||
|
@ -69,6 +69,9 @@ protected:
|
|||||||
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
|
||||||
SkRasterPipeline* postPipeline) const override;
|
SkRasterPipeline* postPipeline) const override;
|
||||||
|
|
||||||
|
MaskNeeded transformT(skvm::Builder*, skvm::Uniforms*,
|
||||||
|
skvm::F32 x, skvm::F32 y, skvm::F32* t) const final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SK_FLATTENABLE_HOOKS(SkTwoPointConicalGradient)
|
SK_FLATTENABLE_HOOKS(SkTwoPointConicalGradient)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user