Support arbitrary bicubic filtering in raster pipeline
Guarded for chromium and Google3 Bug: chromium:1302855 Change-Id: If9b085a24d5f03e6971506c98463aa8c09100a67 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/516016 Reviewed-by: Michael Ludwig <michaelludwig@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
d8590052e8
commit
22c94544b3
@ -126,6 +126,8 @@ struct SkRasterPipeline_GatherCtx {
|
||||
int stride;
|
||||
float width;
|
||||
float height;
|
||||
|
||||
float weights[16]; // for bicubic and bicubic_clamp_8888
|
||||
};
|
||||
|
||||
// State shared by save_xy, accumulate, and bilinear_* / bicubic_*.
|
||||
@ -136,6 +138,8 @@ struct SkRasterPipeline_SamplerCtx {
|
||||
float fy[SkRasterPipeline_kMaxStride];
|
||||
float scalex[SkRasterPipeline_kMaxStride];
|
||||
float scaley[SkRasterPipeline_kMaxStride];
|
||||
|
||||
float weights[16]; // for bicubic_[np][13][xy]
|
||||
};
|
||||
|
||||
struct SkRasterPipeline_TileCtx {
|
||||
|
@ -2651,9 +2651,14 @@ STAGE(bilinear_py, SkRasterPipeline_SamplerCtx* ctx) { bilinear_y<+1>(ctx, &g);
|
||||
// In bicubic interpolation, the 16 pixels and +/- 0.5 and +/- 1.5 offsets from the sample
|
||||
// pixel center are combined with a non-uniform cubic filter, with higher values near the center.
|
||||
//
|
||||
// We break this function into two parts, one for near 0.5 offsets and one for far 1.5 offsets.
|
||||
// See GrCubicEffect for details of this particular filter.
|
||||
// This helper computes the total weight along one axis (our bicubic filter is separable), given one
|
||||
// column of the sampling matrix, and a fractional pixel offset. See SkCubicResampler for details.
|
||||
|
||||
SI F bicubic_wts(F t, float A, float B, float C, float D) {
|
||||
return mad(t, mad(t, mad(t, D, C), B), A);
|
||||
}
|
||||
|
||||
#if defined(SK_LEGACY_RP_BICUBIC)
|
||||
SI F bicubic_near(F t) {
|
||||
// 1/18 + 9/18t + 27/18t^2 - 21/18t^3 == t ( t ( -21/18t + 27/18) + 9/18) + 1/18
|
||||
return mad(t, mad(t, mad((-21/18.0f), t, (27/18.0f)), (9/18.0f)), (1/18.0f));
|
||||
@ -2662,6 +2667,7 @@ SI F bicubic_far(F t) {
|
||||
// 0/18 + 0/18*t - 6/18t^2 + 7/18t^3 == t^2 (7/18t - 6/18)
|
||||
return (t*t)*mad((7/18.0f), t, (-6/18.0f));
|
||||
}
|
||||
#endif
|
||||
|
||||
template <int kScale>
|
||||
SI void bicubic_x(SkRasterPipeline_SamplerCtx* ctx, F* x) {
|
||||
@ -2669,10 +2675,18 @@ SI void bicubic_x(SkRasterPipeline_SamplerCtx* ctx, F* x) {
|
||||
F fx = sk_unaligned_load<F>(ctx->fx);
|
||||
|
||||
F scalex;
|
||||
#if defined(SK_LEGACY_RP_BICUBIC)
|
||||
if (kScale == -3) { scalex = bicubic_far (1.0f - fx); }
|
||||
if (kScale == -1) { scalex = bicubic_near(1.0f - fx); }
|
||||
if (kScale == +1) { scalex = bicubic_near( fx); }
|
||||
if (kScale == +3) { scalex = bicubic_far ( fx); }
|
||||
#else
|
||||
const float* w = ctx->weights;
|
||||
if (kScale == -3) { scalex = bicubic_wts(fx, w[0], w[4], w[ 8], w[12]); }
|
||||
if (kScale == -1) { scalex = bicubic_wts(fx, w[1], w[5], w[ 9], w[13]); }
|
||||
if (kScale == +1) { scalex = bicubic_wts(fx, w[2], w[6], w[10], w[14]); }
|
||||
if (kScale == +3) { scalex = bicubic_wts(fx, w[3], w[7], w[11], w[15]); }
|
||||
#endif
|
||||
sk_unaligned_store(ctx->scalex, scalex);
|
||||
}
|
||||
template <int kScale>
|
||||
@ -2681,10 +2695,18 @@ SI void bicubic_y(SkRasterPipeline_SamplerCtx* ctx, F* y) {
|
||||
F fy = sk_unaligned_load<F>(ctx->fy);
|
||||
|
||||
F scaley;
|
||||
#if defined(SK_LEGACY_RP_BICUBIC)
|
||||
if (kScale == -3) { scaley = bicubic_far (1.0f - fy); }
|
||||
if (kScale == -1) { scaley = bicubic_near(1.0f - fy); }
|
||||
if (kScale == +1) { scaley = bicubic_near( fy); }
|
||||
if (kScale == +3) { scaley = bicubic_far ( fy); }
|
||||
#else
|
||||
const float* w = ctx->weights;
|
||||
if (kScale == -3) { scaley = bicubic_wts(fy, w[0], w[4], w[ 8], w[12]); }
|
||||
if (kScale == -1) { scaley = bicubic_wts(fy, w[1], w[5], w[ 9], w[13]); }
|
||||
if (kScale == +1) { scaley = bicubic_wts(fy, w[2], w[6], w[10], w[14]); }
|
||||
if (kScale == +3) { scaley = bicubic_wts(fy, w[3], w[7], w[11], w[15]); }
|
||||
#endif
|
||||
sk_unaligned_store(ctx->scaley, scaley);
|
||||
}
|
||||
|
||||
@ -2788,8 +2810,20 @@ STAGE(bilinear, const SkRasterPipeline_SamplerCtx2* ctx) {
|
||||
STAGE(bicubic, SkRasterPipeline_SamplerCtx2* ctx) {
|
||||
F x = r, fx = fract(x + 0.5f),
|
||||
y = g, fy = fract(y + 0.5f);
|
||||
#if defined(SK_LEGACY_RP_BICUBIC)
|
||||
const F wx[] = { bicubic_far(1-fx), bicubic_near(1-fx), bicubic_near(fx), bicubic_far(fx) };
|
||||
const F wy[] = { bicubic_far(1-fy), bicubic_near(1-fy), bicubic_near(fy), bicubic_far(fy) };
|
||||
#else
|
||||
const float* w = ctx->weights;
|
||||
const F wx[] = {bicubic_wts(fx, w[0], w[4], w[ 8], w[12]),
|
||||
bicubic_wts(fx, w[1], w[5], w[ 9], w[13]),
|
||||
bicubic_wts(fx, w[2], w[6], w[10], w[14]),
|
||||
bicubic_wts(fx, w[3], w[7], w[11], w[15])};
|
||||
const F wy[] = {bicubic_wts(fy, w[0], w[4], w[ 8], w[12]),
|
||||
bicubic_wts(fy, w[1], w[5], w[ 9], w[13]),
|
||||
bicubic_wts(fy, w[2], w[6], w[10], w[14]),
|
||||
bicubic_wts(fy, w[3], w[7], w[11], w[15])};
|
||||
#endif
|
||||
|
||||
sampler(ctx, x,y, wx,wy, &r,&g,&b,&a);
|
||||
}
|
||||
@ -2850,6 +2884,7 @@ STAGE(bicubic_clamp_8888, const SkRasterPipeline_GatherCtx* ctx) {
|
||||
// We'll accumulate the color of all four samples into {r,g,b,a} directly.
|
||||
r = g = b = a = 0;
|
||||
|
||||
#if defined(SK_LEGACY_RP_BICUBIC)
|
||||
const F scaley[4] = {
|
||||
bicubic_far (1.0f - fy), bicubic_near(1.0f - fy),
|
||||
bicubic_near( fy), bicubic_far ( fy),
|
||||
@ -2858,6 +2893,17 @@ STAGE(bicubic_clamp_8888, const SkRasterPipeline_GatherCtx* ctx) {
|
||||
bicubic_far (1.0f - fx), bicubic_near(1.0f - fx),
|
||||
bicubic_near( fx), bicubic_far ( fx),
|
||||
};
|
||||
#else
|
||||
const float* w = ctx->weights;
|
||||
const F scaley[4] = {bicubic_wts(fy, w[0], w[4], w[ 8], w[12]),
|
||||
bicubic_wts(fy, w[1], w[5], w[ 9], w[13]),
|
||||
bicubic_wts(fy, w[2], w[6], w[10], w[14]),
|
||||
bicubic_wts(fy, w[3], w[7], w[11], w[15])};
|
||||
const F scalex[4] = {bicubic_wts(fx, w[0], w[4], w[ 8], w[12]),
|
||||
bicubic_wts(fx, w[1], w[5], w[ 9], w[13]),
|
||||
bicubic_wts(fx, w[2], w[6], w[10], w[14]),
|
||||
bicubic_wts(fx, w[3], w[7], w[11], w[15])};
|
||||
#endif
|
||||
|
||||
F sample_y = cy - 1.5f;
|
||||
for (int yy = 0; yy <= 3; ++yy) {
|
||||
|
@ -174,12 +174,14 @@ bool SkImageShader::isOpaque() const {
|
||||
fTileModeX != SkTileMode::kDecal && fTileModeY != SkTileMode::kDecal;
|
||||
}
|
||||
|
||||
#if defined(SK_LEGACY_RP_BICUBIC)
|
||||
constexpr SkCubicResampler kDefaultCubicResampler{1.0f/3, 1.0f/3};
|
||||
|
||||
static bool is_default_cubic_resampler(SkCubicResampler cubic) {
|
||||
return SkScalarNearlyEqual(cubic.B, kDefaultCubicResampler.B) &&
|
||||
SkScalarNearlyEqual(cubic.C, kDefaultCubicResampler.C);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
|
||||
|
||||
@ -459,14 +461,14 @@ bool SkImageShader::doStages(const SkStageRec& rec, TransformShader* updater) co
|
||||
SkASSERT(!needs_subset(fImage.get(), fSubset)); // TODO(skbug.com/12784)
|
||||
// We only support certain sampling options in stages so far
|
||||
auto sampling = fSampling;
|
||||
if (sampling.useCubic) {
|
||||
if (!is_default_cubic_resampler(sampling.cubic)) {
|
||||
return false;
|
||||
}
|
||||
} else if (sampling.mipmap == SkMipmapMode::kLinear) {
|
||||
if (sampling.mipmap == SkMipmapMode::kLinear) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(SK_LEGACY_RP_BICUBIC)
|
||||
if (sampling.useCubic && !is_default_cubic_resampler(sampling.cubic)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (updater && (sampling.mipmap != SkMipmapMode::kNone)) {
|
||||
// TODO: medium: recall RequestBitmap and update width/height accordingly
|
||||
@ -510,6 +512,9 @@ bool SkImageShader::doStages(const SkStageRec& rec, TransformShader* updater) co
|
||||
gather->stride = pm.rowBytesAsPixels();
|
||||
gather->width = pm.width();
|
||||
gather->height = pm.height();
|
||||
if (sampling.useCubic) {
|
||||
CubicResamplerMatrix(sampling.cubic.B, sampling.cubic.C).getColMajor(gather->weights);
|
||||
}
|
||||
|
||||
auto limit_x = alloc->make<SkRasterPipeline_TileCtx>(),
|
||||
limit_y = alloc->make<SkRasterPipeline_TileCtx>();
|
||||
@ -693,6 +698,8 @@ bool SkImageShader::doStages(const SkStageRec& rec, TransformShader* updater) co
|
||||
};
|
||||
|
||||
if (sampling.useCubic) {
|
||||
CubicResamplerMatrix(sampling.cubic.B, sampling.cubic.C).getColMajor(sampler->weights);
|
||||
|
||||
p->append(SkRasterPipeline::save_xy, sampler);
|
||||
|
||||
sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n3y);
|
||||
|
Loading…
Reference in New Issue
Block a user