2pt conical stage for focal-pt-on-edge case
When the focal point is on the edge of the end circle, the quadratic equation devolves to linear. Add a stage to handle this case. As a complication, this case can produce "degenerate" values: 1) t == NaN 2) R(t) < 0 For these, we're supposed to draw transparent black - which means overwriting the color from the gradient stage. To support this, build a 0/1 vector mask in the context, and apply it post-gradient-stage. Change-Id: Ice4e3243abfd8c784bb810f6c310aed7a4ac7dc8 Reviewed-on: https://skia-review.googlesource.com/21111 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
c02de0b844
commit
2e409009fb
@ -107,7 +107,8 @@ struct SkJumper_constants;
|
||||
M(evenly_spaced_2_stop_gradient) \
|
||||
M(xy_to_unit_angle) \
|
||||
M(xy_to_radius) \
|
||||
M(xy_to_2pt_conical) \
|
||||
M(xy_to_2pt_conical_quadratic) M(xy_to_2pt_conical_linear) \
|
||||
M(vector_scale) \
|
||||
M(byte_tables) M(byte_tables_rgb) \
|
||||
M(rgb_to_hsl) \
|
||||
M(hsl_to_rgb)
|
||||
|
@ -108,6 +108,7 @@ struct SkJumper_GradientCtx {
|
||||
};
|
||||
|
||||
struct SkJumper_2PtConicalCtx {
|
||||
float fMask[SkJumper_kMaxStride];
|
||||
float fCoeffA,
|
||||
fInvCoeffA,
|
||||
fR0,
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1208,7 +1208,7 @@ STAGE(xy_to_radius) {
|
||||
r = sqrt_(X2 + Y2);
|
||||
}
|
||||
|
||||
STAGE(xy_to_2pt_conical) {
|
||||
STAGE(xy_to_2pt_conical_quadratic) {
|
||||
auto* c = (const SkJumper_2PtConicalCtx*)ctx;
|
||||
|
||||
// At this point, (x, y) is mapped into a synthetic gradient space with
|
||||
@ -1255,6 +1255,31 @@ STAGE(xy_to_2pt_conical) {
|
||||
(-coeffB - sqrt_disc) * invCoeffA * .5f);
|
||||
}
|
||||
|
||||
STAGE(xy_to_2pt_conical_linear) {
|
||||
auto* c = (SkJumper_2PtConicalCtx*)ctx;
|
||||
|
||||
const F coeffB = -2 * (r + c->fDR * c->fR0),
|
||||
coeffC = r * r + g * g - c->fR0 * c->fR0;
|
||||
|
||||
r = -coeffC / coeffB;
|
||||
|
||||
// Compute and save a mask for degenerate values.
|
||||
g = 1.0f;
|
||||
g = if_then_else(mad(r, c->fDR, c->fR0) < 0, F(0), g); // R(t) < 0
|
||||
g = if_then_else(r != r , F(0), g); // NaN
|
||||
|
||||
unaligned_store(&c->fMask, g);
|
||||
}
|
||||
|
||||
STAGE(vector_scale) {
|
||||
const F scale = unaligned_load<F>((const float*)ctx);
|
||||
|
||||
r = r * scale;
|
||||
g = g * scale;
|
||||
b = b * scale;
|
||||
a = a * scale;
|
||||
}
|
||||
|
||||
STAGE(save_xy) {
|
||||
auto c = (SkJumper_SamplerCtx*)ctx;
|
||||
|
||||
|
@ -375,8 +375,9 @@ bool SkGradientShaderBase::onAppendStages(SkRasterPipeline* p,
|
||||
return false;
|
||||
}
|
||||
|
||||
SkRasterPipeline_<256> subclass;
|
||||
if (!this->adjustMatrixAndAppendStages(alloc, &matrix, &subclass)) {
|
||||
SkRasterPipeline_<256> tPipeline;
|
||||
SkRasterPipeline_<256> postPipeline;
|
||||
if (!this->adjustMatrixAndAppendStages(alloc, &matrix, &tPipeline, &postPipeline)) {
|
||||
return this->INHERITED::onAppendStages(p, dstCS, alloc, ctm, paint, localM);
|
||||
}
|
||||
|
||||
@ -390,7 +391,7 @@ bool SkGradientShaderBase::onAppendStages(SkRasterPipeline* p,
|
||||
p->append(SkRasterPipeline::matrix_perspective, m);
|
||||
}
|
||||
|
||||
p->extend(subclass);
|
||||
p->extend(tPipeline);
|
||||
|
||||
switch(fTileMode) {
|
||||
case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x_1); break;
|
||||
@ -496,6 +497,8 @@ bool SkGradientShaderBase::onAppendStages(SkRasterPipeline* p,
|
||||
p->append(SkRasterPipeline::premul);
|
||||
}
|
||||
|
||||
p->extend(postPipeline);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -239,7 +239,10 @@ protected:
|
||||
|
||||
virtual bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
|
||||
SkMatrix* matrix,
|
||||
SkRasterPipeline* p) const { return false; }
|
||||
SkRasterPipeline* tPipeline,
|
||||
SkRasterPipeline* postPipeline) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
|
||||
|
@ -81,7 +81,8 @@ SkShaderBase::Context* SkLinearGradient::onMakeBurstPipelineContext(
|
||||
|
||||
bool SkLinearGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
|
||||
SkMatrix* matrix,
|
||||
SkRasterPipeline* p) const {
|
||||
SkRasterPipeline* p,
|
||||
SkRasterPipeline*) const {
|
||||
*matrix = SkMatrix::Concat(fPtsToUnit, *matrix);
|
||||
// If the gradient is less than a quarter of a pixel, this falls into the
|
||||
// subpixel gradient code handled on a different path.
|
||||
|
@ -66,7 +66,8 @@ protected:
|
||||
|
||||
bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
|
||||
SkMatrix* matrix,
|
||||
SkRasterPipeline* p) const final;
|
||||
SkRasterPipeline* tPipeline,
|
||||
SkRasterPipeline* postPipeline) const final;
|
||||
|
||||
|
||||
sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer* xformer) const override;
|
||||
|
@ -382,7 +382,8 @@ sk_sp<SkShader> SkRadialGradient::onMakeColorSpace(SkColorSpaceXformer* xformer)
|
||||
|
||||
bool SkRadialGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
|
||||
SkMatrix* matrix,
|
||||
SkRasterPipeline* p) const {
|
||||
SkRasterPipeline* p,
|
||||
SkRasterPipeline*) const {
|
||||
matrix->postTranslate(-fCenter.fX, -fCenter.fY);
|
||||
matrix->postScale(1/fRadius, 1/fRadius);
|
||||
|
||||
|
@ -40,7 +40,8 @@ protected:
|
||||
|
||||
bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
|
||||
SkMatrix* matrix,
|
||||
SkRasterPipeline* p) const final;
|
||||
SkRasterPipeline* tPipeline,
|
||||
SkRasterPipeline* postPipeline) const final;
|
||||
|
||||
private:
|
||||
const SkPoint fCenter;
|
||||
|
@ -301,7 +301,8 @@ void SkSweepGradient::toString(SkString* str) const {
|
||||
|
||||
bool SkSweepGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
|
||||
SkMatrix* matrix,
|
||||
SkRasterPipeline* p) const {
|
||||
SkRasterPipeline* p,
|
||||
SkRasterPipeline*) const {
|
||||
matrix->postTranslate(-fCenter.fX, -fCenter.fY);
|
||||
p->append(SkRasterPipeline::xy_to_unit_angle);
|
||||
|
||||
|
@ -40,7 +40,8 @@ protected:
|
||||
|
||||
bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
|
||||
SkMatrix* matrix,
|
||||
SkRasterPipeline* p) const final;
|
||||
SkRasterPipeline* tPipeline,
|
||||
SkRasterPipeline* postPipeline) const final;
|
||||
|
||||
bool isRasterPipelineOnly() const final;
|
||||
|
||||
|
@ -428,7 +428,8 @@ void SkTwoPointConicalGradient::toString(SkString* str) const {
|
||||
|
||||
bool SkTwoPointConicalGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
|
||||
SkMatrix* matrix,
|
||||
SkRasterPipeline* p) const {
|
||||
SkRasterPipeline* p,
|
||||
SkRasterPipeline* postPipeline) const {
|
||||
const auto dCenter = (fCenter1 - fCenter2).length();
|
||||
const auto dRadius = fRadius2 - fRadius1;
|
||||
SkASSERT(dRadius >= 0);
|
||||
@ -468,17 +469,21 @@ bool SkTwoPointConicalGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
|
||||
// Since we've squashed the centers into a unit vector, we must also scale
|
||||
// all the coefficient variables by (1 / dCenter).
|
||||
const auto coeffA = 1 - dRadius * dRadius / (dCenter * dCenter);
|
||||
if (SkScalarNearlyZero(coeffA)) {
|
||||
// We only handle well behaved quadratic cases for now.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* ctx = alloc->make<SkJumper_2PtConicalCtx>();
|
||||
ctx->fCoeffA = coeffA;
|
||||
ctx->fInvCoeffA = 1 / coeffA;
|
||||
ctx->fR0 = fRadius1 / dCenter;
|
||||
ctx->fDR = dRadius / dCenter;
|
||||
|
||||
p->append(SkRasterPipeline::xy_to_2pt_conical, ctx);
|
||||
if (SkScalarNearlyZero(coeffA)) {
|
||||
// The focal point is on the edge of the end circle.
|
||||
p->append(SkRasterPipeline::xy_to_2pt_conical_linear, ctx);
|
||||
// To handle degenerate values (NaN, r < 0), the t stage sets up a scale/mask
|
||||
// context, which we post-apply to force transparent black.
|
||||
postPipeline->append(SkRasterPipeline::vector_scale, &ctx->fMask);
|
||||
} else {
|
||||
p->append(SkRasterPipeline::xy_to_2pt_conical_quadratic, ctx);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -81,7 +81,8 @@ protected:
|
||||
|
||||
bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
|
||||
SkMatrix* matrix,
|
||||
SkRasterPipeline* p) const final;
|
||||
SkRasterPipeline* tPipeline,
|
||||
SkRasterPipeline* postPipeline) const final;
|
||||
|
||||
private:
|
||||
SkPoint fCenter1;
|
||||
|
Loading…
Reference in New Issue
Block a user