Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: src/core/SkLinearBitmapPipeline_sample.h

Issue 2174793002: Revert of Redo Tiling (Closed) Base URL: https://skia.googlesource.com/skia.git@reduce-LBP-sample
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkLinearBitmapPipeline_core.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2016 Google Inc. 2 * Copyright 2016 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #ifndef SkLinearBitmapPipeline_sampler_DEFINED 8 #ifndef SkLinearBitmapPipeline_sampler_DEFINED
9 #define SkLinearBitmapPipeline_sampler_DEFINED 9 #define SkLinearBitmapPipeline_sampler_DEFINED
10 10
(...skipping 22 matching lines...) Expand all
33 // 33 //
34 // 34 //
35 // Given a pixelxy each is multiplied by a different factor derived from the fra ctional part of x 35 // Given a pixelxy each is multiplied by a different factor derived from the fra ctional part of x
36 // and y: 36 // and y:
37 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy 37 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy
38 // * px10 -> x(1 - y) = x - xy 38 // * px10 -> x(1 - y) = x - xy
39 // * px01 -> (1 - x)y = y - xy 39 // * px01 -> (1 - x)y = y - xy
40 // * px11 -> xy 40 // * px11 -> xy
41 // So x * y is calculated first and then used to calculate all the other factors . 41 // So x * y is calculated first and then used to calculate all the other factors .
42 static Sk4s SK_VECTORCALL bilerp4(Sk4s xs, Sk4s ys, Sk4f px00, Sk4f px10, 42 static Sk4s SK_VECTORCALL bilerp4(Sk4s xs, Sk4s ys, Sk4f px00, Sk4f px10,
43 Sk4f px01, Sk4f px11) { 43 Sk4f px01, Sk4f px11) {
44 // Calculate fractional xs and ys. 44 // Calculate fractional xs and ys.
45 Sk4s fxs = xs - xs.floor(); 45 Sk4s fxs = xs - xs.floor();
46 Sk4s fys = ys - ys.floor(); 46 Sk4s fys = ys - ys.floor();
47 Sk4s fxys{fxs * fys}; 47 Sk4s fxys{fxs * fys};
48 Sk4f sum = px11 * fxys; 48 Sk4f sum = px11 * fxys;
49 sum = sum + px01 * (fys - fxys); 49 sum = sum + px01 * (fys - fxys);
50 sum = sum + px10 * (fxs - fxys); 50 sum = sum + px10 * (fxs - fxys);
51 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys); 51 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys);
52 return sum; 52 return sum;
53 } 53 }
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 Sk4f toSk4f(Element pixel) const { 127 Sk4f toSk4f(Element pixel) const {
128 return swizzle_rb( 128 return swizzle_rb(
129 gammaType == kSRGB_SkGammaType ? Sk4f_fromS32(pixel) : Sk4f_f romL32(pixel)); 129 gammaType == kSRGB_SkGammaType ? Sk4f_fromS32(pixel) : Sk4f_f romL32(pixel));
130 } 130 }
131 }; 131 };
132 132
133 template <SkGammaType gammaType> 133 template <SkGammaType gammaType>
134 class PixelConverter<kIndex_8_SkColorType, gammaType> { 134 class PixelConverter<kIndex_8_SkColorType, gammaType> {
135 public: 135 public:
136 using Element = uint8_t; 136 using Element = uint8_t;
137 PixelConverter(const SkPixmap& srcPixmap) 137 PixelConverter(const SkPixmap& srcPixmap) {
138 : fColorTableSize(srcPixmap.ctable()->count()){
139 SkColorTable* skColorTable = srcPixmap.ctable(); 138 SkColorTable* skColorTable = srcPixmap.ctable();
140 SkASSERT(skColorTable != nullptr); 139 SkASSERT(skColorTable != nullptr);
141 140
142 fColorTable = (Sk4f*)SkAlign16((intptr_t)fColorTableStorage.get()); 141 fColorTable = (Sk4f*)SkAlign16((intptr_t)fColorTableStorage.get());
143 for (int i = 0; i < fColorTableSize; i++) { 142 for (int i = 0; i < skColorTable->count(); i++) {
144 fColorTable[i] = pmcolor_to_rgba<gammaType>((*skColorTable)[i]); 143 fColorTable[i] = pmcolor_to_rgba<gammaType>((*skColorTable)[i]);
145 } 144 }
146 } 145 }
147 146
148 PixelConverter(const PixelConverter& strategy) 147 PixelConverter(const PixelConverter& strategy) {
149 : fColorTableSize{strategy.fColorTableSize}{
150 fColorTable = (Sk4f*)SkAlign16((intptr_t)fColorTableStorage.get()); 148 fColorTable = (Sk4f*)SkAlign16((intptr_t)fColorTableStorage.get());
151 for (int i = 0; i < fColorTableSize; i++) { 149 // TODO: figure out the count.
150 for (int i = 0; i < 256; i++) {
152 fColorTable[i] = strategy.fColorTable[i]; 151 fColorTable[i] = strategy.fColorTable[i];
153 } 152 }
154 } 153 }
155 154
156 Sk4f toSk4f(Element index) const { 155 Sk4f toSk4f(Element index) const {
157 return fColorTable[index]; 156 return fColorTable[index];
158 } 157 }
159 158
160 private: 159 private:
161 static const size_t kColorTableSize = sizeof(Sk4f[256]) + 12; 160 static const size_t kColorTableSize = sizeof(Sk4f[256]) + 12;
162 const int fColorTableSize; 161
163 SkAutoMalloc fColorTableStorage{kColorTableSize}; 162 SkAutoMalloc fColorTableStorage{kColorTableSize};
164 Sk4f* fColorTable; 163 Sk4f* fColorTable;
165 }; 164 };
166 165
167 template <SkGammaType gammaType> 166 template <SkGammaType gammaType>
168 class PixelConverter<kGray_8_SkColorType, gammaType> { 167 class PixelConverter<kGray_8_SkColorType, gammaType> {
169 public: 168 public:
170 using Element = uint8_t; 169 using Element = uint8_t;
171 PixelConverter(const SkPixmap& srcPixmap) { } 170 PixelConverter(const SkPixmap& srcPixmap) { }
172 171
173 Sk4f toSk4f(Element pixel) const { 172 Sk4f toSk4f(Element pixel) const {
174 float gray = pixel * (1.0f/255.0f); 173 float gray = pixel * (1.0f/255.0f);
(...skipping 14 matching lines...) Expand all
189 return SkHalfToFloat_finite(pixel); 188 return SkHalfToFloat_finite(pixel);
190 } 189 }
191 }; 190 };
192 191
193 class PixelAccessorShim { 192 class PixelAccessorShim {
194 public: 193 public:
195 explicit PixelAccessorShim(SkLinearBitmapPipeline::PixelAccessorInterface* a ccessor) 194 explicit PixelAccessorShim(SkLinearBitmapPipeline::PixelAccessorInterface* a ccessor)
196 : fPixelAccessor(accessor) { } 195 : fPixelAccessor(accessor) { }
197 196
198 void SK_VECTORCALL getFewPixels( 197 void SK_VECTORCALL getFewPixels(
199 int n, Sk4i xs, Sk4i ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) const { 198 int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) const {
200 fPixelAccessor->getFewPixels(n, xs, ys, px0, px1, px2); 199 fPixelAccessor->getFewPixels(n, xs, ys, px0, px1, px2);
201 } 200 }
202 201
203 void SK_VECTORCALL get4Pixels( 202 void SK_VECTORCALL get4Pixels(
204 Sk4i xs, Sk4i ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const { 203 Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const {
205 fPixelAccessor->get4Pixels(xs, ys, px0, px1, px2, px3); 204 fPixelAccessor->get4Pixels(xs, ys, px0, px1, px2, px3);
206 } 205 }
207 206
208 void get4Pixels( 207 void get4Pixels(
209 const void* src, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const { 208 const void* src, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const {
210 fPixelAccessor->get4Pixels(src, index, px0, px1, px2, px3); 209 fPixelAccessor->get4Pixels(src, index, px0, px1, px2, px3);
211 }; 210 };
212 211
213 Sk4f getPixelFromRow(const void* row, int index) const { 212 Sk4f getPixelFromRow(const void* row, int index) const {
214 return fPixelAccessor->getPixelFromRow(row, index); 213 return fPixelAccessor->getPixelFromRow(row, index);
(...skipping 17 matching lines...) Expand all
232 class PixelAccessor final : public SkLinearBitmapPipeline::PixelAccessorInterfac e { 231 class PixelAccessor final : public SkLinearBitmapPipeline::PixelAccessorInterfac e {
233 using Element = typename PixelConverter<colorType, gammaType>::Element; 232 using Element = typename PixelConverter<colorType, gammaType>::Element;
234 public: 233 public:
235 template <typename... Args> 234 template <typename... Args>
236 PixelAccessor(const SkPixmap& srcPixmap, Args&&... args) 235 PixelAccessor(const SkPixmap& srcPixmap, Args&&... args)
237 : fSrc{static_cast<const Element*>(srcPixmap.addr())} 236 : fSrc{static_cast<const Element*>(srcPixmap.addr())}
238 , fWidth{srcPixmap.rowBytesAsPixels()} 237 , fWidth{srcPixmap.rowBytesAsPixels()}
239 , fConverter{srcPixmap, std::move<Args>(args)...} { } 238 , fConverter{srcPixmap, std::move<Args>(args)...} { }
240 239
241 void SK_VECTORCALL getFewPixels ( 240 void SK_VECTORCALL getFewPixels (
242 int n, Sk4i xs, Sk4i ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) const override { 241 int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) const override {
243 Sk4i bufferLoc = ys * fWidth + xs; 242 Sk4i XIs = SkNx_cast<int, SkScalar>(xs);
243 Sk4i YIs = SkNx_cast<int, SkScalar>(ys);
244 Sk4i bufferLoc = YIs * fWidth + XIs;
244 switch (n) { 245 switch (n) {
245 case 3: 246 case 3:
246 *px2 = this->getPixelAt(bufferLoc[2]); 247 *px2 = this->getPixelAt(bufferLoc[2]);
247 case 2: 248 case 2:
248 *px1 = this->getPixelAt(bufferLoc[1]); 249 *px1 = this->getPixelAt(bufferLoc[1]);
249 case 1: 250 case 1:
250 *px0 = this->getPixelAt(bufferLoc[0]); 251 *px0 = this->getPixelAt(bufferLoc[0]);
251 default: 252 default:
252 break; 253 break;
253 } 254 }
254 } 255 }
255 256
256 void SK_VECTORCALL get4Pixels( 257 void SK_VECTORCALL get4Pixels(
257 Sk4i xs, Sk4i ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const over ride { 258 Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const over ride {
258 Sk4i bufferLoc = ys * fWidth + xs; 259 Sk4i XIs = SkNx_cast<int, SkScalar>(xs);
260 Sk4i YIs = SkNx_cast<int, SkScalar>(ys);
261 Sk4i bufferLoc = YIs * fWidth + XIs;
259 *px0 = this->getPixelAt(bufferLoc[0]); 262 *px0 = this->getPixelAt(bufferLoc[0]);
260 *px1 = this->getPixelAt(bufferLoc[1]); 263 *px1 = this->getPixelAt(bufferLoc[1]);
261 *px2 = this->getPixelAt(bufferLoc[2]); 264 *px2 = this->getPixelAt(bufferLoc[2]);
262 *px3 = this->getPixelAt(bufferLoc[3]); 265 *px3 = this->getPixelAt(bufferLoc[3]);
263 } 266 }
264 267
265 void get4Pixels( 268 void get4Pixels(
266 const void* src, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const override { 269 const void* src, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) const override {
267 *px0 = this->getPixelFromRow(src, index + 0); 270 *px0 = this->getPixelFromRow(src, index + 0);
268 *px1 = this->getPixelFromRow(src, index + 1); 271 *px1 = this->getPixelFromRow(src, index + 1);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 } 324 }
322 325
323 while (count > 0) { 326 while (count > 0) {
324 next->blendPixel(strategy->getPixelFromRow(row, ix)); 327 next->blendPixel(strategy->getPixelFromRow(row, ix));
325 ix -= 1; 328 ix -= 1;
326 count -= 1; 329 count -= 1;
327 } 330 }
328 } 331 }
329 } 332 }
330 333
331 // -- NearestNeighborSampler --------------------------------------------------- --------------------
332 // NearestNeighborSampler - use nearest neighbor filtering to create runs of des tination pixels. 334 // NearestNeighborSampler - use nearest neighbor filtering to create runs of des tination pixels.
333 template<typename Accessor, typename Next> 335 template<typename Accessor, typename Next>
334 class NearestNeighborSampler : public SkLinearBitmapPipeline::SampleProcessorInt erface { 336 class NearestNeighborSampler : public SkLinearBitmapPipeline::SampleProcessorInt erface {
335 public: 337 public:
336 template<typename... Args> 338 template<typename... Args>
337 NearestNeighborSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next , Args&& ... args) 339 NearestNeighborSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next , Args&& ... args)
338 : fNext{next}, fAccessor{std::forward<Args>(args)...} { } 340 : fNext{next}, fAccessor{std::forward<Args>(args)...} { }
339 341
340 NearestNeighborSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next , 342 NearestNeighborSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next ,
341 const NearestNeighborSampler& sampler) 343 const NearestNeighborSampler& sampler)
342 : fNext{next}, fAccessor{sampler.fAccessor} { } 344 : fNext{next}, fAccessor{sampler.fAccessor} { }
343 345
344 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { 346 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
345 SkASSERT(0 < n && n < 4); 347 SkASSERT(0 < n && n < 4);
346 Sk4f px0, px1, px2; 348 Sk4f px0, px1, px2;
347 fAccessor.getFewPixels(n, SkNx_cast<int>(xs), SkNx_cast<int>(ys), &px0, &px1, &px2); 349 fAccessor.getFewPixels(n, xs, ys, &px0, &px1, &px2);
348 if (n >= 1) fNext->blendPixel(px0); 350 if (n >= 1) fNext->blendPixel(px0);
349 if (n >= 2) fNext->blendPixel(px1); 351 if (n >= 2) fNext->blendPixel(px1);
350 if (n >= 3) fNext->blendPixel(px2); 352 if (n >= 3) fNext->blendPixel(px2);
351 } 353 }
352 354
353 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { 355 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
354 Sk4f px0, px1, px2, px3; 356 Sk4f px0, px1, px2, px3;
355 fAccessor.get4Pixels(SkNx_cast<int>(xs), SkNx_cast<int>(ys), &px0, &px1, &px2, &px3); 357 fAccessor.get4Pixels(xs, ys, &px0, &px1, &px2, &px3);
356 fNext->blend4Pixels(px0, px1, px2, px3); 358 fNext->blend4Pixels(px0, px1, px2, px3);
357 } 359 }
358 360
359 void pointSpan(Span span) override { 361 void pointSpan(Span span) override {
360 SkASSERT(!span.isEmpty()); 362 SkASSERT(!span.isEmpty());
361 SkPoint start; 363 SkPoint start;
362 SkScalar length; 364 SkScalar length;
363 int count; 365 int count;
364 std::tie(start, length, count) = span; 366 std::tie(start, length, count) = span;
365 SkScalar absLength = SkScalarAbs(length); 367 SkScalar absLength = SkScalarAbs(length);
366 if (absLength < (count - 1)) { 368 if (absLength < (count - 1)) {
367 this->spanSlowRate(span); 369 this->spanSlowRate(span);
368 } else if (absLength == (count - 1)) { 370 } else if (absLength == (count - 1)) {
369 src_strategy_blend(span, fNext, &fAccessor); 371 src_strategy_blend(span, fNext, &fAccessor);
370 } else { 372 } else {
371 this->spanFastRate(span); 373 this->spanFastRate(span);
372 } 374 }
373 } 375 }
374 376
375 void repeatSpan(Span span, int32_t repeatCount) override { 377 void repeatSpan(Span span, int32_t repeatCount) override {
376 while (repeatCount > 0) { 378 while (repeatCount > 0) {
377 this->pointSpan(span); 379 this->pointSpan(span);
378 repeatCount--; 380 repeatCount--;
379 } 381 }
380 } 382 }
381 383
384 void SK_VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override {
385 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
382 private: 392 private:
383 // When moving through source space more slowly than dst space (zoomed in), 393 // When moving through source space more slowly than dst space (zoomed in),
384 // we'll be sampling from the same source pixel more than once. 394 // we'll be sampling from the same source pixel more than once.
385 void spanSlowRate(Span span) { 395 void spanSlowRate(Span span) {
386 SkPoint start; SkScalar length; int count; 396 SkPoint start;
397 SkScalar length;
398 int count;
387 std::tie(start, length, count) = span; 399 std::tie(start, length, count) = span;
388 SkScalar x = X(start); 400 SkScalar x = X(start);
389 SkFixed fx = SkScalarToFixed(x); 401 SkFixed fx = SkScalarToFixed(x);
390 SkScalar dx = length / (count - 1); 402 SkScalar dx = length / (count - 1);
391 SkFixed fdx = SkScalarToFixed(dx); 403 SkFixed fdx = SkScalarToFixed(dx);
392 404
393 const void* row = fAccessor.row((int)std::floor(Y(start))); 405 const void* row = fAccessor.row((int)std::floor(Y(start)));
394 Next* next = fNext; 406 Next* next = fNext;
395 407
396 int ix = SkFixedFloorToInt(fx); 408 int ix = SkFixedFloorToInt(fx);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 // We're moving through source space faster than dst (zoomed out), 445 // We're moving through source space faster than dst (zoomed out),
434 // so we'll never reuse a source pixel or be able to do contiguous loads. 446 // so we'll never reuse a source pixel or be able to do contiguous loads.
435 void spanFastRate(Span span) { 447 void spanFastRate(Span span) {
436 span_fallback(span, this); 448 span_fallback(span, this);
437 } 449 }
438 450
439 Next* const fNext; 451 Next* const fNext;
440 Accessor fAccessor; 452 Accessor fAccessor;
441 }; 453 };
442 454
443 // From an edgeType, the integer value of a pixel vs, and the integer value of t he extreme edge
444 // vMax, take the point which might be off the tile by one pixel and either wrap it or pin it to
445 // generate the right pixel. The value vs is on the interval [-1, vMax + 1]. It produces a value
446 // on the interval [0, vMax].
447 // Note: vMax is not width or height, but width-1 or height-1 because it is the largest valid pixel.
448 static inline int adjust_edge(SkShader::TileMode edgeType, int vs, int vMax) {
449 SkASSERT(-1 <= vs && vs <= vMax + 1)
450 switch (edgeType) {
451 case SkShader::kClamp_TileMode:
452 case SkShader::kMirror_TileMode:
453 vs = std::max(vs, 0);
454 vs = std::min(vs, vMax);
455 break;
456 case SkShader::kRepeat_TileMode:
457 vs = (vs <= vMax) ? vs : 0;
458 vs = (vs >= 0) ? vs : vMax;
459 break;
460 }
461 SkASSERT(0 <= vs && vs <= vMax);
462 return vs;
463 }
464
465 // From a sample point on the tile, return the top or left filter value.
466 // The result r should be in the range (0, 1]. Since this represents the weight given to the top
467 // left element, then if x == 0.5 the filter value should be 1.0.
468 // The input sample point must be on the tile, therefore it must be >= 0.
469 static SkScalar sample_to_filter(SkScalar x) {
470 SkASSERT(x >= 0.0f);
471 // The usual form of the top or left edge is x - .5, but since we are workin g on the unit
472 // square, then x + .5 works just as well. This also guarantees that v > 0.0 allowing the use
473 // of trunc.
474 SkScalar v = x + 0.5f;
475 // Produce the top or left offset a value on the range [0, 1).
476 SkScalar f = v - SkScalarTruncToScalar(v);
477 // Produce the filter value which is on the range (0, 1].
478 SkScalar r = 1.0f - f;
479 SkASSERT(0.0f < r && r <= 1.0f);
480 return r;
481 }
482
483 // -- BilerpSampler ------------------------------------------------------------ -------------------- 455 // -- BilerpSampler ------------------------------------------------------------ --------------------
484 // BilerpSampler - use a bilerp filter to create runs of destination pixels. 456 // BilerpSampler - use a bilerp filter to create runs of destination pixels.
485 // Note: in the code below, there are two types of points
486 // * sample points - these are the points passed in by pointList* and Span s.
487 // * filter points - are created from a sample point to form the coordinat es of the points
488 // to use in the filter and to generate the filter value s.
489 template<typename Accessor, typename Next> 457 template<typename Accessor, typename Next>
490 class BilerpSampler : public SkLinearBitmapPipeline::SampleProcessorInterface { 458 class BilerpSampler : public SkLinearBitmapPipeline::SampleProcessorInterface {
491 public: 459 public:
492 template<typename... Args> 460 template<typename... Args>
493 BilerpSampler( 461 BilerpSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next, Args&& ... args)
494 SkLinearBitmapPipeline::BlendProcessorInterface* next, 462 : fNext{next}, fAccessor{std::forward<Args>(args)...} { }
495 SkISize dimensions,
496 SkShader::TileMode xTile, SkShader::TileMode yTile,
497 Args&& ... args
498 )
499 : fNext{next}
500 , fXEdgeType{xTile}
501 , fXMax{dimensions.width() - 1}
502 , fYEdgeType{yTile}
503 , fYMax{dimensions.height() - 1}
504 , fAccessor{std::forward<Args>(args)...} { }
505 463
506 BilerpSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next, 464 BilerpSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next,
507 const BilerpSampler& sampler) 465 const BilerpSampler& sampler)
508 : fNext{next} 466 : fNext{next}, fAccessor{sampler.fAccessor} { }
509 , fXEdgeType{sampler.fXEdgeType} 467
510 , fXMax{sampler.fXMax} 468 Sk4f bilerpNonEdgePixel(SkScalar x, SkScalar y) {
511 , fYEdgeType{sampler.fYEdgeType} 469 Sk4f px00, px10, px01, px11;
512 , fYMax{sampler.fYMax} 470
513 , fAccessor{sampler.fAccessor} { } 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};
476 fAccessor.get4Pixels(sampleXs, sampleYs, &px00, &px10, &px01, &px11);
477 return bilerp4(xs, ys, px00, px10, px01, px11);
478 }
514 479
515 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { 480 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
516 SkASSERT(0 < n && n < 4); 481 SkASSERT(0 < n && n < 4);
517 auto bilerpPixel = [&](int index) { 482 auto bilerpPixel = [&](int index) {
518 return this->bilerpSamplePoint(SkPoint{xs[index], ys[index]}); 483 return this->bilerpNonEdgePixel(xs[index], ys[index]);
519 }; 484 };
520 485
521 if (n >= 1) fNext->blendPixel(bilerpPixel(0)); 486 if (n >= 1) fNext->blendPixel(bilerpPixel(0));
522 if (n >= 2) fNext->blendPixel(bilerpPixel(1)); 487 if (n >= 2) fNext->blendPixel(bilerpPixel(1));
523 if (n >= 3) fNext->blendPixel(bilerpPixel(2)); 488 if (n >= 3) fNext->blendPixel(bilerpPixel(2));
524 } 489 }
525 490
526 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { 491 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
527 auto bilerpPixel = [&](int index) { 492 auto bilerpPixel = [&](int index) {
528 return this->bilerpSamplePoint(SkPoint{xs[index], ys[index]}); 493 return this->bilerpNonEdgePixel(xs[index], ys[index]);
529 }; 494 };
530 fNext->blend4Pixels(bilerpPixel(0), bilerpPixel(1), bilerpPixel(2), bile rpPixel(3)); 495 fNext->blend4Pixels(bilerpPixel(0), bilerpPixel(1), bilerpPixel(2), bile rpPixel(3));
531 } 496 }
532 497
533 void pointSpan(Span span) override { 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
509 void SK_VECTORCALL bilerpEdge(Sk4s sampleXs, Sk4s sampleYs) override {
510 Sk4f px00, px10, px01, px11;
511 Sk4f xs = Sk4f{sampleXs[0]};
512 Sk4f ys = Sk4f{sampleYs[0]};
513 fAccessor.get4Pixels(sampleXs, sampleYs, &px00, &px10, &px01, &px11);
514 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11);
515 fNext->blendPixel(pixel);
516 }
517
518 void bilerpSpan(Span span, SkScalar y) override {
534 SkASSERT(!span.isEmpty()); 519 SkASSERT(!span.isEmpty());
535 SkPoint start; 520 SkPoint start;
536 SkScalar length; 521 SkScalar length;
537 int count; 522 int count;
538 std::tie(start, length, count) = span; 523 std::tie(start, length, count) = span;
539
540 // Nothing to do.
541 if (count == 0) {
542 return;
543 }
544
545 // Trivial case. No sample points are generated other than start.
546 if (count == 1) {
547 fNext->blendPixel(this->bilerpSamplePoint(start));
548 return;
549 }
550
551 // Note: the following code could be done in terms of dx = length / (cou nt -1), but that
552 // would introduce a divide that is not needed for the most common dx == 1 cases.
553 SkScalar absLength = SkScalarAbs(length); 524 SkScalar absLength = SkScalarAbs(length);
554 if (absLength == 0.0f) { 525 if (absLength == 0.0f) {
555 // |dx| == 0 526 this->spanZeroRate(span, y);
556 // length is zero, so clamp an edge pixel.
557 this->spanZeroRate(span);
558 } else if (absLength < (count - 1)) { 527 } else if (absLength < (count - 1)) {
559 // 0 < |dx| < 1. 528 this->spanSlowRate(span, y);
560 this->spanSlowRate(span);
561 } else if (absLength == (count - 1)) { 529 } else if (absLength == (count - 1)) {
562 // |dx| == 1. 530 if (std::fmod(span.startX() - 0.5f, 1.0f) == 0.0f) {
563 if (sample_to_filter(span.startX()) == 1.0f 531 if (std::fmod(span.startY() - 0.5f, 1.0f) == 0.0f) {
564 && sample_to_filter(span.startY()) == 1.0f) { 532 src_strategy_blend(span, fNext, &fAccessor);
565 // All the pixels are aligned with the dest; go fast. 533 } else {
566 src_strategy_blend(span, fNext, &fAccessor); 534 this->spanUnitRateAlignedX(span, y);
535 }
567 } else { 536 } else {
568 // There is some sub-pixel offsets, so bilerp. 537 this->spanUnitRate(span, y);
569 this->spanUnitRate(span); 538 }
570 }
571 } else if (absLength < 2.0f * (count - 1)) {
572 // 1 < |dx| < 2.
573 this->spanMediumRate(span);
574 } else { 539 } else {
575 // |dx| >= 2. 540 this->spanFastRate(span, y);
576 this->spanFastRate(span);
577 }
578 }
579
580 void repeatSpan(Span span, int32_t repeatCount) override {
581 while (repeatCount > 0) {
582 this->pointSpan(span);
583 repeatCount--;
584 } 541 }
585 } 542 }
586 543
587 private: 544 private:
588 545 void spanZeroRate(Span span, SkScalar y1) {
589 // Convert a sample point to the points used by the filter. 546 SkScalar y0 = span.startY() - 0.5f;
590 void filterPoints(SkPoint sample, Sk4i* filterXs, Sk4i* filterYs) { 547 y1 += 0.5f;
591 // May be less than zero. Be careful to use Floor. 548 int iy0 = SkScalarFloorToInt(y0);
592 int x0 = adjust_edge(fXEdgeType, SkScalarFloorToInt(X(sample) - 0.5), fX Max); 549 SkScalar filterY1 = y0 - iy0;
593 // Always greater than zero. Use the faster Trunc. 550 SkScalar filterY0 = 1.0f - filterY1;
594 int x1 = adjust_edge(fXEdgeType, SkScalarTruncToInt(X(sample) + 0.5), fX Max); 551 int iy1 = SkScalarFloorToInt(y1);
595 int y0 = adjust_edge(fYEdgeType, SkScalarFloorToInt(Y(sample) - 0.5), fY Max); 552 int ix = SkScalarFloorToInt(span.startX());
596 int y1 = adjust_edge(fYEdgeType, SkScalarTruncToInt(Y(sample) + 0.5), fY Max); 553 Sk4f pixelY0 = fAccessor.getPixelFromRow(fAccessor.row(iy0), ix);
597 554 Sk4f pixelY1 = fAccessor.getPixelFromRow(fAccessor.row(iy1), ix);
598 *filterXs = Sk4i{x0, x1, x0, x1}; 555 Sk4f filterPixel = pixelY0 * filterY0 + pixelY1 * filterY1;
599 *filterYs = Sk4i{y0, y0, y1, y1}; 556 int count = span.count();
600 } 557 while (count >= 4) {
601 558 fNext->blend4Pixels(filterPixel, filterPixel, filterPixel, filterPix el);
602 // Given a sample point, generate a color by bilerping the four filter point s. 559 count -= 4;
603 Sk4f bilerpSamplePoint(SkPoint sample) { 560 }
604 Sk4i iXs, iYs; 561 while (count > 0) {
605 filterPoints(sample, &iXs, &iYs); 562 fNext->blendPixel(filterPixel);
606 Sk4f px00, px10, px01, px11; 563 count -= 1;
607 fAccessor.get4Pixels(iXs, iYs, &px00, &px10, &px01, &px11); 564 }
608 return bilerp4(Sk4f{X(sample) - 0.5f}, Sk4f{Y(sample) - 0.5f}, px00, px1 0, px01, px11); 565 }
609 } 566
610 567 // When moving through source space more slowly than dst space (zoomed in),
611 // Get two pixels at x from row0 and row1. 568 // we'll be sampling from the same source pixel more than once.
612 void get2PixelColumn(const void* row0, const void* row1, int x, Sk4f* px0, S k4f* px1) { 569 void spanSlowRate(Span span, SkScalar ry1) {
613 *px0 = fAccessor.getPixelFromRow(row0, x); 570 SkPoint start;
614 *px1 = fAccessor.getPixelFromRow(row1, x); 571 SkScalar length;
615 } 572 int count;
616
617 // |dx| == 0. This code assumes that length is zero.
618 void spanZeroRate(Span span) {
619 SkPoint start; SkScalar length; int count;
620 std::tie(start, length, count) = span; 573 std::tie(start, length, count) = span;
621 SkASSERT(length == 0.0f); 574 SkFixed fx = SkScalarToFixed(X(start)-0.5f);
622 575
623 // Filter for the blending of the top and bottom pixels. 576 SkFixed fdx = SkScalarToFixed(length / (count - 1));
624 SkScalar filterY = sample_to_filter(Y(start)); 577
625 578 Sk4f xAdjust;
626 // Generate the four filter points from the sample point start. Generate the row* values. 579 if (fdx >= 0) {
627 Sk4i iXs, iYs; 580 xAdjust = Sk4f{-1.0f};
628 this->filterPoints(start, &iXs, &iYs); 581 } else {
629 const void* const row0 = fAccessor.row(iYs[0]); 582 xAdjust = Sk4f{1.0f};
630 const void* const row1 = fAccessor.row(iYs[2]); 583 }
631 584 int ix = SkFixedFloorToInt(fx);
632 // Get the two pixels that make up the clamping pixel. 585 int ioldx = ix;
633 Sk4f pxTop, pxBottom; 586 Sk4f x{SkFixedToScalar(fx) - ix};
634 this->get2PixelColumn(row0, row1, SkScalarFloorToInt(X(start)), &pxTop, &pxBottom); 587 Sk4f dx{SkFixedToScalar(fdx)};
635 Sk4f pixel = pxTop * filterY + (1.0f - filterY) * pxBottom; 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;
593 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);
599 auto getNextPixel = [&]() {
600 if (ix != ioldx) {
601 fpixel00 = fpixel10;
602 fpixel01 = fpixel11;
603 fpixel10 = y0 * fAccessor.getPixelFromRow(row0, ix + 1);
604 fpixel11 = y1 * fAccessor.getPixelFromRow(row1, ix + 1);
605 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 };
636 618
637 while (count >= 4) { 619 while (count >= 4) {
638 fNext->blend4Pixels(pixel, pixel, pixel, pixel); 620 Sk4f fpixel0 = getNextPixel();
621 Sk4f fpixel1 = getNextPixel();
622 Sk4f fpixel2 = getNextPixel();
623 Sk4f fpixel3 = getNextPixel();
624
625 fNext->blend4Pixels(fpixel0, fpixel1, fpixel2, fpixel3);
639 count -= 4; 626 count -= 4;
640 } 627 }
628
641 while (count > 0) { 629 while (count > 0) {
642 fNext->blendPixel(pixel); 630 fNext->blendPixel(getNextPixel());
631
643 count -= 1; 632 count -= 1;
644 } 633 }
645 } 634 }
646 635
647 // 0 < |dx| < 1. This code reuses the calculations from previous pixels to r educe 636 // We're moving through source space at a rate of 1 source pixel per 1 dst p ixel.
648 // computation. In particular, several destination pixels maybe generated fr om the same four 637 // We'll never re-use pixels, but we can at least load contiguous pixels.
649 // source pixels. 638 void spanUnitRate(Span span, SkScalar y1) {
650 // In the following code a "part" is a combination of two pixels from the sa me column of the 639 y1 += 0.5f;
651 // filter. 640 SkScalar y0 = span.startY() - 0.5f;
652 void spanSlowRate(Span span) { 641 int iy0 = SkScalarFloorToInt(y0);
653 SkPoint start; SkScalar length; int count; 642 SkScalar filterY1 = y0 - iy0;
654 std::tie(start, length, count) = span; 643 SkScalar filterY0 = 1.0f - filterY1;
655 644 int iy1 = SkScalarFloorToInt(y1);
656 // Calculate the distance between each sample point. 645 const void* rowY0 = fAccessor.row(iy0);
657 const SkScalar dx = length / (count - 1); 646 const void* rowY1 = fAccessor.row(iy1);
658 SkASSERT(-1.0f < dx && dx < 1.0f && dx != 0.0f); 647 SkScalar x0 = span.startX() - 0.5f;
659 648 int ix0 = SkScalarFloorToInt(x0);
660 // Generate the filter values for the top-left corner. 649 SkScalar filterX1 = x0 - ix0;
661 // Note: these values are in filter space; this has implications about h ow to adjust 650 SkScalar filterX0 = 1.0f - filterX1;
662 // these values at each step. For example, as the sample point increases , the filter 651
663 // value decreases, this is because the filter and position are related by 652 auto getPixelY0 = [&]() {
664 // (1 - (X(sample) - .5)) % 1. The (1 - stuff) causes the filter to move in the opposite 653 Sk4f px = fAccessor.getPixelFromRow(rowY0, ix0);
665 // direction of the sample point which is increasing by dx. 654 return px * filterY0;
666 SkScalar filterX = sample_to_filter(X(start)); 655 };
667 SkScalar filterY = sample_to_filter(Y(start)); 656
668 657 auto getPixelY1 = [&]() {
669 // Generate the four filter points from the sample point start. Generate the row* values. 658 Sk4f px = fAccessor.getPixelFromRow(rowY1, ix0);
670 Sk4i iXs, iYs; 659 return px * filterY1;
671 this->filterPoints(start, &iXs, &iYs); 660 };
672 const void* const row0 = fAccessor.row(iYs[0]); 661
673 const void* const row1 = fAccessor.row(iYs[2]); 662 auto get4PixelsY0 = [&](int ix, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* p x3) {
674 663 fAccessor.get4Pixels(rowY0, ix, px0, px1, px2, px3);
675 // Generate part of the filter value at xColumn. 664 *px0 = *px0 * filterY0;
676 auto partAtColumn = [&](int xColumn) { 665 *px1 = *px1 * filterY0;
677 int adjustedColumn = adjust_edge(fXEdgeType, xColumn, fXMax); 666 *px2 = *px2 * filterY0;
678 Sk4f pxTop, pxBottom; 667 *px3 = *px3 * filterY0;
679 this->get2PixelColumn(row0, row1, adjustedColumn, &pxTop, &pxBottom) ; 668 };
680 return pxTop * filterY + (1.0f - filterY) * pxBottom; 669
681 }; 670 auto get4PixelsY1 = [&](int ix, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* p x3) {
682 671 fAccessor.get4Pixels(rowY1, ix, px0, px1, px2, px3);
683 // The leftPart is made up of two pixels from the left column of the fil ter, right part 672 *px0 = *px0 * filterY1;
684 // is similar. The top and bottom pixels in the *Part are created as a l inear blend of 673 *px1 = *px1 * filterY1;
685 // the top and bottom pixels using filterY. See the partAtColumn functio n above. 674 *px2 = *px2 * filterY1;
686 Sk4f leftPart = partAtColumn(iXs[0]); 675 *px3 = *px3 * filterY1;
687 Sk4f rightPart = partAtColumn(iXs[1]); 676 };
688 677
689 // Create a destination color by blending together a left and right part using filterX. 678 auto lerp = [&](Sk4f& pixelX0, Sk4f& pixelX1) {
690 auto bilerp = [&]() { 679 return pixelX0 * filterX0 + pixelX1 * filterX1;
691 Sk4f pixel = leftPart * filterX + rightPart * (1.0f - filterX); 680 };
692 return check_pixel(pixel); 681
693 }; 682 // Mid making 4 unit rate.
694 683 Sk4f pxB = getPixelY0() + getPixelY1();
695 // Send the first pixel to the destination. This simplifies the loop str ucture so that no 684 if (span.length() > 0) {
696 // extra pixels are fetched for the last iteration of the loop. 685 int count = span.count();
697 fNext->blendPixel(bilerp());
698 count -= 1;
699
700 if (dx > 0.0f) {
701 // * positive direction - generate destination pixels by sliding the filter from left
702 // to right.
703 int rightPartCursor = iXs[1];
704
705 // Advance the filter from left to right. Remember that moving the t op-left corner of
706 // the filter to the right actually makes the filter value smaller.
707 auto advanceFilter = [&]() {
708 filterX -= dx;
709 if (filterX <= 0.0f) {
710 filterX += 1.0f;
711 leftPart = rightPart;
712 rightPartCursor += 1;
713 rightPart = partAtColumn(rightPartCursor);
714 }
715 SkASSERT(0.0f < filterX && filterX <= 1.0f);
716
717 return bilerp();
718 };
719
720 while (count >= 4) { 686 while (count >= 4) {
721 Sk4f px0 = advanceFilter(), 687 Sk4f px00, px10, px20, px30;
722 px1 = advanceFilter(), 688 get4PixelsY0(ix0, &px00, &px10, &px20, &px30);
723 px2 = advanceFilter(), 689 Sk4f px01, px11, px21, px31;
724 px3 = advanceFilter(); 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;
725 fNext->blend4Pixels(px0, px1, px2, px3); 700 fNext->blend4Pixels(px0, px1, px2, px3);
701 ix0 += 4;
726 count -= 4; 702 count -= 4;
727 } 703 }
728
729 while (count > 0) { 704 while (count > 0) {
730 fNext->blendPixel(advanceFilter()); 705 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix0);
706 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix0);
707
708 fNext->blendPixel(lerp(pixelY0, pixelY1));
709 ix0 += 1;
731 count -= 1; 710 count -= 1;
732 } 711 }
733 } else { 712 } else {
734 // * negative direction - generate destination pixels by sliding the filter from 713 int count = span.count();
735 // right to left.
736 int leftPartCursor = iXs[0];
737
738 // Advance the filter from right to left. Remember that moving the t op-left corner of
739 // the filter to the left actually makes the filter value larger.
740 auto advanceFilter = [&]() {
741 // Remember, dx < 0 therefore this adds |dx| to filterX.
742 filterX -= dx;
743 // At this point filterX may be > 1, and needs to be wrapped bac k on to the filter
744 // interval, and the next column in the filter is calculated.
745 if (filterX > 1.0f) {
746 filterX -= 1.0f;
747 rightPart = leftPart;
748 leftPartCursor -= 1;
749 leftPart = partAtColumn(leftPartCursor);
750 }
751 SkASSERT(0.0f < filterX && filterX <= 1.0f);
752
753 return bilerp();
754 };
755
756 while (count >= 4) { 714 while (count >= 4) {
757 Sk4f px0 = advanceFilter(), 715 Sk4f px00, px10, px20, px30;
758 px1 = advanceFilter(), 716 get4PixelsY0(ix0 - 3, &px00, &px10, &px20, &px30);
759 px2 = advanceFilter(), 717 Sk4f px01, px11, px21, px31;
760 px3 = advanceFilter(); 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;
761 fNext->blend4Pixels(px0, px1, px2, px3); 728 fNext->blend4Pixels(px0, px1, px2, px3);
729 ix0 -= 4;
762 count -= 4; 730 count -= 4;
763 } 731 }
764
765 while (count > 0) { 732 while (count > 0) {
766 fNext->blendPixel(advanceFilter()); 733 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix0);
734 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix0);
735
736 fNext->blendPixel(lerp(pixelY0, pixelY1));
737 ix0 -= 1;
767 count -= 1; 738 count -= 1;
768 } 739 }
769 } 740 }
770 } 741 }
771 742
772 // |dx| == 1. Moving through source space at a rate of 1 source pixel per 1 dst pixel. 743 void spanUnitRateAlignedX(Span span, SkScalar y1) {
773 // Every filter part is used for two destination pixels, and the code can bu lk load four 744 SkScalar y0 = span.startY() - 0.5f;
774 // pixels at a time. 745 y1 += 0.5f;
775 void spanUnitRate(Span span) { 746 int iy0 = SkScalarFloorToInt(y0);
776 SkPoint start; SkScalar length; int count; 747 SkScalar filterY1 = y0 - iy0;
777 std::tie(start, length, count) = span; 748 SkScalar filterY0 = 1.0f - filterY1;
778 SkASSERT(SkScalarAbs(length) == (count - 1)); 749 int iy1 = SkScalarFloorToInt(y1);
779 750 int ix = SkScalarFloorToInt(span.startX());
780 // Calculate the four filter points of start, and use the two different Y values to 751 const void* rowY0 = fAccessor.row(iy0);
781 // generate the row pointers. 752 const void* rowY1 = fAccessor.row(iy1);
782 Sk4i iXs, iYs; 753 auto lerp = [&](Sk4f* pixelY0, Sk4f* pixelY1) {
783 filterPoints(start, &iXs, &iYs); 754 return *pixelY0 * filterY0 + *pixelY1 * filterY1;
784 const void* row0 = fAccessor.row(iYs[0]); 755 };
785 const void* row1 = fAccessor.row(iYs[2]); 756
786 757 if (span.length() > 0) {
787 // Calculate the filter values for the top-left filter element. 758 int count = span.count();
788 const SkScalar filterX = sample_to_filter(X(start));
789 const SkScalar filterY = sample_to_filter(Y(start));
790
791 // Generate part of the filter value at xColumn.
792 auto partAtColumn = [&](int xColumn) {
793 int adjustedColumn = adjust_edge(fXEdgeType, xColumn, fXMax);
794 Sk4f pxTop, pxBottom;
795 this->get2PixelColumn(row0, row1, adjustedColumn, &pxTop, &pxBottom) ;
796 return pxTop * filterY + (1.0f - filterY) * pxBottom;
797 };
798
799 auto get4Parts = [&](int ix, Sk4f* part0, Sk4f* part1, Sk4f* part2, Sk4f * part3) {
800 // Check if the pixels needed are near the edges. If not go fast usi ng bulk pixels,
801 // otherwise be careful.
802 if (0 <= ix && ix <= fXMax - 3) {
803 Sk4f px00, px10, px20, px30,
804 px01, px11, px21, px31;
805 fAccessor.get4Pixels(row0, ix, &px00, &px10, &px20, &px30);
806 fAccessor.get4Pixels(row1, ix, &px01, &px11, &px21, &px31);
807 *part0 = filterY * px00 + (1.0f - filterY) * px01;
808 *part1 = filterY * px10 + (1.0f - filterY) * px11;
809 *part2 = filterY * px20 + (1.0f - filterY) * px21;
810 *part3 = filterY * px30 + (1.0f - filterY) * px31;
811 } else {
812 *part0 = partAtColumn(ix + 0);
813 *part1 = partAtColumn(ix + 1);
814 *part2 = partAtColumn(ix + 2);
815 *part3 = partAtColumn(ix + 3);
816 }
817 };
818
819 auto bilerp = [&](Sk4f& part0, Sk4f& part1) {
820 return part0 * filterX + part1 * (1.0f - filterX);
821 };
822
823 if (length > 0) {
824 // * positive direction - generate destination pixels by sliding the filter from left
825 // to right.
826
827 // overlapPart is the filter part from the end of the previous four pixels used at
828 // the start of the next four pixels.
829 Sk4f overlapPart = partAtColumn(iXs[0]);
830 int rightColumnCursor = iXs[1];
831 while (count >= 4) { 759 while (count >= 4) {
832 Sk4f part0, part1, part2, part3; 760 Sk4f px00, px10, px20, px30;
833 get4Parts(rightColumnCursor, &part0, &part1, &part2, &part3); 761 fAccessor.get4Pixels(rowY0, ix, &px00, &px10, &px20, &px30);
834 Sk4f px0 = bilerp(overlapPart, part0); 762 Sk4f px01, px11, px21, px31;
835 Sk4f px1 = bilerp(part0, part1); 763 fAccessor.get4Pixels(rowY1, ix, &px01, &px11, &px21, &px31);
836 Sk4f px2 = bilerp(part1, part2); 764 fNext->blend4Pixels(
837 Sk4f px3 = bilerp(part2, part3); 765 lerp(&px00, &px01), lerp(&px10, &px11), lerp(&px20, &px21), lerp(&px30, &px31));
838 overlapPart = part3; 766 ix += 4;
839 fNext->blend4Pixels(px0, px1, px2, px3);
840 rightColumnCursor += 4;
841 count -= 4; 767 count -= 4;
842 } 768 }
843
844 while (count > 0) { 769 while (count > 0) {
845 Sk4f rightPart = partAtColumn(rightColumnCursor); 770 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix);
846 771 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix);
847 fNext->blendPixel(bilerp(overlapPart, rightPart)); 772
848 overlapPart = rightPart; 773 fNext->blendPixel(lerp(&pixelY0, &pixelY1));
849 rightColumnCursor += 1; 774 ix += 1;
850 count -= 1; 775 count -= 1;
851 } 776 }
852 } else { 777 } else {
853 // * negative direction - generate destination pixels by sliding the filter from 778 int count = span.count();
854 // right to left.
855 Sk4f overlapPart = partAtColumn(iXs[1]);
856 int leftColumnCursor = iXs[0];
857
858 while (count >= 4) { 779 while (count >= 4) {
859 Sk4f part0, part1, part2, part3; 780 Sk4f px00, px10, px20, px30;
860 get4Parts(leftColumnCursor - 3, &part3, &part2, &part1, &part0); 781 fAccessor.get4Pixels(rowY0, ix - 3, &px30, &px20, &px10, &px00);
861 Sk4f px0 = bilerp(part0, overlapPart); 782 Sk4f px01, px11, px21, px31;
862 Sk4f px1 = bilerp(part1, part0); 783 fAccessor.get4Pixels(rowY1, ix - 3, &px31, &px21, &px11, &px01);
863 Sk4f px2 = bilerp(part2, part1); 784 fNext->blend4Pixels(
864 Sk4f px3 = bilerp(part3, part2); 785 lerp(&px00, &px01), lerp(&px10, &px11), lerp(&px20, &px21), lerp(&px30, &px31));
865 overlapPart = part3; 786 ix -= 4;
866 fNext->blend4Pixels(px0, px1, px2, px3);
867 leftColumnCursor -= 4;
868 count -= 4; 787 count -= 4;
869 } 788 }
870
871 while (count > 0) { 789 while (count > 0) {
872 Sk4f leftPart = partAtColumn(leftColumnCursor); 790 Sk4f pixelY0 = fAccessor.getPixelFromRow(rowY0, ix);
873 791 Sk4f pixelY1 = fAccessor.getPixelFromRow(rowY1, ix);
874 fNext->blendPixel(bilerp(leftPart, overlapPart)); 792
875 overlapPart = leftPart; 793 fNext->blendPixel(lerp(&pixelY0, &pixelY1));
876 leftColumnCursor -= 1; 794 ix -= 1;
877 count -= 1; 795 count -= 1;
878 } 796 }
879 } 797 }
880 }
881
882 // 1 < |dx| < 2. Going through the source pixels at a faster rate than the d est pixels, but
883 // still slow enough to take advantage of previous calculations.
884 void spanMediumRate(Span span) {
885 SkPoint start; SkScalar length; int count;
886 std::tie(start, length, count) = span;
887
888 // Calculate the distance between each sample point.
889 const SkScalar dx = length / (count - 1);
890 SkASSERT((-2.0f < dx && dx < -1.0f) || (1.0f < dx && dx < 2.0f));
891
892 // Generate the filter values for the top-left corner.
893 // Note: these values are in filter space; this has implications about h ow to adjust
894 // these values at each step. For example, as the sample point increases , the filter
895 // value decreases, this is because the filter and position are related by
896 // (1 - (X(sample) - .5)) % 1. The (1 - stuff) causes the filter to move in the opposite
897 // direction of the sample point which is increasing by dx.
898 SkScalar filterX = sample_to_filter(X(start));
899 SkScalar filterY = sample_to_filter(Y(start));
900
901 // Generate the four filter points from the sample point start. Generate the row* values.
902 Sk4i iXs, iYs;
903 this->filterPoints(start, &iXs, &iYs);
904 const void* const row0 = fAccessor.row(iYs[0]);
905 const void* const row1 = fAccessor.row(iYs[2]);
906
907 // Generate part of the filter value at xColumn.
908 auto partAtColumn = [&](int xColumn) {
909 int adjustedColumn = adjust_edge(fXEdgeType, xColumn, fXMax);
910 Sk4f pxTop, pxBottom;
911 this->get2PixelColumn(row0, row1, adjustedColumn, &pxTop, &pxBottom) ;
912 return pxTop * filterY + (1.0f - filterY) * pxBottom;
913 };
914
915 // The leftPart is made up of two pixels from the left column of the fil ter, right part
916 // is similar. The top and bottom pixels in the *Part are created as a l inear blend of
917 // the top and bottom pixels using filterY. See the nextPart function be low.
918 Sk4f leftPart = partAtColumn(iXs[0]);
919 Sk4f rightPart = partAtColumn(iXs[1]);
920
921 // Create a destination color by blending together a left and right part using filterX.
922 auto bilerp = [&]() {
923 Sk4f pixel = leftPart * filterX + rightPart * (1.0f - filterX);
924 return check_pixel(pixel);
925 };
926
927 // Send the first pixel to the destination. This simplifies the loop str ucture so that no
928 // extra pixels are fetched for the last iteration of the loop.
929 fNext->blendPixel(bilerp());
930 count -= 1;
931
932 if (dx > 0.0f) {
933 // * positive direction - generate destination pixels by sliding the filter from left
934 // to right.
935 int rightPartCursor = iXs[1];
936
937 // Advance the filter from left to right. Remember that moving the t op-left corner of
938 // the filter to the right actually makes the filter value smaller.
939 auto advanceFilter = [&]() {
940 filterX -= dx;
941 // At this point filterX is less than zero, but might actually b e less than -1.
942 if (filterX > -1.0f) {
943 filterX += 1.0f;
944 leftPart = rightPart;
945 rightPartCursor += 1;
946 rightPart = partAtColumn(rightPartCursor);
947 } else {
948 filterX += 2.0f;
949 rightPartCursor += 2;
950 leftPart = partAtColumn(rightPartCursor - 1);
951 rightPart = partAtColumn(rightPartCursor);
952 }
953 SkASSERT(0.0f < filterX && filterX <= 1.0f);
954
955 return bilerp();
956 };
957
958 while (count >= 4) {
959 Sk4f px0 = advanceFilter(),
960 px1 = advanceFilter(),
961 px2 = advanceFilter(),
962 px3 = advanceFilter();
963 fNext->blend4Pixels(px0, px1, px2, px3);
964 count -= 4;
965 }
966
967 while (count > 0) {
968 fNext->blendPixel(advanceFilter());
969 count -= 1;
970 }
971 } else {
972 // * negative direction - generate destination pixels by sliding the filter from
973 // right to left.
974 int leftPartCursor = iXs[0];
975
976 auto advanceFilter = [&]() {
977 // Remember, dx < 0 therefore this adds |dx| to filterX.
978 filterX -= dx;
979 // At this point, filterX is greater than one, but may actually be greater than two.
980 if (filterX < 2.0f) {
981 filterX -= 1.0f;
982 rightPart = leftPart;
983 leftPartCursor -= 1;
984 leftPart = partAtColumn(leftPartCursor);
985 } else {
986 filterX -= 2.0f;
987 leftPartCursor -= 2;
988 rightPart = partAtColumn(leftPartCursor - 1);
989 leftPart = partAtColumn(leftPartCursor);
990 }
991 SkASSERT(0.0f < filterX && filterX <= 1.0f);
992 return bilerp();
993 };
994
995 while (count >= 4) {
996 Sk4f px0 = advanceFilter(),
997 px1 = advanceFilter(),
998 px2 = advanceFilter(),
999 px3 = advanceFilter();
1000 fNext->blend4Pixels(px0, px1, px2, px3);
1001 count -= 4;
1002 }
1003
1004 while (count > 0) {
1005 fNext->blendPixel(advanceFilter());
1006 count -= 1;
1007 }
1008 }
1009 } 798 }
1010 799
1011 // We're moving through source space faster than dst (zoomed out), 800 // We're moving through source space faster than dst (zoomed out),
1012 // so we'll never reuse a source pixel or be able to do contiguous loads. 801 // so we'll never reuse a source pixel or be able to do contiguous loads.
1013 void spanFastRate(Span span) { 802 void spanFastRate(Span span, SkScalar y1) {
1014 SkPoint start; SkScalar length; int count; 803 SkPoint start;
804 SkScalar length;
805 int count;
1015 std::tie(start, length, count) = span; 806 std::tie(start, length, count) = span;
1016 SkScalar x = X(start); 807 SkScalar x = X(start);
1017 SkScalar y = Y(start); 808 SkScalar y = Y(start);
1018 809
1019 SkScalar dx = length / (count - 1); 810 // In this sampler, it is assumed that if span.StartY() and y1 are the s ame then both
1020 while (count > 0) { 811 // y-lines are on the same tile.
1021 fNext->blendPixel(this->bilerpSamplePoint(SkPoint{x, y})); 812 if (y == y1) {
1022 x += dx; 813 // Both y-lines are on the same tile.
1023 count -= 1; 814 span_fallback(span, this);
815 } else {
816 // The y-lines are on different tiles.
817 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 }
1024 } 825 }
1025 } 826 }
1026 827
1027 Next* const fNext; 828 Next* const fNext;
1028 const SkShader::TileMode fXEdgeType; 829 Accessor fAccessor;
1029 const int fXMax;
1030 const SkShader::TileMode fYEdgeType;
1031 const int fYMax;
1032 Accessor fAccessor;
1033 }; 830 };
1034 831
1035 } // namespace 832 } // namespace
1036 833
1037 #endif // SkLinearBitmapPipeline_sampler_DEFINED 834 #endif // SkLinearBitmapPipeline_sampler_DEFINED
OLDNEW
« no previous file with comments | « src/core/SkLinearBitmapPipeline_core.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698