aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/SkRasterPipeline.h4
-rw-r--r--src/image/SkImageShader.cpp26
-rw-r--r--src/image/SkImageShaderContext.h2
-rw-r--r--src/opts/SkRasterPipeline_opts.h55
4 files changed, 36 insertions, 51 deletions
diff --git a/src/core/SkRasterPipeline.h b/src/core/SkRasterPipeline.h
index 179bfb531d..3ecf80f79b 100644
--- a/src/core/SkRasterPipeline.h
+++ b/src/core/SkRasterPipeline.h
@@ -86,8 +86,8 @@
M(clamp_y) M(mirror_y) M(repeat_y) \
M(gather_a8) M(gather_g8) M(gather_i8) \
M(gather_565) M(gather_4444) M(gather_8888) M(gather_f16) \
- M(top_left) M(top_right) M(bottom_left) M(bottom_right) \
- M(accumulate)
+ M(bilinear_nn) M(bilinear_pn) M(bilinear_np) M(bilinear_pp) \
+ M(save_xy) M(accumulate)
class SkRasterPipeline {
public:
diff --git a/src/image/SkImageShader.cpp b/src/image/SkImageShader.cpp
index d2ddc95744..719bced4f5 100644
--- a/src/image/SkImageShader.cpp
+++ b/src/image/SkImageShader.cpp
@@ -358,26 +358,20 @@ bool SkImageShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* dst, SkFal
}
};
- if (quality == kNone_SkFilterQuality) {
- append_tiling_and_gather();
-
- } else {
- p->append(SkRasterPipeline::top_left, ctx);
- append_tiling_and_gather();
- p->append(SkRasterPipeline::accumulate, ctx);
-
- p->append(SkRasterPipeline::top_right, ctx);
- append_tiling_and_gather();
- p->append(SkRasterPipeline::accumulate, ctx);
-
- p->append(SkRasterPipeline::bottom_left, ctx);
+ auto sample = [&](SkRasterPipeline::StockStage sampler) {
+ p->append(sampler, ctx);
append_tiling_and_gather();
p->append(SkRasterPipeline::accumulate, ctx);
+ };
- p->append(SkRasterPipeline::bottom_right, ctx);
+ if (quality == kNone_SkFilterQuality) {
append_tiling_and_gather();
- p->append(SkRasterPipeline::accumulate, ctx);
-
+ } else {
+ p->append(SkRasterPipeline::save_xy, ctx);
+ sample(SkRasterPipeline::bilinear_nn);
+ sample(SkRasterPipeline::bilinear_np);
+ sample(SkRasterPipeline::bilinear_pn);
+ sample(SkRasterPipeline::bilinear_pp);
p->append(SkRasterPipeline::move_dst_src);
}
diff --git a/src/image/SkImageShaderContext.h b/src/image/SkImageShaderContext.h
index 7e50286072..b0652900dd 100644
--- a/src/image/SkImageShaderContext.h
+++ b/src/image/SkImageShaderContext.h
@@ -28,6 +28,8 @@ struct SkImageShaderContext {
float matrix[9];
float x[8];
float y[8];
+ float fx[8];
+ float fy[8];
float scale[8];
};
diff --git a/src/opts/SkRasterPipeline_opts.h b/src/opts/SkRasterPipeline_opts.h
index e73d56cc8b..d0a57e4a11 100644
--- a/src/opts/SkRasterPipeline_opts.h
+++ b/src/opts/SkRasterPipeline_opts.h
@@ -801,49 +801,38 @@ STAGE( clamp_y) { g = clamp (g, *(const int*)ctx); }
STAGE(repeat_y) { g = repeat(g, *(const int*)ctx); }
STAGE(mirror_y) { g = mirror(g, *(const int*)ctx); }
-STAGE(top_left) {
+STAGE(save_xy) {
auto sc = (SkImageShaderContext*)ctx;
r.store(sc->x);
g.store(sc->y);
- r -= 0.5f;
- g -= 0.5f;
-
- auto fx = r - r.floor(),
- fy = g - g.floor();
- ((1.0f - fx) * (1.0f - fy)).store(sc->scale);
-};
-STAGE(top_right) {
- auto sc = (SkImageShaderContext*)ctx;
-
- r = SkNf::Load(sc->x) + 0.5f;
- g = SkNf::Load(sc->y) - 0.5f;
+ auto fract = [](const SkNf& v) { return v - v.floor(); };
+ fract(r + 0.5f).store(sc->fx);
+ fract(g + 0.5f).store(sc->fy);
+}
- auto fx = r - r.floor(),
- fy = g - g.floor();
- (fx * (1.0f - fy)).store(sc->scale);
-};
-STAGE(bottom_left) {
+template <int X, int Y>
+SI void bilinear(void* ctx, SkNf* x, SkNf* y) {
auto sc = (SkImageShaderContext*)ctx;
- r = SkNf::Load(sc->x) - 0.5f;
- g = SkNf::Load(sc->y) + 0.5f;
+ // Bilinear interpolation considers the 4 physical pixels at
+ // each corner of a logical pixel centered at (sc->x, sc->y).
+ *x = SkNf::Load(sc->x) + X*0.5f;
+ *y = SkNf::Load(sc->y) + Y*0.5f;
- auto fx = r - r.floor(),
- fy = g - g.floor();
- ((1.0f - fx) * fy).store(sc->scale);
-};
-STAGE(bottom_right) {
- auto sc = (SkImageShaderContext*)ctx;
-
- r = SkNf::Load(sc->x) + 0.5f;
- g = SkNf::Load(sc->y) + 0.5f;
+ // Each corner pixel contributes color in direct proportion to its overlap.
+ auto fx = SkNf::Load(sc->fx),
+ fy = SkNf::Load(sc->fy);
+ auto overlap = (X > 0 ? fx : (1.0f - fx))
+ * (Y > 0 ? fy : (1.0f - fy));
+ overlap.store(sc->scale);
+}
+STAGE(bilinear_nn) { bilinear<-1,-1>(ctx, &r, &g); }
+STAGE(bilinear_pn) { bilinear<+1,-1>(ctx, &r, &g); }
+STAGE(bilinear_np) { bilinear<-1,+1>(ctx, &r, &g); }
+STAGE(bilinear_pp) { bilinear<+1,+1>(ctx, &r, &g); }
- auto fx = r - r.floor(),
- fy = g - g.floor();
- (fx * fy).store(sc->scale);
-};
STAGE(accumulate) {
auto sc = (const SkImageShaderContext*)ctx;