OLD | NEW |
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 #include "SkLinearBitmapPipeline.h" | 8 #include "SkLinearBitmapPipeline.h" |
9 #include "SkPM4f.h" | 9 #include "SkPM4f.h" |
10 | 10 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 void clampToSinglePixel(SkPoint pixel) { | 125 void clampToSinglePixel(SkPoint pixel) { |
126 fStart = pixel; | 126 fStart = pixel; |
127 fLength = 0.0f; | 127 fLength = 0.0f; |
128 } | 128 } |
129 | 129 |
130 private: | 130 private: |
131 SkPoint fStart; | 131 SkPoint fStart; |
132 SkScalar fLength; | 132 SkScalar fLength; |
133 int fCount; | 133 int fCount; |
134 }; | 134 }; |
| 135 |
| 136 // BilerpSpans are similar to Spans, but they represent four source samples conv
erting to single |
| 137 // destination pixel per count. The pixels for the four samples are collect alon
g two horizontal |
| 138 // lines; one starting at {x, y0} and the other starting at {x, y1}. There are t
wo distinct lines |
| 139 // to deal with the edge case of the tile mode. For example, y0 may be at the la
st y position in |
| 140 // a tile while y1 would be at the first. |
| 141 // The step of a Bilerp (dx) is still length / (count - 1) and the start to the
next sample is |
| 142 // still dx * count, but the bounds are complicated by the sampling kernel so th
at the pixels |
| 143 // touched are from x to x + length + 1. |
| 144 class BilerpSpan { |
| 145 public: |
| 146 BilerpSpan(SkScalar x, SkScalar y0, SkScalar y1, SkScalar length, int count) |
| 147 : fX{x}, fY0{y0}, fY1{y1}, fLength{length}, fCount{count} { |
| 148 SkASSERT(count >= 0); |
| 149 SkASSERT(std::isfinite(length)); |
| 150 SkASSERT(std::isfinite(x)); |
| 151 SkASSERT(std::isfinite(y0)); |
| 152 SkASSERT(std::isfinite(y1)); |
| 153 } |
| 154 |
| 155 operator std::tuple<SkScalar&, SkScalar&, SkScalar&, SkScalar&, int&>() { |
| 156 return std::tie(fX, fY0, fY1, fLength, fCount); |
| 157 } |
| 158 |
| 159 bool isEmpty() const { return 0 == fCount; } |
| 160 |
| 161 private: |
| 162 SkScalar fX; |
| 163 SkScalar fY0; |
| 164 SkScalar fY1; |
| 165 SkScalar fLength; |
| 166 int fCount; |
| 167 }; |
135 } // namespace | 168 } // namespace |
136 | 169 |
137 class SkLinearBitmapPipeline::PointProcessorInterface { | 170 class SkLinearBitmapPipeline::PointProcessorInterface { |
138 public: | 171 public: |
139 virtual ~PointProcessorInterface() { } | 172 virtual ~PointProcessorInterface() { } |
140 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; | 173 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; |
141 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; | 174 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; |
142 virtual void pointSpan(Span span) = 0; | 175 virtual void pointSpan(Span span) = 0; |
143 }; | 176 }; |
144 | 177 |
145 class SkLinearBitmapPipeline::BilerpProcessorInterface | 178 class SkLinearBitmapPipeline::BilerpProcessorInterface |
146 : public SkLinearBitmapPipeline::PointProcessorInterface { | 179 : public SkLinearBitmapPipeline::PointProcessorInterface { |
147 public: | 180 public: |
148 // The x's and y's are setup in the following order: | 181 // The x's and y's are setup in the following order: |
149 // +--------+--------+ | 182 // +--------+--------+ |
150 // | | | | 183 // | | | |
151 // | px00 | px10 | | 184 // | px00 | px10 | |
152 // | 0 | 1 | | 185 // | 0 | 1 | |
153 // +--------+--------+ | 186 // +--------+--------+ |
154 // | | | | 187 // | | | |
155 // | px01 | px11 | | 188 // | px01 | px11 | |
156 // | 2 | 3 | | 189 // | 2 | 3 | |
157 // +--------+--------+ | 190 // +--------+--------+ |
158 // These pixels coordinates are arranged in the following order in xs and ys
: | 191 // These pixels coordinates are arranged in the following order in xs and ys
: |
159 // px00 px10 px01 px11 | 192 // px00 px10 px01 px11 |
160 virtual void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) = 0; | 193 virtual void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) = 0; |
| 194 virtual void bilerpSpan(BilerpSpan span) = 0; |
161 }; | 195 }; |
162 | 196 |
163 class SkLinearBitmapPipeline::PixelPlacerInterface { | 197 class SkLinearBitmapPipeline::PixelPlacerInterface { |
164 public: | 198 public: |
165 virtual ~PixelPlacerInterface() { } | 199 virtual ~PixelPlacerInterface() { } |
166 virtual void setDestination(SkPM4f* dst) = 0; | 200 virtual void setDestination(SkPM4f* dst) = 0; |
167 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; | 201 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; |
168 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0
; | 202 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0
; |
169 }; | 203 }; |
170 | 204 |
(...skipping 19 matching lines...) Expand all Loading... |
190 while (count >= 4) { | 224 while (count >= 4) { |
191 stage->pointList4(xs, ys); | 225 stage->pointList4(xs, ys); |
192 xs = xs + fourDx; | 226 xs = xs + fourDx; |
193 count -= 4; | 227 count -= 4; |
194 } | 228 } |
195 if (count > 0) { | 229 if (count > 0) { |
196 stage->pointListFew(count, xs, ys); | 230 stage->pointListFew(count, xs, ys); |
197 } | 231 } |
198 } | 232 } |
199 | 233 |
| 234 template <typename Next> |
| 235 void bilerp_span_fallback(BilerpSpan span, Next* next) { |
| 236 SkScalar x, y0, y1; SkScalar length; int count; |
| 237 std::tie(x, y0, y1, length, count) = span; |
| 238 |
| 239 SkASSERT(!span.isEmpty()); |
| 240 float dx = length / (count - 1); |
| 241 |
| 242 Sk4f xs = Sk4f{x} + Sk4f{0.0f, 1.0f, 0.0f, 1.0f}; |
| 243 Sk4f ys = Sk4f{y0, y0, y1, y1}; |
| 244 |
| 245 // If count == 1 then dx will be inf or NaN, but that is ok because the resu
lting addition is |
| 246 // never used. |
| 247 while (count > 0) { |
| 248 next->bilerpList(xs, ys); |
| 249 xs = xs + dx; |
| 250 count -= 1; |
| 251 } |
| 252 } |
| 253 |
200 // PointProcessor uses a strategy to help complete the work of the different sta
ges. The strategy | 254 // PointProcessor uses a strategy to help complete the work of the different sta
ges. The strategy |
201 // must implement the following methods: | 255 // must implement the following methods: |
202 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. | 256 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. |
203 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixel
s | 257 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixel
s |
204 // to work over. | 258 // to work over. |
205 // span - encapsulation of span. | 259 // span - encapsulation of span. |
206 // next - a pointer to the next stage. | 260 // next - a pointer to the next stage. |
207 // maybeProcessSpan - returns false if it can not process the span and needs t
o fallback to | 261 // maybeProcessSpan - returns false if it can not process the span and needs t
o fallback to |
208 // point lists for processing. | 262 // point lists for processing. |
209 template<typename Strategy, typename Next> | 263 template<typename Strategy, typename Next> |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 fNext->bilerpList(xs, ys); | 315 fNext->bilerpList(xs, ys); |
262 } | 316 } |
263 | 317 |
264 void pointSpan(Span span) override { | 318 void pointSpan(Span span) override { |
265 SkASSERT(!span.isEmpty()); | 319 SkASSERT(!span.isEmpty()); |
266 if (!fStrategy.maybeProcessSpan(span, fNext)) { | 320 if (!fStrategy.maybeProcessSpan(span, fNext)) { |
267 span_fallback(span, this); | 321 span_fallback(span, this); |
268 } | 322 } |
269 } | 323 } |
270 | 324 |
| 325 void bilerpSpan(BilerpSpan bSpan) override { |
| 326 SkASSERT(!bSpan.isEmpty()); |
| 327 if (!fStrategy.maybeProcessBilerpSpan(bSpan, fNext)) { |
| 328 bilerp_span_fallback(bSpan, this); |
| 329 } |
| 330 } |
| 331 |
271 private: | 332 private: |
272 Next* const fNext; | 333 Next* const fNext; |
273 Strategy fStrategy; | 334 Strategy fStrategy; |
274 }; | 335 }; |
275 | 336 |
276 class TranslateMatrixStrategy { | 337 class TranslateMatrixStrategy { |
277 public: | 338 public: |
278 TranslateMatrixStrategy(SkVector offset) | 339 TranslateMatrixStrategy(SkVector offset) |
279 : fXOffset{X(offset)} | 340 : fXOffset{X(offset)} |
280 , fYOffset{Y(offset)} { } | 341 , fYOffset{Y(offset)} { } |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYOffsets); | 463 fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYOffsets); |
403 fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYOffsets); | 464 fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYOffsets); |
404 fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYOffsets); | 465 fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYOffsets); |
405 fNext->bilerpList(Sk4s{xs[3]} + kXOffsets, Sk4s{ys[3]} + kYOffsets); | 466 fNext->bilerpList(Sk4s{xs[3]} + kXOffsets, Sk4s{ys[3]} + kYOffsets); |
406 } | 467 } |
407 | 468 |
408 void pointSpan(Span span) override { | 469 void pointSpan(Span span) override { |
409 SkASSERT(!span.isEmpty()); | 470 SkASSERT(!span.isEmpty()); |
410 SkPoint start; SkScalar length; int count; | 471 SkPoint start; SkScalar length; int count; |
411 std::tie(start, length, count) = span; | 472 std::tie(start, length, count) = span; |
412 float dx = length / (count - 1); | 473 // Adjust the span so that it is in the correct phase with the pixel. |
413 | 474 BilerpSpan bSpan{X(start) - 0.5f, Y(start) - 0.5f, Y(start) + 0.5f, leng
th, count}; |
414 Sk4f Xs = Sk4f{X(start)} + Sk4f{-0.5f, 0.5f, -0.5f, 0.5f}; | 475 fNext->bilerpSpan(bSpan); |
415 Sk4f Ys = Sk4f{Y(start)} + Sk4f{-0.5f, -0.5f, 0.5f, 0.5f}; | |
416 | |
417 Sk4f dXs{dx}; | |
418 while (count > 0) { | |
419 fNext->bilerpList(Xs, Ys); | |
420 Xs = Xs + dXs; | |
421 count -= 1; | |
422 } | |
423 } | 476 } |
424 | 477 |
425 private: | 478 private: |
426 Next* const fNext; | 479 Next* const fNext; |
427 }; | 480 }; |
428 | 481 |
429 static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter( | 482 static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter( |
430 SkLinearBitmapPipeline::BilerpProcessorInterface* next, | 483 SkLinearBitmapPipeline::BilerpProcessorInterface* next, |
431 SkFilterQuality filterQuailty, | 484 SkFilterQuality filterQuailty, |
432 SkLinearBitmapPipeline::FilterStage* filterProc) { | 485 SkLinearBitmapPipeline::FilterStage* filterProc) { |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 next->pointSpan(middle); | 586 next->pointSpan(middle); |
534 } | 587 } |
535 if (!span.isEmpty()) { | 588 if (!span.isEmpty()) { |
536 span.clampToSinglePixel({xMin, y}); | 589 span.clampToSinglePixel({xMin, y}); |
537 next->pointSpan(span); | 590 next->pointSpan(span); |
538 } | 591 } |
539 } | 592 } |
540 return true; | 593 return true; |
541 } | 594 } |
542 | 595 |
| 596 template <typename Next> |
| 597 bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) { |
| 598 return false; |
| 599 } |
| 600 |
543 private: | 601 private: |
544 const Sk4s fXMin{SK_FloatNegativeInfinity}; | 602 const Sk4s fXMin{SK_FloatNegativeInfinity}; |
545 const Sk4s fYMin{SK_FloatNegativeInfinity}; | 603 const Sk4s fYMin{SK_FloatNegativeInfinity}; |
546 const Sk4s fXMax{SK_FloatInfinity}; | 604 const Sk4s fXMax{SK_FloatInfinity}; |
547 const Sk4s fYMax{SK_FloatInfinity}; | 605 const Sk4s fYMax{SK_FloatInfinity}; |
548 }; | 606 }; |
549 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 607 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
550 using Clamp = BilerpProcessor<ClampStrategy, Next>; | 608 using Clamp = BilerpProcessor<ClampStrategy, Next>; |
551 | 609 |
552 static SkScalar tile_mod(SkScalar x, SkScalar base) { | 610 static SkScalar tile_mod(SkScalar x, SkScalar base) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
636 } | 694 } |
637 | 695 |
638 // All on a single tile. | 696 // All on a single tile. |
639 if (!span.isEmpty()) { | 697 if (!span.isEmpty()) { |
640 next->pointSpan(span); | 698 next->pointSpan(span); |
641 } | 699 } |
642 | 700 |
643 return true; | 701 return true; |
644 } | 702 } |
645 | 703 |
| 704 template <typename Next> |
| 705 bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) { |
| 706 return false; |
| 707 } |
| 708 |
646 private: | 709 private: |
647 const Sk4s fXMax{0.0f}; | 710 const Sk4s fXMax{0.0f}; |
648 const Sk4s fXInvMax{0.0f}; | 711 const Sk4s fXInvMax{0.0f}; |
649 const Sk4s fYMax{0.0f}; | 712 const Sk4s fYMax{0.0f}; |
650 const Sk4s fYInvMax{0.0f}; | 713 const Sk4s fYInvMax{0.0f}; |
651 }; | 714 }; |
652 | 715 |
653 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 716 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
654 using Repeat = BilerpProcessor<RepeatStrategy, Next>; | 717 using Repeat = BilerpProcessor<RepeatStrategy, Next>; |
655 | 718 |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
917 count -= 1; | 980 count -= 1; |
918 } | 981 } |
919 } | 982 } |
920 | 983 |
921 // We're moving through source space faster than dst (zoomed out), | 984 // We're moving through source space faster than dst (zoomed out), |
922 // so we'll never reuse a source pixel or be able to do contiguous loads. | 985 // so we'll never reuse a source pixel or be able to do contiguous loads. |
923 void pointSpanFastRate(Span span) { | 986 void pointSpanFastRate(Span span) { |
924 span_fallback(span, this); | 987 span_fallback(span, this); |
925 } | 988 } |
926 | 989 |
| 990 void bilerpSpan(BilerpSpan span) override { |
| 991 bilerp_span_fallback(span, this); |
| 992 } |
| 993 |
927 private: | 994 private: |
928 SkLinearBitmapPipeline::PixelPlacerInterface* const fNext; | 995 SkLinearBitmapPipeline::PixelPlacerInterface* const fNext; |
929 SourceStrategy fStrategy; | 996 SourceStrategy fStrategy; |
930 }; | 997 }; |
931 | 998 |
932 using Pixel8888SRGB = Pixel8888<kSRGB_SkColorProfileType, ColorOrder::kRGBA>; | 999 using Pixel8888SRGB = Pixel8888<kSRGB_SkColorProfileType, ColorOrder::kRGBA>; |
933 using Pixel8888LRGB = Pixel8888<kLinear_SkColorProfileType, ColorOrder::kRGBA>; | 1000 using Pixel8888LRGB = Pixel8888<kLinear_SkColorProfileType, ColorOrder::kRGBA>; |
934 using Pixel8888SBGR = Pixel8888<kSRGB_SkColorProfileType, ColorOrder::kBGRA>; | 1001 using Pixel8888SBGR = Pixel8888<kSRGB_SkColorProfileType, ColorOrder::kBGRA>; |
935 using Pixel8888LBGR = Pixel8888<kLinear_SkColorProfileType, ColorOrder::kBGRA>; | 1002 using Pixel8888LBGR = Pixel8888<kLinear_SkColorProfileType, ColorOrder::kBGRA>; |
936 | 1003 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1033 | 1100 |
1034 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { | 1101 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { |
1035 SkASSERT(count > 0); | 1102 SkASSERT(count > 0); |
1036 fPixelStage->setDestination(dst); | 1103 fPixelStage->setDestination(dst); |
1037 // The count and length arguments start out in a precise relation in order t
o keep the | 1104 // The count and length arguments start out in a precise relation in order t
o keep the |
1038 // math correct through the different stages. Count is the number of pixel t
o produce. | 1105 // math correct through the different stages. Count is the number of pixel t
o produce. |
1039 // Since the code samples at pixel centers, length is the distance from the
center of the | 1106 // Since the code samples at pixel centers, length is the distance from the
center of the |
1040 // first pixel to the center of the last pixel. This implies that length is
count-1. | 1107 // first pixel to the center of the last pixel. This implies that length is
count-1. |
1041 fFirstStage->pointSpan(Span{SkPoint{x + 0.5f, y + 0.5f}, count - 1.0f, count
}); | 1108 fFirstStage->pointSpan(Span{SkPoint{x + 0.5f, y + 0.5f}, count - 1.0f, count
}); |
1042 } | 1109 } |
OLD | NEW |