| 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 |