blob: 39400f67500bc95986135123d5ffe3970098e54e [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>
herb00dd4532016-07-11 10:33:37 -070080class PixelConverter<kRGB_565_SkColorType, gammaType> {
herb670f01f2016-05-13 10:04:46 -070081public:
82 using Element = uint16_t;
herb00dd4532016-07-11 10:33:37 -070083 PixelConverter(const SkPixmap& srcPixmap) { }
herb670f01f2016-05-13 10:04:46 -070084
herb00dd4532016-07-11 10:33:37 -070085 Sk4f toSk4f(Element pixel) const {
86 SkPMColor pixel32 = SkPixel16ToPixel32(pixel);
87 return gammaType == kSRGB_SkGammaType
88 ? Sk4f_fromS32(pixel32)
89 : Sk4f_fromL32(pixel32);
90 }
91};
92
93template <SkGammaType gammaType>
94class PixelConverter<kARGB_4444_SkColorType, gammaType> {
95public:
96 using Element = uint16_t;
97 PixelConverter(const SkPixmap& srcPixmap) { }
98
99 Sk4f toSk4f(Element pixel) const {
100 SkPMColor pixel32 = SkPixel4444ToPixel32(pixel);
101 return gammaType == kSRGB_SkGammaType
102 ? Sk4f_fromS32(pixel32)
103 : Sk4f_fromL32(pixel32);
104 }
105};
106
107template <SkGammaType gammaType>
108class PixelConverter<kRGBA_8888_SkColorType, gammaType> {
109public:
110 using Element = uint32_t;
111 PixelConverter(const SkPixmap& srcPixmap) { }
112
113 Sk4f toSk4f(Element pixel) const {
reeddabe5d32016-06-21 10:28:14 -0700114 return gammaType == kSRGB_SkGammaType
herb670f01f2016-05-13 10:04:46 -0700115 ? Sk4f_fromS32(pixel)
116 : Sk4f_fromL32(pixel);
117 }
118};
119
reeddabe5d32016-06-21 10:28:14 -0700120template <SkGammaType gammaType>
herb00dd4532016-07-11 10:33:37 -0700121class PixelConverter<kBGRA_8888_SkColorType, gammaType> {
herb15332a82016-05-12 11:37:00 -0700122public:
123 using Element = uint32_t;
herb00dd4532016-07-11 10:33:37 -0700124 PixelConverter(const SkPixmap& srcPixmap) { }
herb15332a82016-05-12 11:37:00 -0700125
herb00dd4532016-07-11 10:33:37 -0700126 Sk4f toSk4f(Element pixel) const {
127 return swizzle_rb(
128 gammaType == kSRGB_SkGammaType ? Sk4f_fromS32(pixel) : Sk4f_fromL32(pixel));
herb15332a82016-05-12 11:37:00 -0700129 }
130};
131
reeddabe5d32016-06-21 10:28:14 -0700132template <SkGammaType gammaType>
herb00dd4532016-07-11 10:33:37 -0700133class PixelConverter<kIndex_8_SkColorType, gammaType> {
herb15332a82016-05-12 11:37:00 -0700134public:
135 using Element = uint8_t;
herb00dd4532016-07-11 10:33:37 -0700136 PixelConverter(const SkPixmap& srcPixmap) {
herb15332a82016-05-12 11:37:00 -0700137 SkColorTable* skColorTable = srcPixmap.ctable();
138 SkASSERT(skColorTable != nullptr);
139
140 fColorTable = (Sk4f*)SkAlign16((intptr_t)fColorTableStorage.get());
141 for (int i = 0; i < skColorTable->count(); i++) {
142 fColorTable[i] = this->convertPixel((*skColorTable)[i]);
143 }
144 }
145
herb00dd4532016-07-11 10:33:37 -0700146 PixelConverter(const PixelConverter& strategy) {
herb15332a82016-05-12 11:37:00 -0700147 fColorTable = (Sk4f*)SkAlign16((intptr_t)fColorTableStorage.get());
148 // TODO: figure out the count.
149 for (int i = 0; i < 256; i++) {
150 fColorTable[i] = strategy.fColorTable[i];
151 }
152 }
153
herb00dd4532016-07-11 10:33:37 -0700154 Sk4f toSk4f(Element index) const {
155 return fColorTable[index];
herb15332a82016-05-12 11:37:00 -0700156 }
157
158private:
159 static const size_t kColorTableSize = sizeof(Sk4f[256]) + 12;
160 Sk4f convertPixel(SkPMColor pmColor) {
161 Sk4f pixel = to_4f(pmColor);
162 float alpha = get_alpha(pixel);
163 if (alpha != 0.0f) {
164 float invAlpha = 1.0f / alpha;
165 Sk4f normalize = {invAlpha, invAlpha, invAlpha, 1.0f / 255.0f};
166 pixel = pixel * normalize;
reeddabe5d32016-06-21 10:28:14 -0700167 if (gammaType == kSRGB_SkGammaType) {
herb15332a82016-05-12 11:37:00 -0700168 pixel = linear_to_srgb(pixel);
169 }
170 return pixel;
171 } else {
172 return Sk4f{0.0f};
173 }
174 }
175 SkAutoMalloc fColorTableStorage{kColorTableSize};
176 Sk4f* fColorTable;
177};
178
reeddabe5d32016-06-21 10:28:14 -0700179template <SkGammaType gammaType>
herb00dd4532016-07-11 10:33:37 -0700180class PixelConverter<kGray_8_SkColorType, gammaType> {
herb670f01f2016-05-13 10:04:46 -0700181public:
182 using Element = uint8_t;
herb00dd4532016-07-11 10:33:37 -0700183 PixelConverter(const SkPixmap& srcPixmap) { }
herb670f01f2016-05-13 10:04:46 -0700184
herb00dd4532016-07-11 10:33:37 -0700185 Sk4f toSk4f(Element pixel) const {
186 float gray = pixel * (1.0f/255.0f);
187 Sk4f result = Sk4f{gray, gray, gray, 1.0f};
reeddabe5d32016-06-21 10:28:14 -0700188 return gammaType == kSRGB_SkGammaType
herb00dd4532016-07-11 10:33:37 -0700189 ? srgb_to_linear(result)
190 : result;
herb670f01f2016-05-13 10:04:46 -0700191 }
192};
193
herb15332a82016-05-12 11:37:00 -0700194template <>
herb00dd4532016-07-11 10:33:37 -0700195class PixelConverter<kRGBA_F16_SkColorType, kLinear_SkGammaType> {
herb15332a82016-05-12 11:37:00 -0700196public:
197 using Element = uint64_t;
herb00dd4532016-07-11 10:33:37 -0700198 PixelConverter(const SkPixmap& srcPixmap) { }
herb15332a82016-05-12 11:37:00 -0700199
herb00dd4532016-07-11 10:33:37 -0700200 Sk4f toSk4f(const Element pixel) const {
201 return SkHalfToFloat_01(pixel);
herb15332a82016-05-12 11:37:00 -0700202 }
203};
204
herb00dd4532016-07-11 10:33:37 -0700205class PixelAccessorShim {
206public:
207 explicit PixelAccessorShim(SkLinearBitmapPipeline::PixelAccessorInterface* accessor)
208 : fPixelAccessor(accessor) { }
209
210 void SK_VECTORCALL getFewPixels(
211 int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) const {
212 fPixelAccessor->getFewPixels(n, xs, ys, px0, px1, px2);
213 }
214
215 void SK_VECTORCALL get4Pixels(
216 Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const {
217 fPixelAccessor->get4Pixels(xs, ys, px0, px1, px2, px3);
218 }
219
220 void get4Pixels(
221 const void* src, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const {
222 fPixelAccessor->get4Pixels(src, index, px0, px1, px2, px3);
223 };
224
225 Sk4f getPixelFromRow(const void* row, int index) const {
226 return fPixelAccessor->getPixelFromRow(row, index);
227 }
228
229 Sk4f getPixelAt(int index) const {
230 return fPixelAccessor->getPixelAt(index);
231 }
232
233 const void* row(int y) const {
234 return fPixelAccessor->row(y);
235 }
236
237private:
238 SkLinearBitmapPipeline::PixelAccessorInterface* const fPixelAccessor;
239};
240
herb15332a82016-05-12 11:37:00 -0700241////////////////////////////////////////////////////////////////////////////////////////////////////
242// PixelAccessor handles all the same plumbing for all the PixelGetters.
reeddabe5d32016-06-21 10:28:14 -0700243template <SkColorType colorType, SkGammaType gammaType>
herb00dd4532016-07-11 10:33:37 -0700244class PixelAccessor final : public SkLinearBitmapPipeline::PixelAccessorInterface {
245 using Element = typename PixelConverter<colorType, gammaType>::Element;
herb15332a82016-05-12 11:37:00 -0700246public:
herb670f01f2016-05-13 10:04:46 -0700247 template <typename... Args>
248 PixelAccessor(const SkPixmap& srcPixmap, Args&&... args)
herb15332a82016-05-12 11:37:00 -0700249 : fSrc{static_cast<const Element*>(srcPixmap.addr())}
250 , fWidth{srcPixmap.rowBytesAsPixels()}
herb00dd4532016-07-11 10:33:37 -0700251 , fConverter{srcPixmap, std::move<Args>(args)...} { }
herb15332a82016-05-12 11:37:00 -0700252
herb00dd4532016-07-11 10:33:37 -0700253 void SK_VECTORCALL getFewPixels (
254 int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) const override {
herb15332a82016-05-12 11:37:00 -0700255 Sk4i XIs = SkNx_cast<int, SkScalar>(xs);
256 Sk4i YIs = SkNx_cast<int, SkScalar>(ys);
257 Sk4i bufferLoc = YIs * fWidth + XIs;
258 switch (n) {
259 case 3:
260 *px2 = this->getPixelAt(bufferLoc[2]);
261 case 2:
262 *px1 = this->getPixelAt(bufferLoc[1]);
263 case 1:
264 *px0 = this->getPixelAt(bufferLoc[0]);
265 default:
266 break;
267 }
268 }
269
herb00dd4532016-07-11 10:33:37 -0700270 void SK_VECTORCALL get4Pixels(
271 Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const override {
herb15332a82016-05-12 11:37:00 -0700272 Sk4i XIs = SkNx_cast<int, SkScalar>(xs);
273 Sk4i YIs = SkNx_cast<int, SkScalar>(ys);
274 Sk4i bufferLoc = YIs * fWidth + XIs;
275 *px0 = this->getPixelAt(bufferLoc[0]);
276 *px1 = this->getPixelAt(bufferLoc[1]);
277 *px2 = this->getPixelAt(bufferLoc[2]);
278 *px3 = this->getPixelAt(bufferLoc[3]);
279 }
280
herb00dd4532016-07-11 10:33:37 -0700281 void get4Pixels(
282 const void* src, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const override {
herb15332a82016-05-12 11:37:00 -0700283 *px0 = this->getPixelFromRow(src, index + 0);
284 *px1 = this->getPixelFromRow(src, index + 1);
285 *px2 = this->getPixelFromRow(src, index + 2);
286 *px3 = this->getPixelFromRow(src, index + 3);
287 }
288
herb00dd4532016-07-11 10:33:37 -0700289 Sk4f getPixelFromRow(const void* row, int index) const override {
herb15332a82016-05-12 11:37:00 -0700290 const Element* src = static_cast<const Element*>(row);
herb00dd4532016-07-11 10:33:37 -0700291 return fConverter.toSk4f(src[index]);
herb15332a82016-05-12 11:37:00 -0700292 }
293
herb00dd4532016-07-11 10:33:37 -0700294 Sk4f getPixelAt(int index) const override {
herb15332a82016-05-12 11:37:00 -0700295 return this->getPixelFromRow(fSrc, index);
296 }
297
herb00dd4532016-07-11 10:33:37 -0700298 const void* row(int y) const override { return fSrc + y * fWidth; }
herb15332a82016-05-12 11:37:00 -0700299
300private:
301 const Element* const fSrc;
herb00dd4532016-07-11 10:33:37 -0700302 const int fWidth;
303 PixelConverter<colorType, gammaType> fConverter;
herb15332a82016-05-12 11:37:00 -0700304};
305
herb7ccbc1a2016-06-09 09:05:00 -0700306// We're moving through source space at a rate of 1 source pixel per 1 dst pixel.
307// We'll never re-use pixels, but we can at least load contiguous pixels.
308template <typename Next, typename Strategy>
309static void src_strategy_blend(Span span, Next* next, Strategy* strategy) {
310 SkPoint start;
311 SkScalar length;
312 int count;
313 std::tie(start, length, count) = span;
314 int ix = SkScalarFloorToInt(X(start));
315 const void* row = strategy->row((int)std::floor(Y(start)));
316 if (length > 0) {
317 while (count >= 4) {
318 Sk4f px0, px1, px2, px3;
319 strategy->get4Pixels(row, ix, &px0, &px1, &px2, &px3);
320 next->blend4Pixels(px0, px1, px2, px3);
321 ix += 4;
322 count -= 4;
323 }
324
325 while (count > 0) {
326 next->blendPixel(strategy->getPixelFromRow(row, ix));
327 ix += 1;
328 count -= 1;
329 }
330 } else {
331 while (count >= 4) {
332 Sk4f px0, px1, px2, px3;
333 strategy->get4Pixels(row, ix - 3, &px3, &px2, &px1, &px0);
334 next->blend4Pixels(px0, px1, px2, px3);
335 ix -= 4;
336 count -= 4;
337 }
338
339 while (count > 0) {
340 next->blendPixel(strategy->getPixelFromRow(row, ix));
341 ix -= 1;
342 count -= 1;
343 }
344 }
345}
346
347// NearestNeighborSampler - use nearest neighbor filtering to create runs of destination pixels.
herb00dd4532016-07-11 10:33:37 -0700348template<typename Accessor, typename Next>
herb7ccbc1a2016-06-09 09:05:00 -0700349class NearestNeighborSampler : public SkLinearBitmapPipeline::SampleProcessorInterface {
herb6eff52a2016-03-23 09:00:33 -0700350public:
351 template<typename... Args>
herb7ccbc1a2016-06-09 09:05:00 -0700352 NearestNeighborSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next, Args&& ... args)
herb00dd4532016-07-11 10:33:37 -0700353 : fNext{next}, fAccessor{std::forward<Args>(args)...} { }
herb6eff52a2016-03-23 09:00:33 -0700354
herb7ccbc1a2016-06-09 09:05:00 -0700355 NearestNeighborSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next,
356 const NearestNeighborSampler& sampler)
herb00dd4532016-07-11 10:33:37 -0700357 : fNext{next}, fAccessor{sampler.fAccessor} { }
herb9e0efe52016-04-08 13:25:28 -0700358
mtkleine5fb9c82016-07-07 08:12:09 -0700359 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
herb6eff52a2016-03-23 09:00:33 -0700360 SkASSERT(0 < n && n < 4);
361 Sk4f px0, px1, px2;
herb00dd4532016-07-11 10:33:37 -0700362 fAccessor.getFewPixels(n, xs, ys, &px0, &px1, &px2);
herb9e0efe52016-04-08 13:25:28 -0700363 if (n >= 1) fNext->blendPixel(px0);
364 if (n >= 2) fNext->blendPixel(px1);
365 if (n >= 3) fNext->blendPixel(px2);
herb6eff52a2016-03-23 09:00:33 -0700366 }
367
mtkleine5fb9c82016-07-07 08:12:09 -0700368 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
herb6eff52a2016-03-23 09:00:33 -0700369 Sk4f px0, px1, px2, px3;
herb00dd4532016-07-11 10:33:37 -0700370 fAccessor.get4Pixels(xs, ys, &px0, &px1, &px2, &px3);
herb9e0efe52016-04-08 13:25:28 -0700371 fNext->blend4Pixels(px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700372 }
373
herb7ccbc1a2016-06-09 09:05:00 -0700374 void pointSpan(Span span) override {
herb6eff52a2016-03-23 09:00:33 -0700375 SkASSERT(!span.isEmpty());
376 SkPoint start;
377 SkScalar length;
378 int count;
379 std::tie(start, length, count) = span;
380 SkScalar absLength = SkScalarAbs(length);
381 if (absLength < (count - 1)) {
herb7ccbc1a2016-06-09 09:05:00 -0700382 this->spanSlowRate(span);
herb6eff52a2016-03-23 09:00:33 -0700383 } else if (absLength == (count - 1)) {
herb00dd4532016-07-11 10:33:37 -0700384 src_strategy_blend(span, fNext, &fAccessor);
herb6eff52a2016-03-23 09:00:33 -0700385 } else {
herb7ccbc1a2016-06-09 09:05:00 -0700386 this->spanFastRate(span);
herb6eff52a2016-03-23 09:00:33 -0700387 }
388 }
389
herb7ccbc1a2016-06-09 09:05:00 -0700390 void repeatSpan(Span span, int32_t repeatCount) override {
391 while (repeatCount > 0) {
392 this->pointSpan(span);
393 repeatCount--;
herb6eff52a2016-03-23 09:00:33 -0700394 }
395 }
396
mtkleine5fb9c82016-07-07 08:12:09 -0700397 void SK_VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override {
herb7ccbc1a2016-06-09 09:05:00 -0700398 SkFAIL("Using nearest neighbor sampler, but calling a bilerpEdge.");
399 }
400
401 void bilerpSpan(Span span, SkScalar y) override {
402 SkFAIL("Using nearest neighbor sampler, but calling a bilerpSpan.");
403 }
404
herb6eff52a2016-03-23 09:00:33 -0700405private:
406 // When moving through source space more slowly than dst space (zoomed in),
407 // we'll be sampling from the same source pixel more than once.
herb7ccbc1a2016-06-09 09:05:00 -0700408 void spanSlowRate(Span span) {
herb6eff52a2016-03-23 09:00:33 -0700409 SkPoint start;
410 SkScalar length;
411 int count;
412 std::tie(start, length, count) = span;
413 SkScalar x = X(start);
414 SkFixed fx = SkScalarToFixed(x);
415 SkScalar dx = length / (count - 1);
416 SkFixed fdx = SkScalarToFixed(dx);
417
herb00dd4532016-07-11 10:33:37 -0700418 const void* row = fAccessor.row((int)std::floor(Y(start)));
herb6eff52a2016-03-23 09:00:33 -0700419 Next* next = fNext;
420
421 int ix = SkFixedFloorToInt(fx);
422 int prevIX = ix;
herb00dd4532016-07-11 10:33:37 -0700423 Sk4f fpixel = fAccessor.getPixelFromRow(row, ix);
herb6eff52a2016-03-23 09:00:33 -0700424
425 // When dx is less than one, each pixel is used more than once. Using the fixed point fx
426 // allows the code to quickly check that the same pixel is being used. The code uses this
427 // same pixel check to do the sRGB and normalization only once.
428 auto getNextPixel = [&]() {
429 if (ix != prevIX) {
herb00dd4532016-07-11 10:33:37 -0700430 fpixel = fAccessor.getPixelFromRow(row, ix);
herb6eff52a2016-03-23 09:00:33 -0700431 prevIX = ix;
432 }
433 fx += fdx;
434 ix = SkFixedFloorToInt(fx);
435 return fpixel;
436 };
437
438 while (count >= 4) {
439 Sk4f px0 = getNextPixel();
440 Sk4f px1 = getNextPixel();
441 Sk4f px2 = getNextPixel();
442 Sk4f px3 = getNextPixel();
herb9e0efe52016-04-08 13:25:28 -0700443 next->blend4Pixels(px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700444 count -= 4;
445 }
446 while (count > 0) {
herb9e0efe52016-04-08 13:25:28 -0700447 next->blendPixel(getNextPixel());
herb6eff52a2016-03-23 09:00:33 -0700448 count -= 1;
449 }
450 }
451
452 // We're moving through source space at a rate of 1 source pixel per 1 dst pixel.
453 // We'll never re-use pixels, but we can at least load contiguous pixels.
herb7ccbc1a2016-06-09 09:05:00 -0700454 void spanUnitRate(Span span) {
herb00dd4532016-07-11 10:33:37 -0700455 src_strategy_blend(span, fNext, &fAccessor);
herb6eff52a2016-03-23 09:00:33 -0700456 }
457
458 // We're moving through source space faster than dst (zoomed out),
459 // so we'll never reuse a source pixel or be able to do contiguous loads.
herb7ccbc1a2016-06-09 09:05:00 -0700460 void spanFastRate(Span span) {
461 span_fallback(span, this);
herb6eff52a2016-03-23 09:00:33 -0700462 }
463
herb00dd4532016-07-11 10:33:37 -0700464 Next* const fNext;
465 Accessor fAccessor;
herb7ccbc1a2016-06-09 09:05:00 -0700466};
467
herb7df9e4a2016-06-10 13:01:27 -0700468// -- BilerpSampler --------------------------------------------------------------------------------
herb7ccbc1a2016-06-09 09:05:00 -0700469// BilerpSampler - use a bilerp filter to create runs of destination pixels.
herb00dd4532016-07-11 10:33:37 -0700470template<typename Accessor, typename Next>
herb7ccbc1a2016-06-09 09:05:00 -0700471class BilerpSampler : public SkLinearBitmapPipeline::SampleProcessorInterface {
472public:
473 template<typename... Args>
474 BilerpSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next, Args&& ... args)
herb00dd4532016-07-11 10:33:37 -0700475 : fNext{next}, fAccessor{std::forward<Args>(args)...} { }
herb7ccbc1a2016-06-09 09:05:00 -0700476
477 BilerpSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next,
478 const BilerpSampler& sampler)
herb00dd4532016-07-11 10:33:37 -0700479 : fNext{next}, fAccessor{sampler.fAccessor} { }
herb7ccbc1a2016-06-09 09:05:00 -0700480
481 Sk4f bilerpNonEdgePixel(SkScalar x, SkScalar y) {
482 Sk4f px00, px10, px01, px11;
483
484 // bilerp4() expects xs, ys are the top-lefts of the 2x2 kernel.
485 Sk4f xs = Sk4f{x} - 0.5f;
486 Sk4f ys = Sk4f{y} - 0.5f;
487 Sk4f sampleXs = xs + Sk4f{0.0f, 1.0f, 0.0f, 1.0f};
488 Sk4f sampleYs = ys + Sk4f{0.0f, 0.0f, 1.0f, 1.0f};
herb00dd4532016-07-11 10:33:37 -0700489 fAccessor.get4Pixels(sampleXs, sampleYs, &px00, &px10, &px01, &px11);
herb7ccbc1a2016-06-09 09:05:00 -0700490 return bilerp4(xs, ys, px00, px10, px01, px11);
491 }
492
mtkleine5fb9c82016-07-07 08:12:09 -0700493 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
herb7ccbc1a2016-06-09 09:05:00 -0700494 SkASSERT(0 < n && n < 4);
495 auto bilerpPixel = [&](int index) {
496 return this->bilerpNonEdgePixel(xs[index], ys[index]);
497 };
498
499 if (n >= 1) fNext->blendPixel(bilerpPixel(0));
500 if (n >= 2) fNext->blendPixel(bilerpPixel(1));
501 if (n >= 3) fNext->blendPixel(bilerpPixel(2));
502 }
503
mtkleine5fb9c82016-07-07 08:12:09 -0700504 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
herb7ccbc1a2016-06-09 09:05:00 -0700505 auto bilerpPixel = [&](int index) {
506 return this->bilerpNonEdgePixel(xs[index], ys[index]);
507 };
508 fNext->blend4Pixels(bilerpPixel(0), bilerpPixel(1), bilerpPixel(2), bilerpPixel(3));
509 }
510
511 void pointSpan(Span span) override {
512 this->bilerpSpan(span, span.startY());
513 }
514
515 void repeatSpan(Span span, int32_t repeatCount) override {
516 while (repeatCount > 0) {
517 this->pointSpan(span);
518 repeatCount--;
519 }
520 }
521
mtkleine5fb9c82016-07-07 08:12:09 -0700522 void SK_VECTORCALL bilerpEdge(Sk4s sampleXs, Sk4s sampleYs) override {
herb7ccbc1a2016-06-09 09:05:00 -0700523 Sk4f px00, px10, px01, px11;
524 Sk4f xs = Sk4f{sampleXs[0]};
525 Sk4f ys = Sk4f{sampleYs[0]};
herb00dd4532016-07-11 10:33:37 -0700526 fAccessor.get4Pixels(sampleXs, sampleYs, &px00, &px10, &px01, &px11);
herb7ccbc1a2016-06-09 09:05:00 -0700527 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11);
528 fNext->blendPixel(pixel);
529 }
530
531 void bilerpSpan(Span span, SkScalar y) override {
532 SkASSERT(!span.isEmpty());
533 SkPoint start;
534 SkScalar length;
535 int count;
536 std::tie(start, length, count) = span;
537 SkScalar absLength = SkScalarAbs(length);
538 if (absLength == 0.0f) {
539 this->spanZeroRate(span, y);
540 } else if (absLength < (count - 1)) {
541 this->spanSlowRate(span, y);
542 } else if (absLength == (count - 1)) {
543 if (std::fmod(span.startX() - 0.5f, 1.0f) == 0.0f) {
544 if (std::fmod(span.startY() - 0.5f, 1.0f) == 0.0f) {
herb00dd4532016-07-11 10:33:37 -0700545 src_strategy_blend(span, fNext, &fAccessor);
herb7ccbc1a2016-06-09 09:05:00 -0700546 } else {
547 this->spanUnitRateAlignedX(span, y);
548 }
549 } else {
550 this->spanUnitRate(span, y);
551 }
552 } else {
553 this->spanFastRate(span, y);
554 }
555 }
556
557private:
558 void spanZeroRate(Span span, SkScalar y1) {
herb6eff52a2016-03-23 09:00:33 -0700559 SkScalar y0 = span.startY() - 0.5f;
560 y1 += 0.5f;
561 int iy0 = SkScalarFloorToInt(y0);
562 SkScalar filterY1 = y0 - iy0;
563 SkScalar filterY0 = 1.0f - filterY1;
564 int iy1 = SkScalarFloorToInt(y1);
565 int ix = SkScalarFloorToInt(span.startX());
herb00dd4532016-07-11 10:33:37 -0700566 Sk4f pixelY0 = fAccessor.getPixelFromRow(fAccessor.row(iy0), ix);
567 Sk4f pixelY1 = fAccessor.getPixelFromRow(fAccessor.row(iy1), ix);
herb6eff52a2016-03-23 09:00:33 -0700568 Sk4f filterPixel = pixelY0 * filterY0 + pixelY1 * filterY1;
569 int count = span.count();
570 while (count >= 4) {
herb9e0efe52016-04-08 13:25:28 -0700571 fNext->blend4Pixels(filterPixel, filterPixel, filterPixel, filterPixel);
herb6eff52a2016-03-23 09:00:33 -0700572 count -= 4;
573 }
574 while (count > 0) {
herb9e0efe52016-04-08 13:25:28 -0700575 fNext->blendPixel(filterPixel);
herb6eff52a2016-03-23 09:00:33 -0700576 count -= 1;
577 }
578 }
579
580 // When moving through source space more slowly than dst space (zoomed in),
581 // we'll be sampling from the same source pixel more than once.
herb7ccbc1a2016-06-09 09:05:00 -0700582 void spanSlowRate(Span span, SkScalar ry1) {
herb6eff52a2016-03-23 09:00:33 -0700583 SkPoint start;
584 SkScalar length;
585 int count;
586 std::tie(start, length, count) = span;
herbdd404832016-06-08 14:33:15 -0700587 SkFixed fx = SkScalarToFixed(X(start)-0.5f);
herb6eff52a2016-03-23 09:00:33 -0700588
589 SkFixed fdx = SkScalarToFixed(length / (count - 1));
herb6eff52a2016-03-23 09:00:33 -0700590
591 Sk4f xAdjust;
592 if (fdx >= 0) {
593 xAdjust = Sk4f{-1.0f};
594 } else {
595 xAdjust = Sk4f{1.0f};
596 }
597 int ix = SkFixedFloorToInt(fx);
598 int ioldx = ix;
599 Sk4f x{SkFixedToScalar(fx) - ix};
600 Sk4f dx{SkFixedToScalar(fdx)};
601 SkScalar ry0 = Y(start) - 0.5f;
602 ry1 += 0.5f;
603 SkScalar yFloor = std::floor(ry0);
604 Sk4f y1 = Sk4f{ry0 - yFloor};
605 Sk4f y0 = Sk4f{1.0f} - y1;
herb00dd4532016-07-11 10:33:37 -0700606 const void* const row0 = fAccessor.row(SkScalarFloorToInt(ry0));
607 const void* const row1 = fAccessor.row(SkScalarFloorToInt(ry1));
608 Sk4f fpixel00 = y0 * fAccessor.getPixelFromRow(row0, ix);
609 Sk4f fpixel01 = y1 * fAccessor.getPixelFromRow(row1, ix);
610 Sk4f fpixel10 = y0 * fAccessor.getPixelFromRow(row0, ix + 1);
611 Sk4f fpixel11 = y1 * fAccessor.getPixelFromRow(row1, ix + 1);
herb6eff52a2016-03-23 09:00:33 -0700612 auto getNextPixel = [&]() {
613 if (ix != ioldx) {
614 fpixel00 = fpixel10;
615 fpixel01 = fpixel11;
herb00dd4532016-07-11 10:33:37 -0700616 fpixel10 = y0 * fAccessor.getPixelFromRow(row0, ix + 1);
617 fpixel11 = y1 * fAccessor.getPixelFromRow(row1, ix + 1);
herb6eff52a2016-03-23 09:00:33 -0700618 ioldx = ix;
619 x = x + xAdjust;
620 }
621
622 Sk4f x0, x1;
623 x0 = Sk4f{1.0f} - x;
624 x1 = x;
625 Sk4f fpixel = x0 * (fpixel00 + fpixel01) + x1 * (fpixel10 + fpixel11);
626 fx += fdx;
627 ix = SkFixedFloorToInt(fx);
628 x = x + dx;
629 return fpixel;
630 };
631
632 while (count >= 4) {
633 Sk4f fpixel0 = getNextPixel();
634 Sk4f fpixel1 = getNextPixel();
635 Sk4f fpixel2 = getNextPixel();
636 Sk4f fpixel3 = getNextPixel();
637
herb9e0efe52016-04-08 13:25:28 -0700638 fNext->blend4Pixels(fpixel0, fpixel1, fpixel2, fpixel3);
herb6eff52a2016-03-23 09:00:33 -0700639 count -= 4;
640 }
641
642 while (count > 0) {
herb9e0efe52016-04-08 13:25:28 -0700643 fNext->blendPixel(getNextPixel());
herb6eff52a2016-03-23 09:00:33 -0700644
645 count -= 1;
646 }
647 }
648
649 // We're moving through source space at a rate of 1 source pixel per 1 dst pixel.
650 // We'll never re-use pixels, but we can at least load contiguous pixels.
herb7ccbc1a2016-06-09 09:05:00 -0700651 void spanUnitRate(Span span, SkScalar y1) {
herb6eff52a2016-03-23 09:00:33 -0700652 y1 += 0.5f;
653 SkScalar y0 = span.startY() - 0.5f;
654 int iy0 = SkScalarFloorToInt(y0);
655 SkScalar filterY1 = y0 - iy0;
656 SkScalar filterY0 = 1.0f - filterY1;
657 int iy1 = SkScalarFloorToInt(y1);
herb00dd4532016-07-11 10:33:37 -0700658 const void* rowY0 = fAccessor.row(iy0);
659 const void* rowY1 = fAccessor.row(iy1);
herb6eff52a2016-03-23 09:00:33 -0700660 SkScalar x0 = span.startX() - 0.5f;
661 int ix0 = SkScalarFloorToInt(x0);
662 SkScalar filterX1 = x0 - ix0;
663 SkScalar filterX0 = 1.0f - filterX1;
664
665 auto getPixelY0 = [&]() {
herb00dd4532016-07-11 10:33:37 -0700666 Sk4f px = fAccessor.getPixelFromRow(rowY0, ix0);
herb6eff52a2016-03-23 09:00:33 -0700667 return px * filterY0;
668 };
669
670 auto getPixelY1 = [&]() {
herb00dd4532016-07-11 10:33:37 -0700671 Sk4f px = fAccessor.getPixelFromRow(rowY1, ix0);
herb6eff52a2016-03-23 09:00:33 -0700672 return px * filterY1;
673 };
674
675 auto get4PixelsY0 = [&](int ix, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) {
herb00dd4532016-07-11 10:33:37 -0700676 fAccessor.get4Pixels(rowY0, ix, px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700677 *px0 = *px0 * filterY0;
678 *px1 = *px1 * filterY0;
679 *px2 = *px2 * filterY0;
680 *px3 = *px3 * filterY0;
681 };
682
683 auto get4PixelsY1 = [&](int ix, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) {
herb00dd4532016-07-11 10:33:37 -0700684 fAccessor.get4Pixels(rowY1, ix, px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700685 *px0 = *px0 * filterY1;
686 *px1 = *px1 * filterY1;
687 *px2 = *px2 * filterY1;
688 *px3 = *px3 * filterY1;
689 };
690
691 auto lerp = [&](Sk4f& pixelX0, Sk4f& pixelX1) {
692 return pixelX0 * filterX0 + pixelX1 * filterX1;
693 };
694
695 // Mid making 4 unit rate.
696 Sk4f pxB = getPixelY0() + getPixelY1();
697 if (span.length() > 0) {
698 int count = span.count();
699 while (count >= 4) {
700 Sk4f px00, px10, px20, px30;
701 get4PixelsY0(ix0, &px00, &px10, &px20, &px30);
702 Sk4f px01, px11, px21, px31;
703 get4PixelsY1(ix0, &px01, &px11, &px21, &px31);
704 Sk4f pxS0 = px00 + px01;
705 Sk4f px0 = lerp(pxB, pxS0);
706 Sk4f pxS1 = px10 + px11;
707 Sk4f px1 = lerp(pxS0, pxS1);
708 Sk4f pxS2 = px20 + px21;
709 Sk4f px2 = lerp(pxS1, pxS2);
710 Sk4f pxS3 = px30 + px31;
711 Sk4f px3 = lerp(pxS2, pxS3);
712 pxB = pxS3;
herb9e0efe52016-04-08 13:25:28 -0700713 fNext->blend4Pixels(px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700714 ix0 += 4;
715 count -= 4;
716 }
717 while (count > 0) {
herb00dd4532016-07-11 10:33:37 -0700718 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix0);
719 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix0);
herb6eff52a2016-03-23 09:00:33 -0700720
herb9e0efe52016-04-08 13:25:28 -0700721 fNext->blendPixel(lerp(pixelY0, pixelY1));
herb6eff52a2016-03-23 09:00:33 -0700722 ix0 += 1;
723 count -= 1;
724 }
725 } else {
726 int count = span.count();
727 while (count >= 4) {
728 Sk4f px00, px10, px20, px30;
729 get4PixelsY0(ix0 - 3, &px00, &px10, &px20, &px30);
730 Sk4f px01, px11, px21, px31;
731 get4PixelsY1(ix0 - 3, &px01, &px11, &px21, &px31);
732 Sk4f pxS3 = px30 + px31;
733 Sk4f px0 = lerp(pxS3, pxB);
734 Sk4f pxS2 = px20 + px21;
735 Sk4f px1 = lerp(pxS2, pxS3);
736 Sk4f pxS1 = px10 + px11;
737 Sk4f px2 = lerp(pxS1, pxS2);
738 Sk4f pxS0 = px00 + px01;
739 Sk4f px3 = lerp(pxS0, pxS1);
740 pxB = pxS0;
herb9e0efe52016-04-08 13:25:28 -0700741 fNext->blend4Pixels(px0, px1, px2, px3);
herb6eff52a2016-03-23 09:00:33 -0700742 ix0 -= 4;
743 count -= 4;
744 }
745 while (count > 0) {
herb00dd4532016-07-11 10:33:37 -0700746 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix0);
747 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix0);
herb6eff52a2016-03-23 09:00:33 -0700748
herb9e0efe52016-04-08 13:25:28 -0700749 fNext->blendPixel(lerp(pixelY0, pixelY1));
herb6eff52a2016-03-23 09:00:33 -0700750 ix0 -= 1;
751 count -= 1;
752 }
753 }
754 }
755
herb7ccbc1a2016-06-09 09:05:00 -0700756 void spanUnitRateAlignedX(Span span, SkScalar y1) {
herb6eff52a2016-03-23 09:00:33 -0700757 SkScalar y0 = span.startY() - 0.5f;
758 y1 += 0.5f;
759 int iy0 = SkScalarFloorToInt(y0);
760 SkScalar filterY1 = y0 - iy0;
761 SkScalar filterY0 = 1.0f - filterY1;
762 int iy1 = SkScalarFloorToInt(y1);
763 int ix = SkScalarFloorToInt(span.startX());
herb00dd4532016-07-11 10:33:37 -0700764 const void* rowY0 = fAccessor.row(iy0);
765 const void* rowY1 = fAccessor.row(iy1);
herb6eff52a2016-03-23 09:00:33 -0700766 auto lerp = [&](Sk4f* pixelY0, Sk4f* pixelY1) {
767 return *pixelY0 * filterY0 + *pixelY1 * filterY1;
768 };
769
770 if (span.length() > 0) {
771 int count = span.count();
772 while (count >= 4) {
773 Sk4f px00, px10, px20, px30;
herb00dd4532016-07-11 10:33:37 -0700774 fAccessor.get4Pixels(rowY0, ix, &px00, &px10, &px20, &px30);
herb6eff52a2016-03-23 09:00:33 -0700775 Sk4f px01, px11, px21, px31;
herb00dd4532016-07-11 10:33:37 -0700776 fAccessor.get4Pixels(rowY1, ix, &px01, &px11, &px21, &px31);
herb9e0efe52016-04-08 13:25:28 -0700777 fNext->blend4Pixels(
herb6eff52a2016-03-23 09:00:33 -0700778 lerp(&px00, &px01), lerp(&px10, &px11), lerp(&px20, &px21), lerp(&px30, &px31));
779 ix += 4;
780 count -= 4;
781 }
782 while (count > 0) {
herb00dd4532016-07-11 10:33:37 -0700783 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix);
784 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix);
herb6eff52a2016-03-23 09:00:33 -0700785
herb9e0efe52016-04-08 13:25:28 -0700786 fNext->blendPixel(lerp(&pixelY0, &pixelY1));
herb6eff52a2016-03-23 09:00:33 -0700787 ix += 1;
788 count -= 1;
789 }
790 } else {
791 int count = span.count();
792 while (count >= 4) {
793 Sk4f px00, px10, px20, px30;
herb00dd4532016-07-11 10:33:37 -0700794 fAccessor.get4Pixels(rowY0, ix - 3, &px30, &px20, &px10, &px00);
herb6eff52a2016-03-23 09:00:33 -0700795 Sk4f px01, px11, px21, px31;
herb00dd4532016-07-11 10:33:37 -0700796 fAccessor.get4Pixels(rowY1, ix - 3, &px31, &px21, &px11, &px01);
herb9e0efe52016-04-08 13:25:28 -0700797 fNext->blend4Pixels(
herb6eff52a2016-03-23 09:00:33 -0700798 lerp(&px00, &px01), lerp(&px10, &px11), lerp(&px20, &px21), lerp(&px30, &px31));
799 ix -= 4;
800 count -= 4;
801 }
802 while (count > 0) {
herb00dd4532016-07-11 10:33:37 -0700803 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix);
804 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix);
herb6eff52a2016-03-23 09:00:33 -0700805
herb9e0efe52016-04-08 13:25:28 -0700806 fNext->blendPixel(lerp(&pixelY0, &pixelY1));
herb6eff52a2016-03-23 09:00:33 -0700807 ix -= 1;
808 count -= 1;
809 }
810 }
811 }
812
813 // We're moving through source space faster than dst (zoomed out),
814 // so we'll never reuse a source pixel or be able to do contiguous loads.
herb7ccbc1a2016-06-09 09:05:00 -0700815 void spanFastRate(Span span, SkScalar y1) {
herb6eff52a2016-03-23 09:00:33 -0700816 SkPoint start;
817 SkScalar length;
818 int count;
819 std::tie(start, length, count) = span;
820 SkScalar x = X(start);
821 SkScalar y = Y(start);
herb7ccbc1a2016-06-09 09:05:00 -0700822
herbdd404832016-06-08 14:33:15 -0700823 // In this sampler, it is assumed that if span.StartY() and y1 are the same then both
824 // y-lines are on the same tile.
825 if (y == y1) {
826 // Both y-lines are on the same tile.
herb7ccbc1a2016-06-09 09:05:00 -0700827 span_fallback(span, this);
herb6eff52a2016-03-23 09:00:33 -0700828 } else {
herbdd404832016-06-08 14:33:15 -0700829 // The y-lines are on different tiles.
herb6eff52a2016-03-23 09:00:33 -0700830 SkScalar dx = length / (count - 1);
831 Sk4f ys = {y - 0.5f, y - 0.5f, y1 + 0.5f, y1 + 0.5f};
832 while (count > 0) {
833 Sk4f xs = Sk4f{-0.5f, 0.5f, -0.5f, 0.5f} + Sk4f{x};
834 this->bilerpEdge(xs, ys);
835 x += dx;
836 count -= 1;
837 }
838 }
839 }
840
herb00dd4532016-07-11 10:33:37 -0700841 Next* const fNext;
842 Accessor fAccessor;
herb6eff52a2016-03-23 09:00:33 -0700843};
844
herb6eff52a2016-03-23 09:00:33 -0700845} // namespace
846
847#endif // SkLinearBitmapPipeline_sampler_DEFINED