blob: 86ad6e146f0062ed779d493538f8f366ece46a00 [file] [log] [blame]
herb6eff52a2016-03-23 09:00:33 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkLinearBitmapPipeline_sampler_DEFINED
9#define SkLinearBitmapPipeline_sampler_DEFINED
10
herbcf05dcd2016-05-11 11:53:36 -070011#include <tuple>
12
herb670f01f2016-05-13 10:04:46 -070013#include "SkColor.h"
14#include "SkColorPriv.h"
benjaminwagner6c71e0a2016-04-07 08:49:31 -070015#include "SkFixed.h"
herbd5f2e2e2016-04-14 11:16:44 -070016#include "SkHalf.h"
herb6eff52a2016-03-23 09:00:33 -070017#include "SkLinearBitmapPipeline_core.h"
herb670f01f2016-05-13 10:04:46 -070018#include "SkNx.h"
herbcf05dcd2016-05-11 11:53:36 -070019#include "SkPM4fPriv.h"
herb6eff52a2016-03-23 09:00:33 -070020
21namespace {
22// Explaination of the math:
23// 1 - x x
24// +--------+--------+
25// | | |
26// 1 - y | px00 | px10 |
27// | | |
28// +--------+--------+
29// | | |
30// y | px01 | px11 |
31// | | |
32// +--------+--------+
33//
34//
35// Given a pixelxy each is multiplied by a different factor derived from the fractional part of x
36// and y:
37// * px00 -> (1 - x)(1 - y) = 1 - x - y + xy
38// * px10 -> x(1 - y) = x - xy
39// * px01 -> (1 - x)y = y - xy
40// * px11 -> xy
41// So x * y is calculated first and then used to calculate all the other factors.
mtkleine5fb9c82016-07-07 08:12:09 -070042static Sk4s SK_VECTORCALL bilerp4(Sk4s xs, Sk4s ys, Sk4f px00, Sk4f px10,
herb6eff52a2016-03-23 09:00:33 -070043 Sk4f px01, Sk4f px11) {
44 // Calculate fractional xs and ys.
45 Sk4s fxs = xs - xs.floor();
46 Sk4s fys = ys - ys.floor();
47 Sk4s fxys{fxs * fys};
48 Sk4f sum = px11 * fxys;
49 sum = sum + px01 * (fys - fxys);
50 sum = sum + px10 * (fxs - fxys);
51 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys);
52 return sum;
53}
54
herb15332a82016-05-12 11:37:00 -070055////////////////////////////////////////////////////////////////////////////////////////////////////
herb00dd4532016-07-11 10:33:37 -070056// PixelGetter is the lowest level interface to the source data. There is a PixelConverter for each
herb15332a82016-05-12 11:37:00 -070057// of the different SkColorTypes.
herb00dd4532016-07-11 10:33:37 -070058template <SkColorType, SkGammaType> class PixelConverter;
herb15332a82016-05-12 11:37:00 -070059
herb670f01f2016-05-13 10:04:46 -070060// Alpha handling:
61// The alpha from the paint (tintColor) is used in the blend part of the pipeline to modulate
62// the entire bitmap. So, the tint color is given an alpha of 1.0 so that the later alpha can
63// modulate this color later.
64template <>
herb00dd4532016-07-11 10:33:37 -070065class PixelConverter<kAlpha_8_SkColorType, kLinear_SkGammaType> {
herb670f01f2016-05-13 10:04:46 -070066public:
67 using Element = uint8_t;
herb00dd4532016-07-11 10:33:37 -070068 PixelConverter(const SkPixmap& srcPixmap, SkColor tintColor)
herb670f01f2016-05-13 10:04:46 -070069 : fTintColor{set_alpha(Sk4f_from_SkColor(tintColor), 1.0f)} { }
70
herb00dd4532016-07-11 10:33:37 -070071 Sk4f toSk4f(const Element pixel) const {
72 return fTintColor * (pixel * (1.0f/255.0f));
herb670f01f2016-05-13 10:04:46 -070073 }
74
75private:
76 const Sk4f fTintColor;
77};
78
reeddabe5d32016-06-21 10:28:14 -070079template <SkGammaType gammaType>
mtklein53574b72016-07-20 05:23:31 -070080static inline Sk4f pmcolor_to_rgba(SkPMColor pixel) {
81 return swizzle_rb_if_bgra(
82 (gammaType == kSRGB_SkGammaType) ? Sk4f_fromS32(pixel)
83 : Sk4f_fromL32(pixel));
84}
85
86template <SkGammaType gammaType>
herb00dd4532016-07-11 10:33:37 -070087class PixelConverter<kRGB_565_SkColorType, gammaType> {
herb670f01f2016-05-13 10:04:46 -070088public:
89 using Element = uint16_t;
herb00dd4532016-07-11 10:33:37 -070090 PixelConverter(const SkPixmap& srcPixmap) { }
herb670f01f2016-05-13 10:04:46 -070091
herb00dd4532016-07-11 10:33:37 -070092 Sk4f toSk4f(Element pixel) const {
mtklein53574b72016-07-20 05:23:31 -070093 return pmcolor_to_rgba<gammaType>(SkPixel16ToPixel32(pixel));
herb00dd4532016-07-11 10:33:37 -070094 }
95};
96
97template <SkGammaType gammaType>
98class PixelConverter<kARGB_4444_SkColorType, gammaType> {
99public:
100 using Element = uint16_t;
101 PixelConverter(const SkPixmap& srcPixmap) { }
102
103 Sk4f toSk4f(Element pixel) const {
mtklein53574b72016-07-20 05:23:31 -0700104 return pmcolor_to_rgba<gammaType>(SkPixel4444ToPixel32(pixel));
herb00dd4532016-07-11 10:33:37 -0700105 }
106};
107
108template <SkGammaType gammaType>
109class PixelConverter<kRGBA_8888_SkColorType, gammaType> {
110public:
111 using Element = uint32_t;
112 PixelConverter(const SkPixmap& srcPixmap) { }
113
114 Sk4f toSk4f(Element pixel) const {
reeddabe5d32016-06-21 10:28:14 -0700115 return gammaType == kSRGB_SkGammaType
herb670f01f2016-05-13 10:04:46 -0700116 ? Sk4f_fromS32(pixel)
117 : Sk4f_fromL32(pixel);
118 }
119};
120
reeddabe5d32016-06-21 10:28:14 -0700121template <SkGammaType gammaType>
herb00dd4532016-07-11 10:33:37 -0700122class PixelConverter<kBGRA_8888_SkColorType, gammaType> {
herb15332a82016-05-12 11:37:00 -0700123public:
124 using Element = uint32_t;
herb00dd4532016-07-11 10:33:37 -0700125 PixelConverter(const SkPixmap& srcPixmap) { }
herb15332a82016-05-12 11:37:00 -0700126
herb00dd4532016-07-11 10:33:37 -0700127 Sk4f toSk4f(Element pixel) const {
128 return swizzle_rb(
129 gammaType == kSRGB_SkGammaType ? Sk4f_fromS32(pixel) : Sk4f_fromL32(pixel));
herb15332a82016-05-12 11:37:00 -0700130 }
131};
132
reeddabe5d32016-06-21 10:28:14 -0700133template <SkGammaType gammaType>
herb00dd4532016-07-11 10:33:37 -0700134class PixelConverter<kIndex_8_SkColorType, gammaType> {
herb15332a82016-05-12 11:37:00 -0700135public:
136 using Element = uint8_t;
herb00dd4532016-07-11 10:33:37 -0700137 PixelConverter(const SkPixmap& srcPixmap) {
herb15332a82016-05-12 11:37:00 -0700138 SkColorTable* skColorTable = srcPixmap.ctable();
139 SkASSERT(skColorTable != nullptr);
140
141 fColorTable = (Sk4f*)SkAlign16((intptr_t)fColorTableStorage.get());
142 for (int i = 0; i < skColorTable->count(); i++) {
mtklein53574b72016-07-20 05:23:31 -0700143 fColorTable[i] = pmcolor_to_rgba<gammaType>((*skColorTable)[i]);
herb15332a82016-05-12 11:37:00 -0700144 }
145 }
146
herb00dd4532016-07-11 10:33:37 -0700147 PixelConverter(const PixelConverter& strategy) {
herb15332a82016-05-12 11:37:00 -0700148 fColorTable = (Sk4f*)SkAlign16((intptr_t)fColorTableStorage.get());
149 // TODO: figure out the count.
150 for (int i = 0; i < 256; i++) {
151 fColorTable[i] = strategy.fColorTable[i];
152 }
153 }
154
herb00dd4532016-07-11 10:33:37 -0700155 Sk4f toSk4f(Element index) const {
156 return fColorTable[index];
herb15332a82016-05-12 11:37:00 -0700157 }
158
159private:
160 static const size_t kColorTableSize = sizeof(Sk4f[256]) + 12;
mtklein53574b72016-07-20 05:23:31 -0700161
herb15332a82016-05-12 11:37:00 -0700162 SkAutoMalloc fColorTableStorage{kColorTableSize};
163 Sk4f* fColorTable;
164};
165
reeddabe5d32016-06-21 10:28:14 -0700166template <SkGammaType gammaType>
herb00dd4532016-07-11 10:33:37 -0700167class PixelConverter<kGray_8_SkColorType, gammaType> {
herb670f01f2016-05-13 10:04:46 -0700168public:
169 using Element = uint8_t;
herb00dd4532016-07-11 10:33:37 -0700170 PixelConverter(const SkPixmap& srcPixmap) { }
herb670f01f2016-05-13 10:04:46 -0700171
herb00dd4532016-07-11 10:33:37 -0700172 Sk4f toSk4f(Element pixel) const {
173 float gray = pixel * (1.0f/255.0f);
174 Sk4f result = Sk4f{gray, gray, gray, 1.0f};
reeddabe5d32016-06-21 10:28:14 -0700175 return gammaType == kSRGB_SkGammaType
herb00dd4532016-07-11 10:33:37 -0700176 ? srgb_to_linear(result)
177 : result;
herb670f01f2016-05-13 10:04:46 -0700178 }
179};
180
herb15332a82016-05-12 11:37:00 -0700181template <>
herb00dd4532016-07-11 10:33:37 -0700182class PixelConverter<kRGBA_F16_SkColorType, kLinear_SkGammaType> {
herb15332a82016-05-12 11:37:00 -0700183public:
184 using Element = uint64_t;
herb00dd4532016-07-11 10:33:37 -0700185 PixelConverter(const SkPixmap& srcPixmap) { }
herb15332a82016-05-12 11:37:00 -0700186
herb00dd4532016-07-11 10:33:37 -0700187 Sk4f toSk4f(const Element pixel) const {
mtklein58e389b2016-07-15 07:00:11 -0700188 return SkHalfToFloat_finite(pixel);
herb15332a82016-05-12 11:37:00 -0700189 }
190};
191
herb00dd4532016-07-11 10:33:37 -0700192class PixelAccessorShim {
193public:
194 explicit PixelAccessorShim(SkLinearBitmapPipeline::PixelAccessorInterface* accessor)
195 : fPixelAccessor(accessor) { }
196
197 void SK_VECTORCALL getFewPixels(
198 int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) const {
199 fPixelAccessor->getFewPixels(n, xs, ys, px0, px1, px2);
200 }
201
202 void SK_VECTORCALL get4Pixels(
203 Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const {
204 fPixelAccessor->get4Pixels(xs, ys, px0, px1, px2, px3);
205 }
206
207 void get4Pixels(
208 const void* src, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const {
209 fPixelAccessor->get4Pixels(src, index, px0, px1, px2, px3);
210 };
211
212 Sk4f getPixelFromRow(const void* row, int index) const {
213 return fPixelAccessor->getPixelFromRow(row, index);
214 }
215
216 Sk4f getPixelAt(int index) const {
217 return fPixelAccessor->getPixelAt(index);
218 }
219
220 const void* row(int y) const {
221 return fPixelAccessor->row(y);
222 }
223
224private:
225 SkLinearBitmapPipeline::PixelAccessorInterface* const fPixelAccessor;
226};
227
herb15332a82016-05-12 11:37:00 -0700228////////////////////////////////////////////////////////////////////////////////////////////////////
229// PixelAccessor handles all the same plumbing for all the PixelGetters.
reeddabe5d32016-06-21 10:28:14 -0700230template <SkColorType colorType, SkGammaType gammaType>
herb00dd4532016-07-11 10:33:37 -0700231class PixelAccessor final : public SkLinearBitmapPipeline::PixelAccessorInterface {
232 using Element = typename PixelConverter<colorType, gammaType>::Element;
herb15332a82016-05-12 11:37:00 -0700233public:
herb670f01f2016-05-13 10:04:46 -0700234 template <typename... Args>
235 PixelAccessor(const SkPixmap& srcPixmap, Args&&... args)
herb15332a82016-05-12 11:37:00 -0700236 : fSrc{static_cast<const Element*>(srcPixmap.addr())}
237 , fWidth{srcPixmap.rowBytesAsPixels()}
herb00dd4532016-07-11 10:33:37 -0700238 , fConverter{srcPixmap, std::move<Args>(args)...} { }
herb15332a82016-05-12 11:37:00 -0700239
herb00dd4532016-07-11 10:33:37 -0700240 void SK_VECTORCALL getFewPixels (
241 int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) const override {
herb15332a82016-05-12 11:37:00 -0700242 Sk4i XIs = SkNx_cast<int, SkScalar>(xs);
243 Sk4i YIs = SkNx_cast<int, SkScalar>(ys);
244 Sk4i bufferLoc = YIs * fWidth + XIs;
245 switch (n) {
246 case 3:
247 *px2 = this->getPixelAt(bufferLoc[2]);
248 case 2:
249 *px1 = this->getPixelAt(bufferLoc[1]);
250 case 1:
251 *px0 = this->getPixelAt(bufferLoc[0]);
252 default:
253 break;
254 }
255 }
256
herb00dd4532016-07-11 10:33:37 -0700257 void SK_VECTORCALL get4Pixels(
258 Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const override {
herb15332a82016-05-12 11:37:00 -0700259 Sk4i XIs = SkNx_cast<int, SkScalar>(xs);
260 Sk4i YIs = SkNx_cast<int, SkScalar>(ys);
261 Sk4i bufferLoc = YIs * fWidth + XIs;
262 *px0 = this->getPixelAt(bufferLoc[0]);
263 *px1 = this->getPixelAt(bufferLoc[1]);
264 *px2 = this->getPixelAt(bufferLoc[2]);
265 *px3 = this->getPixelAt(bufferLoc[3]);
266 }
267
herb00dd4532016-07-11 10:33:37 -0700268 void get4Pixels(
269 const void* src, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const override {
herb15332a82016-05-12 11:37:00 -0700270 *px0 = this->getPixelFromRow(src, index + 0);
271 *px1 = this->getPixelFromRow(src, index + 1);
272 *px2 = this->getPixelFromRow(src, index + 2);
273 *px3 = this->getPixelFromRow(src, index + 3);
274 }
275
herb00dd4532016-07-11 10:33:37 -0700276 Sk4f getPixelFromRow(const void* row, int index) const override {
herb15332a82016-05-12 11:37:00 -0700277 const Element* src = static_cast<const Element*>(row);
herb00dd4532016-07-11 10:33:37 -0700278 return fConverter.toSk4f(src[index]);
herb15332a82016-05-12 11:37:00 -0700279 }
280
herb00dd4532016-07-11 10:33:37 -0700281 Sk4f getPixelAt(int index) const override {
herb15332a82016-05-12 11:37:00 -0700282 return this->getPixelFromRow(fSrc, index);
283 }
284
herb00dd4532016-07-11 10:33:37 -0700285 const void* row(int y) const override { return fSrc + y * fWidth; }
herb15332a82016-05-12 11:37:00 -0700286
287private:
288 const Element* const fSrc;
herb00dd4532016-07-11 10:33:37 -0700289 const int fWidth;
290 PixelConverter<colorType, gammaType> fConverter;
herb15332a82016-05-12 11:37:00 -0700291};
292
herb7ccbc1a2016-06-09 09:05:00 -0700293// We're moving through source space at a rate of 1 source pixel per 1 dst pixel.
294// We'll never re-use pixels, but we can at least load contiguous pixels.
295template <typename Next, typename Strategy>
296static void src_strategy_blend(Span span, Next* next, Strategy* strategy) {
297 SkPoint start;
298 SkScalar length;
299 int count;
300 std::tie(start, length, count) = span;
301 int ix = SkScalarFloorToInt(X(start));
302 const void* row = strategy->row((int)std::floor(Y(start)));
303 if (length > 0) {
304 while (count >= 4) {
305 Sk4f px0, px1, px2, px3;
306 strategy->get4Pixels(row, ix, &px0, &px1, &px2, &px3);
307 next->blend4Pixels(px0, px1, px2, px3);
308 ix += 4;
309 count -= 4;
310 }
311
312 while (count > 0) {
313 next->blendPixel(strategy->getPixelFromRow(row, ix));
314 ix += 1;
315 count -= 1;
316 }
317 } else {
318 while (count >= 4) {
319 Sk4f px0, px1, px2, px3;
320 strategy->get4Pixels(row, ix - 3, &px3, &px2, &px1, &px0);
321 next->blend4Pixels(px0, px1, px2, px3);
322 ix -= 4;
323 count -= 4;
324 }
325
326 while (count > 0) {
327 next->blendPixel(strategy->getPixelFromRow(row, ix));
328 ix -= 1;
329 count -= 1;
330 }
331 }
332}
333
334// NearestNeighborSampler - use nearest neighbor filtering to create runs of destination pixels.
herb00dd4532016-07-11 10:33:37 -0700335template<typename Accessor, typename Next>
herb7ccbc1a2016-06-09 09:05:00 -0700336class NearestNeighborSampler : public SkLinearBitmapPipeline::SampleProcessorInterface {
herb6eff52a2016-03-23 09:00:33 -0700337public:
338 template<typename... Args>
herb7ccbc1a2016-06-09 09:05:00 -0700339 NearestNeighborSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next, Args&& ... args)
herb00dd4532016-07-11 10:33:37 -0700340 : fNext{next}, fAccessor{std::forward<Args>(args)...} { }
herb6eff52a2016-03-23 09:00:33 -0700341
herb7ccbc1a2016-06-09 09:05:00 -0700342 NearestNeighborSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next,
343 const NearestNeighborSampler& sampler)
herb00dd4532016-07-11 10:33:37 -0700344 : fNext{next}, fAccessor{sampler.fAccessor} { }
herb9e0efe52016-04-08 13:25:28 -0700345
mtkleine5fb9c82016-07-07 08:12:09 -0700346 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
herb6eff52a2016-03-23 09:00:33 -0700347 SkASSERT(0 < n && n < 4);
348 Sk4f px0, px1, px2;
herb00dd4532016-07-11 10:33:37 -0700349 fAccessor.getFewPixels(n, xs, ys, &px0, &px1, &px2);
herb9e0efe52016-04-08 13:25:28 -0700350 if (n >= 1) fNext->blendPixel(px0);
351 if (n >= 2) fNext->blendPixel(px1);
352 if (n >= 3) fNext->blendPixel(px2);
herb6eff52a2016-03-23 09:00:33 -0700353 }
354
mtkleine5fb9c82016-07-07 08:12:09 -0700355 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
herb6eff52a2016-03-23 09:00:33 -0700356 Sk4f px0, px1, px2, px3;
herb00dd4532016-07-11 10:33:37 -0700357 fAccessor.get4Pixels(xs, ys, &px0, &px1, &px2, &px3);
herb9e0efe52016-04-08 13:25:28 -0700358 fNext->blend4Pixels(px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700359 }
360
herb7ccbc1a2016-06-09 09:05:00 -0700361 void pointSpan(Span span) override {
herb6eff52a2016-03-23 09:00:33 -0700362 SkASSERT(!span.isEmpty());
363 SkPoint start;
364 SkScalar length;
365 int count;
366 std::tie(start, length, count) = span;
367 SkScalar absLength = SkScalarAbs(length);
368 if (absLength < (count - 1)) {
herb7ccbc1a2016-06-09 09:05:00 -0700369 this->spanSlowRate(span);
herb6eff52a2016-03-23 09:00:33 -0700370 } else if (absLength == (count - 1)) {
herb00dd4532016-07-11 10:33:37 -0700371 src_strategy_blend(span, fNext, &fAccessor);
herb6eff52a2016-03-23 09:00:33 -0700372 } else {
herb7ccbc1a2016-06-09 09:05:00 -0700373 this->spanFastRate(span);
herb6eff52a2016-03-23 09:00:33 -0700374 }
375 }
376
herb7ccbc1a2016-06-09 09:05:00 -0700377 void repeatSpan(Span span, int32_t repeatCount) override {
378 while (repeatCount > 0) {
379 this->pointSpan(span);
380 repeatCount--;
herb6eff52a2016-03-23 09:00:33 -0700381 }
382 }
383
mtkleine5fb9c82016-07-07 08:12:09 -0700384 void SK_VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override {
herb7ccbc1a2016-06-09 09:05:00 -0700385 SkFAIL("Using nearest neighbor sampler, but calling a bilerpEdge.");
386 }
387
388 void bilerpSpan(Span span, SkScalar y) override {
389 SkFAIL("Using nearest neighbor sampler, but calling a bilerpSpan.");
390 }
391
herb6eff52a2016-03-23 09:00:33 -0700392private:
393 // When moving through source space more slowly than dst space (zoomed in),
394 // we'll be sampling from the same source pixel more than once.
herb7ccbc1a2016-06-09 09:05:00 -0700395 void spanSlowRate(Span span) {
herb6eff52a2016-03-23 09:00:33 -0700396 SkPoint start;
397 SkScalar length;
398 int count;
399 std::tie(start, length, count) = span;
400 SkScalar x = X(start);
401 SkFixed fx = SkScalarToFixed(x);
402 SkScalar dx = length / (count - 1);
403 SkFixed fdx = SkScalarToFixed(dx);
404
herb00dd4532016-07-11 10:33:37 -0700405 const void* row = fAccessor.row((int)std::floor(Y(start)));
herb6eff52a2016-03-23 09:00:33 -0700406 Next* next = fNext;
407
408 int ix = SkFixedFloorToInt(fx);
409 int prevIX = ix;
herb00dd4532016-07-11 10:33:37 -0700410 Sk4f fpixel = fAccessor.getPixelFromRow(row, ix);
herb6eff52a2016-03-23 09:00:33 -0700411
412 // When dx is less than one, each pixel is used more than once. Using the fixed point fx
413 // allows the code to quickly check that the same pixel is being used. The code uses this
414 // same pixel check to do the sRGB and normalization only once.
415 auto getNextPixel = [&]() {
416 if (ix != prevIX) {
herb00dd4532016-07-11 10:33:37 -0700417 fpixel = fAccessor.getPixelFromRow(row, ix);
herb6eff52a2016-03-23 09:00:33 -0700418 prevIX = ix;
419 }
420 fx += fdx;
421 ix = SkFixedFloorToInt(fx);
422 return fpixel;
423 };
424
425 while (count >= 4) {
426 Sk4f px0 = getNextPixel();
427 Sk4f px1 = getNextPixel();
428 Sk4f px2 = getNextPixel();
429 Sk4f px3 = getNextPixel();
herb9e0efe52016-04-08 13:25:28 -0700430 next->blend4Pixels(px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700431 count -= 4;
432 }
433 while (count > 0) {
herb9e0efe52016-04-08 13:25:28 -0700434 next->blendPixel(getNextPixel());
herb6eff52a2016-03-23 09:00:33 -0700435 count -= 1;
436 }
437 }
438
439 // We're moving through source space at a rate of 1 source pixel per 1 dst pixel.
440 // We'll never re-use pixels, but we can at least load contiguous pixels.
herb7ccbc1a2016-06-09 09:05:00 -0700441 void spanUnitRate(Span span) {
herb00dd4532016-07-11 10:33:37 -0700442 src_strategy_blend(span, fNext, &fAccessor);
herb6eff52a2016-03-23 09:00:33 -0700443 }
444
445 // We're moving through source space faster than dst (zoomed out),
446 // so we'll never reuse a source pixel or be able to do contiguous loads.
herb7ccbc1a2016-06-09 09:05:00 -0700447 void spanFastRate(Span span) {
448 span_fallback(span, this);
herb6eff52a2016-03-23 09:00:33 -0700449 }
450
herb00dd4532016-07-11 10:33:37 -0700451 Next* const fNext;
452 Accessor fAccessor;
herb7ccbc1a2016-06-09 09:05:00 -0700453};
454
herb7df9e4a2016-06-10 13:01:27 -0700455// -- BilerpSampler --------------------------------------------------------------------------------
herb7ccbc1a2016-06-09 09:05:00 -0700456// BilerpSampler - use a bilerp filter to create runs of destination pixels.
herb00dd4532016-07-11 10:33:37 -0700457template<typename Accessor, typename Next>
herb7ccbc1a2016-06-09 09:05:00 -0700458class BilerpSampler : public SkLinearBitmapPipeline::SampleProcessorInterface {
459public:
460 template<typename... Args>
461 BilerpSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next, Args&& ... args)
herb00dd4532016-07-11 10:33:37 -0700462 : fNext{next}, fAccessor{std::forward<Args>(args)...} { }
herb7ccbc1a2016-06-09 09:05:00 -0700463
464 BilerpSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next,
465 const BilerpSampler& sampler)
herb00dd4532016-07-11 10:33:37 -0700466 : fNext{next}, fAccessor{sampler.fAccessor} { }
herb7ccbc1a2016-06-09 09:05:00 -0700467
468 Sk4f bilerpNonEdgePixel(SkScalar x, SkScalar y) {
469 Sk4f px00, px10, px01, px11;
470
471 // bilerp4() expects xs, ys are the top-lefts of the 2x2 kernel.
472 Sk4f xs = Sk4f{x} - 0.5f;
473 Sk4f ys = Sk4f{y} - 0.5f;
474 Sk4f sampleXs = xs + Sk4f{0.0f, 1.0f, 0.0f, 1.0f};
475 Sk4f sampleYs = ys + Sk4f{0.0f, 0.0f, 1.0f, 1.0f};
herb00dd4532016-07-11 10:33:37 -0700476 fAccessor.get4Pixels(sampleXs, sampleYs, &px00, &px10, &px01, &px11);
herb7ccbc1a2016-06-09 09:05:00 -0700477 return bilerp4(xs, ys, px00, px10, px01, px11);
478 }
479
mtkleine5fb9c82016-07-07 08:12:09 -0700480 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
herb7ccbc1a2016-06-09 09:05:00 -0700481 SkASSERT(0 < n && n < 4);
482 auto bilerpPixel = [&](int index) {
483 return this->bilerpNonEdgePixel(xs[index], ys[index]);
484 };
485
486 if (n >= 1) fNext->blendPixel(bilerpPixel(0));
487 if (n >= 2) fNext->blendPixel(bilerpPixel(1));
488 if (n >= 3) fNext->blendPixel(bilerpPixel(2));
489 }
490
mtkleine5fb9c82016-07-07 08:12:09 -0700491 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
herb7ccbc1a2016-06-09 09:05:00 -0700492 auto bilerpPixel = [&](int index) {
493 return this->bilerpNonEdgePixel(xs[index], ys[index]);
494 };
495 fNext->blend4Pixels(bilerpPixel(0), bilerpPixel(1), bilerpPixel(2), bilerpPixel(3));
496 }
497
498 void pointSpan(Span span) override {
499 this->bilerpSpan(span, span.startY());
500 }
501
502 void repeatSpan(Span span, int32_t repeatCount) override {
503 while (repeatCount > 0) {
504 this->pointSpan(span);
505 repeatCount--;
506 }
507 }
508
mtkleine5fb9c82016-07-07 08:12:09 -0700509 void SK_VECTORCALL bilerpEdge(Sk4s sampleXs, Sk4s sampleYs) override {
herb7ccbc1a2016-06-09 09:05:00 -0700510 Sk4f px00, px10, px01, px11;
511 Sk4f xs = Sk4f{sampleXs[0]};
512 Sk4f ys = Sk4f{sampleYs[0]};
herb00dd4532016-07-11 10:33:37 -0700513 fAccessor.get4Pixels(sampleXs, sampleYs, &px00, &px10, &px01, &px11);
herb7ccbc1a2016-06-09 09:05:00 -0700514 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11);
515 fNext->blendPixel(pixel);
516 }
517
518 void bilerpSpan(Span span, SkScalar y) override {
519 SkASSERT(!span.isEmpty());
520 SkPoint start;
521 SkScalar length;
522 int count;
523 std::tie(start, length, count) = span;
524 SkScalar absLength = SkScalarAbs(length);
525 if (absLength == 0.0f) {
526 this->spanZeroRate(span, y);
527 } else if (absLength < (count - 1)) {
528 this->spanSlowRate(span, y);
529 } else if (absLength == (count - 1)) {
530 if (std::fmod(span.startX() - 0.5f, 1.0f) == 0.0f) {
531 if (std::fmod(span.startY() - 0.5f, 1.0f) == 0.0f) {
herb00dd4532016-07-11 10:33:37 -0700532 src_strategy_blend(span, fNext, &fAccessor);
herb7ccbc1a2016-06-09 09:05:00 -0700533 } else {
534 this->spanUnitRateAlignedX(span, y);
535 }
536 } else {
537 this->spanUnitRate(span, y);
538 }
539 } else {
540 this->spanFastRate(span, y);
541 }
542 }
543
544private:
545 void spanZeroRate(Span span, SkScalar y1) {
herb6eff52a2016-03-23 09:00:33 -0700546 SkScalar y0 = span.startY() - 0.5f;
547 y1 += 0.5f;
548 int iy0 = SkScalarFloorToInt(y0);
549 SkScalar filterY1 = y0 - iy0;
550 SkScalar filterY0 = 1.0f - filterY1;
551 int iy1 = SkScalarFloorToInt(y1);
552 int ix = SkScalarFloorToInt(span.startX());
herb00dd4532016-07-11 10:33:37 -0700553 Sk4f pixelY0 = fAccessor.getPixelFromRow(fAccessor.row(iy0), ix);
554 Sk4f pixelY1 = fAccessor.getPixelFromRow(fAccessor.row(iy1), ix);
herb6eff52a2016-03-23 09:00:33 -0700555 Sk4f filterPixel = pixelY0 * filterY0 + pixelY1 * filterY1;
556 int count = span.count();
557 while (count >= 4) {
herb9e0efe52016-04-08 13:25:28 -0700558 fNext->blend4Pixels(filterPixel, filterPixel, filterPixel, filterPixel);
herb6eff52a2016-03-23 09:00:33 -0700559 count -= 4;
560 }
561 while (count > 0) {
herb9e0efe52016-04-08 13:25:28 -0700562 fNext->blendPixel(filterPixel);
herb6eff52a2016-03-23 09:00:33 -0700563 count -= 1;
564 }
565 }
566
567 // When moving through source space more slowly than dst space (zoomed in),
568 // we'll be sampling from the same source pixel more than once.
herb7ccbc1a2016-06-09 09:05:00 -0700569 void spanSlowRate(Span span, SkScalar ry1) {
herb6eff52a2016-03-23 09:00:33 -0700570 SkPoint start;
571 SkScalar length;
572 int count;
573 std::tie(start, length, count) = span;
herbdd404832016-06-08 14:33:15 -0700574 SkFixed fx = SkScalarToFixed(X(start)-0.5f);
herb6eff52a2016-03-23 09:00:33 -0700575
576 SkFixed fdx = SkScalarToFixed(length / (count - 1));
herb6eff52a2016-03-23 09:00:33 -0700577
578 Sk4f xAdjust;
579 if (fdx >= 0) {
580 xAdjust = Sk4f{-1.0f};
581 } else {
582 xAdjust = Sk4f{1.0f};
583 }
584 int ix = SkFixedFloorToInt(fx);
585 int ioldx = ix;
586 Sk4f x{SkFixedToScalar(fx) - ix};
587 Sk4f dx{SkFixedToScalar(fdx)};
588 SkScalar ry0 = Y(start) - 0.5f;
589 ry1 += 0.5f;
590 SkScalar yFloor = std::floor(ry0);
591 Sk4f y1 = Sk4f{ry0 - yFloor};
592 Sk4f y0 = Sk4f{1.0f} - y1;
herb00dd4532016-07-11 10:33:37 -0700593 const void* const row0 = fAccessor.row(SkScalarFloorToInt(ry0));
594 const void* const row1 = fAccessor.row(SkScalarFloorToInt(ry1));
595 Sk4f fpixel00 = y0 * fAccessor.getPixelFromRow(row0, ix);
596 Sk4f fpixel01 = y1 * fAccessor.getPixelFromRow(row1, ix);
597 Sk4f fpixel10 = y0 * fAccessor.getPixelFromRow(row0, ix + 1);
598 Sk4f fpixel11 = y1 * fAccessor.getPixelFromRow(row1, ix + 1);
herb6eff52a2016-03-23 09:00:33 -0700599 auto getNextPixel = [&]() {
600 if (ix != ioldx) {
601 fpixel00 = fpixel10;
602 fpixel01 = fpixel11;
herb00dd4532016-07-11 10:33:37 -0700603 fpixel10 = y0 * fAccessor.getPixelFromRow(row0, ix + 1);
604 fpixel11 = y1 * fAccessor.getPixelFromRow(row1, ix + 1);
herb6eff52a2016-03-23 09:00:33 -0700605 ioldx = ix;
606 x = x + xAdjust;
607 }
608
609 Sk4f x0, x1;
610 x0 = Sk4f{1.0f} - x;
611 x1 = x;
612 Sk4f fpixel = x0 * (fpixel00 + fpixel01) + x1 * (fpixel10 + fpixel11);
613 fx += fdx;
614 ix = SkFixedFloorToInt(fx);
615 x = x + dx;
616 return fpixel;
617 };
618
619 while (count >= 4) {
620 Sk4f fpixel0 = getNextPixel();
621 Sk4f fpixel1 = getNextPixel();
622 Sk4f fpixel2 = getNextPixel();
623 Sk4f fpixel3 = getNextPixel();
624
herb9e0efe52016-04-08 13:25:28 -0700625 fNext->blend4Pixels(fpixel0, fpixel1, fpixel2, fpixel3);
herb6eff52a2016-03-23 09:00:33 -0700626 count -= 4;
627 }
628
629 while (count > 0) {
herb9e0efe52016-04-08 13:25:28 -0700630 fNext->blendPixel(getNextPixel());
herb6eff52a2016-03-23 09:00:33 -0700631
632 count -= 1;
633 }
634 }
635
636 // We're moving through source space at a rate of 1 source pixel per 1 dst pixel.
637 // We'll never re-use pixels, but we can at least load contiguous pixels.
herb7ccbc1a2016-06-09 09:05:00 -0700638 void spanUnitRate(Span span, SkScalar y1) {
herb6eff52a2016-03-23 09:00:33 -0700639 y1 += 0.5f;
640 SkScalar y0 = span.startY() - 0.5f;
641 int iy0 = SkScalarFloorToInt(y0);
642 SkScalar filterY1 = y0 - iy0;
643 SkScalar filterY0 = 1.0f - filterY1;
644 int iy1 = SkScalarFloorToInt(y1);
herb00dd4532016-07-11 10:33:37 -0700645 const void* rowY0 = fAccessor.row(iy0);
646 const void* rowY1 = fAccessor.row(iy1);
herb6eff52a2016-03-23 09:00:33 -0700647 SkScalar x0 = span.startX() - 0.5f;
648 int ix0 = SkScalarFloorToInt(x0);
649 SkScalar filterX1 = x0 - ix0;
650 SkScalar filterX0 = 1.0f - filterX1;
651
652 auto getPixelY0 = [&]() {
herb00dd4532016-07-11 10:33:37 -0700653 Sk4f px = fAccessor.getPixelFromRow(rowY0, ix0);
herb6eff52a2016-03-23 09:00:33 -0700654 return px * filterY0;
655 };
656
657 auto getPixelY1 = [&]() {
herb00dd4532016-07-11 10:33:37 -0700658 Sk4f px = fAccessor.getPixelFromRow(rowY1, ix0);
herb6eff52a2016-03-23 09:00:33 -0700659 return px * filterY1;
660 };
661
662 auto get4PixelsY0 = [&](int ix, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) {
herb00dd4532016-07-11 10:33:37 -0700663 fAccessor.get4Pixels(rowY0, ix, px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700664 *px0 = *px0 * filterY0;
665 *px1 = *px1 * filterY0;
666 *px2 = *px2 * filterY0;
667 *px3 = *px3 * filterY0;
668 };
669
670 auto get4PixelsY1 = [&](int ix, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) {
herb00dd4532016-07-11 10:33:37 -0700671 fAccessor.get4Pixels(rowY1, ix, px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700672 *px0 = *px0 * filterY1;
673 *px1 = *px1 * filterY1;
674 *px2 = *px2 * filterY1;
675 *px3 = *px3 * filterY1;
676 };
677
678 auto lerp = [&](Sk4f& pixelX0, Sk4f& pixelX1) {
679 return pixelX0 * filterX0 + pixelX1 * filterX1;
680 };
681
682 // Mid making 4 unit rate.
683 Sk4f pxB = getPixelY0() + getPixelY1();
684 if (span.length() > 0) {
685 int count = span.count();
686 while (count >= 4) {
687 Sk4f px00, px10, px20, px30;
688 get4PixelsY0(ix0, &px00, &px10, &px20, &px30);
689 Sk4f px01, px11, px21, px31;
690 get4PixelsY1(ix0, &px01, &px11, &px21, &px31);
691 Sk4f pxS0 = px00 + px01;
692 Sk4f px0 = lerp(pxB, pxS0);
693 Sk4f pxS1 = px10 + px11;
694 Sk4f px1 = lerp(pxS0, pxS1);
695 Sk4f pxS2 = px20 + px21;
696 Sk4f px2 = lerp(pxS1, pxS2);
697 Sk4f pxS3 = px30 + px31;
698 Sk4f px3 = lerp(pxS2, pxS3);
699 pxB = pxS3;
herb9e0efe52016-04-08 13:25:28 -0700700 fNext->blend4Pixels(px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700701 ix0 += 4;
702 count -= 4;
703 }
704 while (count > 0) {
herb00dd4532016-07-11 10:33:37 -0700705 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix0);
706 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix0);
herb6eff52a2016-03-23 09:00:33 -0700707
herb9e0efe52016-04-08 13:25:28 -0700708 fNext->blendPixel(lerp(pixelY0, pixelY1));
herb6eff52a2016-03-23 09:00:33 -0700709 ix0 += 1;
710 count -= 1;
711 }
712 } else {
713 int count = span.count();
714 while (count >= 4) {
715 Sk4f px00, px10, px20, px30;
716 get4PixelsY0(ix0 - 3, &px00, &px10, &px20, &px30);
717 Sk4f px01, px11, px21, px31;
718 get4PixelsY1(ix0 - 3, &px01, &px11, &px21, &px31);
719 Sk4f pxS3 = px30 + px31;
720 Sk4f px0 = lerp(pxS3, pxB);
721 Sk4f pxS2 = px20 + px21;
722 Sk4f px1 = lerp(pxS2, pxS3);
723 Sk4f pxS1 = px10 + px11;
724 Sk4f px2 = lerp(pxS1, pxS2);
725 Sk4f pxS0 = px00 + px01;
726 Sk4f px3 = lerp(pxS0, pxS1);
727 pxB = pxS0;
herb9e0efe52016-04-08 13:25:28 -0700728 fNext->blend4Pixels(px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700729 ix0 -= 4;
730 count -= 4;
731 }
732 while (count > 0) {
herb00dd4532016-07-11 10:33:37 -0700733 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix0);
734 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix0);
herb6eff52a2016-03-23 09:00:33 -0700735
herb9e0efe52016-04-08 13:25:28 -0700736 fNext->blendPixel(lerp(pixelY0, pixelY1));
herb6eff52a2016-03-23 09:00:33 -0700737 ix0 -= 1;
738 count -= 1;
739 }
740 }
741 }
742
herb7ccbc1a2016-06-09 09:05:00 -0700743 void spanUnitRateAlignedX(Span span, SkScalar y1) {
herb6eff52a2016-03-23 09:00:33 -0700744 SkScalar y0 = span.startY() - 0.5f;
745 y1 += 0.5f;
746 int iy0 = SkScalarFloorToInt(y0);
747 SkScalar filterY1 = y0 - iy0;
748 SkScalar filterY0 = 1.0f - filterY1;
749 int iy1 = SkScalarFloorToInt(y1);
750 int ix = SkScalarFloorToInt(span.startX());
herb00dd4532016-07-11 10:33:37 -0700751 const void* rowY0 = fAccessor.row(iy0);
752 const void* rowY1 = fAccessor.row(iy1);
herb6eff52a2016-03-23 09:00:33 -0700753 auto lerp = [&](Sk4f* pixelY0, Sk4f* pixelY1) {
754 return *pixelY0 * filterY0 + *pixelY1 * filterY1;
755 };
756
757 if (span.length() > 0) {
758 int count = span.count();
759 while (count >= 4) {
760 Sk4f px00, px10, px20, px30;
herb00dd4532016-07-11 10:33:37 -0700761 fAccessor.get4Pixels(rowY0, ix, &px00, &px10, &px20, &px30);
herb6eff52a2016-03-23 09:00:33 -0700762 Sk4f px01, px11, px21, px31;
herb00dd4532016-07-11 10:33:37 -0700763 fAccessor.get4Pixels(rowY1, ix, &px01, &px11, &px21, &px31);
herb9e0efe52016-04-08 13:25:28 -0700764 fNext->blend4Pixels(
herb6eff52a2016-03-23 09:00:33 -0700765 lerp(&px00, &px01), lerp(&px10, &px11), lerp(&px20, &px21), lerp(&px30, &px31));
766 ix += 4;
767 count -= 4;
768 }
769 while (count > 0) {
herb00dd4532016-07-11 10:33:37 -0700770 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix);
771 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix);
herb6eff52a2016-03-23 09:00:33 -0700772
herb9e0efe52016-04-08 13:25:28 -0700773 fNext->blendPixel(lerp(&pixelY0, &pixelY1));
herb6eff52a2016-03-23 09:00:33 -0700774 ix += 1;
775 count -= 1;
776 }
777 } else {
778 int count = span.count();
779 while (count >= 4) {
780 Sk4f px00, px10, px20, px30;
herb00dd4532016-07-11 10:33:37 -0700781 fAccessor.get4Pixels(rowY0, ix - 3, &px30, &px20, &px10, &px00);
herb6eff52a2016-03-23 09:00:33 -0700782 Sk4f px01, px11, px21, px31;
herb00dd4532016-07-11 10:33:37 -0700783 fAccessor.get4Pixels(rowY1, ix - 3, &px31, &px21, &px11, &px01);
herb9e0efe52016-04-08 13:25:28 -0700784 fNext->blend4Pixels(
herb6eff52a2016-03-23 09:00:33 -0700785 lerp(&px00, &px01), lerp(&px10, &px11), lerp(&px20, &px21), lerp(&px30, &px31));
786 ix -= 4;
787 count -= 4;
788 }
789 while (count > 0) {
herb00dd4532016-07-11 10:33:37 -0700790 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix);
791 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix);
herb6eff52a2016-03-23 09:00:33 -0700792
herb9e0efe52016-04-08 13:25:28 -0700793 fNext->blendPixel(lerp(&pixelY0, &pixelY1));
herb6eff52a2016-03-23 09:00:33 -0700794 ix -= 1;
795 count -= 1;
796 }
797 }
798 }
799
800 // We're moving through source space faster than dst (zoomed out),
801 // so we'll never reuse a source pixel or be able to do contiguous loads.
herb7ccbc1a2016-06-09 09:05:00 -0700802 void spanFastRate(Span span, SkScalar y1) {
herb6eff52a2016-03-23 09:00:33 -0700803 SkPoint start;
804 SkScalar length;
805 int count;
806 std::tie(start, length, count) = span;
807 SkScalar x = X(start);
808 SkScalar y = Y(start);
herb7ccbc1a2016-06-09 09:05:00 -0700809
herbdd404832016-06-08 14:33:15 -0700810 // In this sampler, it is assumed that if span.StartY() and y1 are the same then both
811 // y-lines are on the same tile.
812 if (y == y1) {
813 // Both y-lines are on the same tile.
herb7ccbc1a2016-06-09 09:05:00 -0700814 span_fallback(span, this);
herb6eff52a2016-03-23 09:00:33 -0700815 } else {
herbdd404832016-06-08 14:33:15 -0700816 // The y-lines are on different tiles.
herb6eff52a2016-03-23 09:00:33 -0700817 SkScalar dx = length / (count - 1);
818 Sk4f ys = {y - 0.5f, y - 0.5f, y1 + 0.5f, y1 + 0.5f};
819 while (count > 0) {
820 Sk4f xs = Sk4f{-0.5f, 0.5f, -0.5f, 0.5f} + Sk4f{x};
821 this->bilerpEdge(xs, ys);
822 x += dx;
823 count -= 1;
824 }
825 }
826 }
827
herb00dd4532016-07-11 10:33:37 -0700828 Next* const fNext;
829 Accessor fAccessor;
herb6eff52a2016-03-23 09:00:33 -0700830};
831
herb6eff52a2016-03-23 09:00:33 -0700832} // namespace
833
834#endif // SkLinearBitmapPipeline_sampler_DEFINED