| 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 |
| 9 #include "SkPM4f.h" | 10 #include "SkPM4f.h" |
| 10 | |
| 11 #include <algorithm> | 11 #include <algorithm> |
| 12 #include <cmath> | 12 #include <cmath> |
| 13 #include <limits> | 13 #include <limits> |
| 14 #include "SkColor.h" | 14 #include "SkColor.h" |
| 15 #include "SkSize.h" | 15 #include "SkSize.h" |
| 16 #include <tuple> | 16 #include <tuple> |
| 17 | 17 #include "SkLinearBitmapPipeline_core.h" |
| 18 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. | 18 #include "SkLinearBitmapPipeline_matrix.h" |
| 19 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 | 19 #include "SkLinearBitmapPipeline_tile.h" |
| 20 #define VECTORCALL __vectorcall | |
| 21 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) | |
| 22 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) | |
| 23 #else | |
| 24 #define VECTORCALL | |
| 25 #endif | |
| 26 | |
| 27 namespace { | |
| 28 struct X { | |
| 29 explicit X(SkScalar val) : fVal{val} { } | |
| 30 explicit X(SkPoint pt) : fVal{pt.fX} { } | |
| 31 explicit X(SkSize s) : fVal{s.fWidth} { } | |
| 32 explicit X(SkISize s) : fVal(s.fWidth) { } | |
| 33 operator SkScalar () const {return fVal;} | |
| 34 private: | |
| 35 SkScalar fVal; | |
| 36 }; | |
| 37 | |
| 38 struct Y { | |
| 39 explicit Y(SkScalar val) : fVal{val} { } | |
| 40 explicit Y(SkPoint pt) : fVal{pt.fY} { } | |
| 41 explicit Y(SkSize s) : fVal{s.fHeight} { } | |
| 42 explicit Y(SkISize s) : fVal(s.fHeight) { } | |
| 43 operator SkScalar () const {return fVal;} | |
| 44 private: | |
| 45 SkScalar fVal; | |
| 46 }; | |
| 47 | |
| 48 // The Span class enables efficient processing horizontal spans of pixels. | |
| 49 // * start - the point where to start the span. | |
| 50 // * length - the number of pixels to traverse in source space. | |
| 51 // * count - the number of pixels to produce in destination space. | |
| 52 // Both start and length are mapped through the inversion matrix to produce valu
es in source | |
| 53 // space. After the matrix operation, the tilers may break the spans up into sma
ller spans. | |
| 54 // The tilers can produce spans that seem nonsensical. | |
| 55 // * The clamp tiler can create spans with length of 0. This indicates to copy a
n edge pixel out | |
| 56 // to the edge of the destination scan. | |
| 57 // * The mirror tiler can produce spans with negative length. This indicates tha
t the source | |
| 58 // should be traversed in the opposite direction to the destination pixels. | |
| 59 class Span { | |
| 60 public: | |
| 61 Span(SkPoint start, SkScalar length, int count) | |
| 62 : fStart(start) | |
| 63 , fLength(length) | |
| 64 , fCount{count} { | |
| 65 SkASSERT(std::isfinite(length)); | |
| 66 } | |
| 67 | |
| 68 operator std::tuple<SkPoint&, SkScalar&, int&>() { | |
| 69 return std::tie(fStart, fLength, fCount); | |
| 70 } | |
| 71 | |
| 72 bool isEmpty() const { return 0 == fCount; } | |
| 73 SkScalar length() const { return fLength; } | |
| 74 SkScalar startX() const { return X(fStart); } | |
| 75 SkScalar endX() const { return startX() + length(); } | |
| 76 void clear() { | |
| 77 fCount = 0; | |
| 78 } | |
| 79 | |
| 80 bool completelyWithin(SkScalar xMin, SkScalar xMax) const { | |
| 81 SkScalar sMin, sMax; | |
| 82 std::tie(sMin, sMax) = std::minmax(startX(), endX()); | |
| 83 return xMin <= sMin && sMax <= xMax; | |
| 84 } | |
| 85 | |
| 86 void offset(SkScalar offsetX) { | |
| 87 fStart.offset(offsetX, 0.0f); | |
| 88 } | |
| 89 | |
| 90 Span breakAt(SkScalar breakX, SkScalar dx) { | |
| 91 SkASSERT(std::isfinite(breakX)); | |
| 92 SkASSERT(std::isfinite(dx)); | |
| 93 SkASSERT(dx != 0.0f); | |
| 94 | |
| 95 if (this->isEmpty()) { | |
| 96 return Span{{0.0, 0.0}, 0.0f, 0}; | |
| 97 } | |
| 98 | |
| 99 int dxSteps = SkScalarFloorToInt((breakX - this->startX()) / dx); | |
| 100 if (dxSteps < 0) { | |
| 101 // The span is wholly after breakX. | |
| 102 return Span{{0.0, 0.0}, 0.0f, 0}; | |
| 103 } else if (dxSteps > fCount) { | |
| 104 // The span is wholly before breakX. | |
| 105 Span answer = *this; | |
| 106 this->clear(); | |
| 107 return answer; | |
| 108 } | |
| 109 | |
| 110 // Calculate the values for the span to cleave off. | |
| 111 SkPoint newStart = fStart; | |
| 112 SkScalar newLength = dxSteps * dx; | |
| 113 int newCount = dxSteps + 1; | |
| 114 SkASSERT(newCount > 0); | |
| 115 | |
| 116 // Update this span to reflect the break. | |
| 117 SkScalar lengthToStart = newLength + dx; | |
| 118 fLength -= lengthToStart; | |
| 119 fCount -= newCount; | |
| 120 fStart = {this->startX() + lengthToStart, Y(fStart)}; | |
| 121 | |
| 122 return Span{newStart, newLength, newCount}; | |
| 123 } | |
| 124 | |
| 125 void clampToSinglePixel(SkPoint pixel) { | |
| 126 fStart = pixel; | |
| 127 fLength = 0.0f; | |
| 128 } | |
| 129 | |
| 130 private: | |
| 131 SkPoint fStart; | |
| 132 SkScalar fLength; | |
| 133 int fCount; | |
| 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 }; | |
| 168 } // namespace | |
| 169 | 20 |
| 170 class SkLinearBitmapPipeline::PointProcessorInterface { | 21 class SkLinearBitmapPipeline::PointProcessorInterface { |
| 171 public: | 22 public: |
| 172 virtual ~PointProcessorInterface() { } | 23 virtual ~PointProcessorInterface() { } |
| 173 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; | 24 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; |
| 174 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; | 25 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; |
| 175 virtual void pointSpan(Span span) = 0; | 26 virtual void pointSpan(Span span) = 0; |
| 176 }; | 27 }; |
| 177 | 28 |
| 178 class SkLinearBitmapPipeline::BilerpProcessorInterface | 29 class SkLinearBitmapPipeline::BilerpProcessorInterface |
| (...skipping 17 matching lines...) Expand all Loading... |
| 196 | 47 |
| 197 class SkLinearBitmapPipeline::PixelPlacerInterface { | 48 class SkLinearBitmapPipeline::PixelPlacerInterface { |
| 198 public: | 49 public: |
| 199 virtual ~PixelPlacerInterface() { } | 50 virtual ~PixelPlacerInterface() { } |
| 200 virtual void setDestination(SkPM4f* dst) = 0; | 51 virtual void setDestination(SkPM4f* dst) = 0; |
| 201 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; | 52 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; |
| 202 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0
; | 53 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0
; |
| 203 }; | 54 }; |
| 204 | 55 |
| 205 namespace { | 56 namespace { |
| 206 template <typename Stage> | |
| 207 void span_fallback(Span span, Stage* stage) { | |
| 208 SkPoint start; | |
| 209 SkScalar length; | |
| 210 int count; | |
| 211 std::tie(start, length, count) = span; | |
| 212 Sk4f xs{X(start)}; | |
| 213 Sk4f ys{Y(start)}; | |
| 214 | |
| 215 // Initializing this is not needed, but some compilers can't figure this out
. | |
| 216 Sk4s fourDx{0.0f}; | |
| 217 if (count > 1) { | |
| 218 SkScalar dx = length / (count - 1); | |
| 219 xs = xs + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * dx; | |
| 220 // Only used if count is >= 4. | |
| 221 fourDx = Sk4f{4.0f * dx}; | |
| 222 } | |
| 223 | |
| 224 while (count >= 4) { | |
| 225 stage->pointList4(xs, ys); | |
| 226 xs = xs + fourDx; | |
| 227 count -= 4; | |
| 228 } | |
| 229 if (count > 0) { | |
| 230 stage->pointListFew(count, xs, ys); | |
| 231 } | |
| 232 } | |
| 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 | 57 |
| 254 // PointProcessor uses a strategy to help complete the work of the different sta
ges. The strategy | 58 // PointProcessor uses a strategy to help complete the work of the different sta
ges. The strategy |
| 255 // must implement the following methods: | 59 // must implement the following methods: |
| 256 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. | 60 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. |
| 257 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixel
s | 61 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixel
s |
| 258 // to work over. | 62 // to work over. |
| 259 // span - encapsulation of span. | 63 // span - encapsulation of span. |
| 260 // next - a pointer to the next stage. | 64 // next - a pointer to the next stage. |
| 261 // maybeProcessSpan - returns false if it can not process the span and needs t
o fallback to | 65 // maybeProcessSpan - returns false if it can not process the span and needs t
o fallback to |
| 262 // point lists for processing. | 66 // point lists for processing. |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 if (!fStrategy.maybeProcessBilerpSpan(bSpan, fNext)) { | 131 if (!fStrategy.maybeProcessBilerpSpan(bSpan, fNext)) { |
| 328 bilerp_span_fallback(bSpan, this); | 132 bilerp_span_fallback(bSpan, this); |
| 329 } | 133 } |
| 330 } | 134 } |
| 331 | 135 |
| 332 private: | 136 private: |
| 333 Next* const fNext; | 137 Next* const fNext; |
| 334 Strategy fStrategy; | 138 Strategy fStrategy; |
| 335 }; | 139 }; |
| 336 | 140 |
| 337 class TranslateMatrixStrategy { | 141 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 338 public: | 142 // Matrix Stage |
| 339 TranslateMatrixStrategy(SkVector offset) | |
| 340 : fXOffset{X(offset)} | |
| 341 , fYOffset{Y(offset)} { } | |
| 342 | |
| 343 void processPoints(Sk4s* xs, Sk4s* ys) { | |
| 344 *xs = *xs + fXOffset; | |
| 345 *ys = *ys + fYOffset; | |
| 346 } | |
| 347 | |
| 348 template <typename Next> | |
| 349 bool maybeProcessSpan(Span span, Next* next) { | |
| 350 SkPoint start; SkScalar length; int count; | |
| 351 std::tie(start, length, count) = span; | |
| 352 next->pointSpan(Span{start + SkPoint{fXOffset[0], fYOffset[0]}, length,
count}); | |
| 353 return true; | |
| 354 } | |
| 355 | |
| 356 private: | |
| 357 const Sk4s fXOffset, fYOffset; | |
| 358 }; | |
| 359 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 143 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
| 360 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; | 144 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; |
| 361 | 145 |
| 362 class ScaleMatrixStrategy { | |
| 363 public: | |
| 364 ScaleMatrixStrategy(SkVector offset, SkVector scale) | |
| 365 : fXOffset{X(offset)}, fYOffset{Y(offset)} | |
| 366 , fXScale{X(scale)}, fYScale{Y(scale)} { } | |
| 367 void processPoints(Sk4s* xs, Sk4s* ys) { | |
| 368 *xs = *xs * fXScale + fXOffset; | |
| 369 *ys = *ys * fYScale + fYOffset; | |
| 370 } | |
| 371 | |
| 372 template <typename Next> | |
| 373 bool maybeProcessSpan(Span span, Next* next) { | |
| 374 SkPoint start; SkScalar length; int count; | |
| 375 std::tie(start, length, count) = span; | |
| 376 SkPoint newStart = | |
| 377 SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] +
fYOffset[0]}; | |
| 378 SkScalar newLength = length * fXScale[0]; | |
| 379 next->pointSpan(Span{newStart, newLength, count}); | |
| 380 return true; | |
| 381 } | |
| 382 | |
| 383 private: | |
| 384 const Sk4s fXOffset, fYOffset; | |
| 385 const Sk4s fXScale, fYScale; | |
| 386 }; | |
| 387 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 146 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
| 388 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; | 147 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; |
| 389 | 148 |
| 390 class AffineMatrixStrategy { | |
| 391 public: | |
| 392 AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew) | |
| 393 : fXOffset{X(offset)}, fYOffset{Y(offset)} | |
| 394 , fXScale{X(scale)}, fYScale{Y(scale)} | |
| 395 , fXSkew{X(skew)}, fYSkew{Y(skew)} { } | |
| 396 void processPoints(Sk4s* xs, Sk4s* ys) { | |
| 397 Sk4s newXs = fXScale * *xs + fXSkew * *ys + fXOffset; | |
| 398 Sk4s newYs = fYSkew * *xs + fYScale * *ys + fYOffset; | |
| 399 | |
| 400 *xs = newXs; | |
| 401 *ys = newYs; | |
| 402 } | |
| 403 | |
| 404 template <typename Next> | |
| 405 bool maybeProcessSpan(Span span, Next* next) { | |
| 406 return false; | |
| 407 } | |
| 408 | |
| 409 private: | |
| 410 const Sk4s fXOffset, fYOffset; | |
| 411 const Sk4s fXScale, fYScale; | |
| 412 const Sk4s fXSkew, fYSkew; | |
| 413 }; | |
| 414 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 149 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
| 415 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; | 150 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; |
| 416 | 151 |
| 417 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( | 152 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( |
| 418 SkLinearBitmapPipeline::PointProcessorInterface* next, | 153 SkLinearBitmapPipeline::PointProcessorInterface* next, |
| 419 const SkMatrix& inverse, | 154 const SkMatrix& inverse, |
| 420 SkLinearBitmapPipeline::MatrixStage* matrixProc) { | 155 SkLinearBitmapPipeline::MatrixStage* matrixProc) { |
| 421 if (inverse.hasPerspective()) { | 156 if (inverse.hasPerspective()) { |
| 422 SkFAIL("Not implemented."); | 157 SkFAIL("Not implemented."); |
| 423 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { | 158 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 434 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0
f) { | 169 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0
f) { |
| 435 matrixProc->Initialize<TranslateMatrix<>>( | 170 matrixProc->Initialize<TranslateMatrix<>>( |
| 436 next, | 171 next, |
| 437 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); | 172 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); |
| 438 } else { | 173 } else { |
| 439 return next; | 174 return next; |
| 440 } | 175 } |
| 441 return matrixProc->get(); | 176 return matrixProc->get(); |
| 442 } | 177 } |
| 443 | 178 |
| 179 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 180 // Bilerp Expansion Stage |
| 444 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 181 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
| 445 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac
e { | 182 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac
e { |
| 446 public: | 183 public: |
| 447 ExpandBilerp(Next* next) : fNext{next} { } | 184 ExpandBilerp(Next* next) : fNext{next} { } |
| 448 | 185 |
| 449 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { | 186 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
| 450 SkASSERT(0 < n && n < 4); | 187 SkASSERT(0 < n && n < 4); |
| 451 // px00 px10 px01 px11 | 188 // px00 px10 px01 px11 |
| 452 const Sk4s kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, | 189 const Sk4s kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, |
| 453 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; | 190 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 484 SkFilterQuality filterQuailty, | 221 SkFilterQuality filterQuailty, |
| 485 SkLinearBitmapPipeline::FilterStage* filterProc) { | 222 SkLinearBitmapPipeline::FilterStage* filterProc) { |
| 486 if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) { | 223 if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) { |
| 487 return next; | 224 return next; |
| 488 } else { | 225 } else { |
| 489 filterProc->Initialize<ExpandBilerp<>>(next); | 226 filterProc->Initialize<ExpandBilerp<>>(next); |
| 490 return filterProc->get(); | 227 return filterProc->get(); |
| 491 } | 228 } |
| 492 } | 229 } |
| 493 | 230 |
| 494 class ClampStrategy { | 231 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 495 public: | 232 // Tile Stage |
| 496 ClampStrategy(X max) | |
| 497 : fXMin{0.0f} | |
| 498 , fXMax{max - 1.0f} { } | |
| 499 ClampStrategy(Y max) | |
| 500 : fYMin{0.0f} | |
| 501 , fYMax{max - 1.0f} { } | |
| 502 ClampStrategy(SkSize max) | |
| 503 : fXMin{0.0f} | |
| 504 , fYMin{0.0f} | |
| 505 , fXMax{X(max) - 1.0f} | |
| 506 , fYMax{Y(max) - 1.0f} { } | |
| 507 | |
| 508 void processPoints(Sk4s* xs, Sk4s* ys) { | |
| 509 *xs = Sk4s::Min(Sk4s::Max(*xs, fXMin), fXMax); | |
| 510 *ys = Sk4s::Min(Sk4s::Max(*ys, fYMin), fYMax); | |
| 511 } | |
| 512 | |
| 513 template <typename Next> | |
| 514 bool maybeProcessSpan(Span originalSpan, Next* next) { | |
| 515 SkASSERT(!originalSpan.isEmpty()); | |
| 516 SkPoint start; SkScalar length; int count; | |
| 517 std::tie(start, length, count) = originalSpan; | |
| 518 SkScalar xMin = fXMin[0]; | |
| 519 SkScalar xMax = fXMax[0] + 1.0f; | |
| 520 SkScalar yMin = fYMin[0]; | |
| 521 SkScalar yMax = fYMax[0]; | |
| 522 SkScalar x = X(start); | |
| 523 SkScalar y = std::min(std::max<SkScalar>(yMin, Y(start)), yMax); | |
| 524 | |
| 525 Span span{{x, y}, length, count}; | |
| 526 | |
| 527 if (span.completelyWithin(xMin, xMax)) { | |
| 528 next->pointSpan(span); | |
| 529 return true; | |
| 530 } | |
| 531 if (1 == count || 0.0f == length) { | |
| 532 return false; | |
| 533 } | |
| 534 | |
| 535 SkScalar dx = length / (count - 1); | |
| 536 | |
| 537 // A B C | |
| 538 // +-------+-------+-------++-------+-------+-------+ +-------+-----
--++------ | |
| 539 // | *---*|---*---|*---*--||-*---*-|---*---|*---...| |--*---*|---*-
--||*---*.... | |
| 540 // | | | || | | | ... | |
|| | |
| 541 // | | | || | | | | |
|| | |
| 542 // +-------+-------+-------++-------+-------+-------+ +-------+-----
--++------ | |
| 543 // ^
^ | |
| 544 // | xMin xMax-
1 | xMax | |
| 545 // | |
| 546 // *---*---*---... - track of samples. * = sample | |
| 547 // | |
| 548 // +-+ || | |
| 549 // | | - pixels in source space. || - tile border. | |
| 550 // +-+ || | |
| 551 // | |
| 552 // The length from A to B is the length in source space or 4 * dx or (co
unt - 1) * dx | |
| 553 // where dx is the distance between samples. There are 5 destination pix
els | |
| 554 // corresponding to 5 samples specified in the A, B span. The distance f
rom A to the next | |
| 555 // span starting at C is 5 * dx, so count * dx. | |
| 556 // Remember, count is the number of pixels needed for the destination an
d the number of | |
| 557 // samples. | |
| 558 // Overall Strategy: | |
| 559 // * Under - for portions of the span < xMin, take the color at pixel {x
Min, y} and use it | |
| 560 // to fill in the 5 pixel sampled from A to B. | |
| 561 // * Middle - for the portion of the span between xMin and xMax sample n
ormally. | |
| 562 // * Over - for the portion of the span > xMax, take the color at pixel
{xMax-1, y} and | |
| 563 // use it to fill in the rest of the destination pixels. | |
| 564 if (dx >= 0) { | |
| 565 Span leftClamped = span.breakAt(xMin, dx); | |
| 566 if (!leftClamped.isEmpty()) { | |
| 567 leftClamped.clampToSinglePixel({xMin, y}); | |
| 568 next->pointSpan(leftClamped); | |
| 569 } | |
| 570 Span middle = span.breakAt(xMax, dx); | |
| 571 if (!middle.isEmpty()) { | |
| 572 next->pointSpan(middle); | |
| 573 } | |
| 574 if (!span.isEmpty()) { | |
| 575 span.clampToSinglePixel({xMax - 1, y}); | |
| 576 next->pointSpan(span); | |
| 577 } | |
| 578 } else { | |
| 579 Span rightClamped = span.breakAt(xMax, dx); | |
| 580 if (!rightClamped.isEmpty()) { | |
| 581 rightClamped.clampToSinglePixel({xMax - 1, y}); | |
| 582 next->pointSpan(rightClamped); | |
| 583 } | |
| 584 Span middle = span.breakAt(xMin, dx); | |
| 585 if (!middle.isEmpty()) { | |
| 586 next->pointSpan(middle); | |
| 587 } | |
| 588 if (!span.isEmpty()) { | |
| 589 span.clampToSinglePixel({xMin, y}); | |
| 590 next->pointSpan(span); | |
| 591 } | |
| 592 } | |
| 593 return true; | |
| 594 } | |
| 595 | |
| 596 template <typename Next> | |
| 597 bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) { | |
| 598 return false; | |
| 599 } | |
| 600 | |
| 601 private: | |
| 602 const Sk4s fXMin{SK_FloatNegativeInfinity}; | |
| 603 const Sk4s fYMin{SK_FloatNegativeInfinity}; | |
| 604 const Sk4s fXMax{SK_FloatInfinity}; | |
| 605 const Sk4s fYMax{SK_FloatInfinity}; | |
| 606 }; | |
| 607 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 233 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
| 608 using Clamp = BilerpProcessor<ClampStrategy, Next>; | 234 using Clamp = BilerpProcessor<ClampStrategy, Next>; |
| 609 | 235 |
| 610 static SkScalar tile_mod(SkScalar x, SkScalar base) { | |
| 611 return x - std::floor(x / base) * base; | |
| 612 } | |
| 613 | |
| 614 class RepeatStrategy { | |
| 615 public: | |
| 616 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { } | |
| 617 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { } | |
| 618 RepeatStrategy(SkSize max) | |
| 619 : fXMax{X(max)} | |
| 620 , fXInvMax{1.0f / X(max)} | |
| 621 , fYMax{Y(max)} | |
| 622 , fYInvMax{1.0f / Y(max)} { } | |
| 623 | |
| 624 void processPoints(Sk4s* xs, Sk4s* ys) { | |
| 625 Sk4s divX = (*xs * fXInvMax).floor(); | |
| 626 Sk4s divY = (*ys * fYInvMax).floor(); | |
| 627 Sk4s baseX = (divX * fXMax); | |
| 628 Sk4s baseY = (divY * fYMax); | |
| 629 *xs = *xs - baseX; | |
| 630 *ys = *ys - baseY; | |
| 631 } | |
| 632 | |
| 633 template <typename Next> | |
| 634 bool maybeProcessSpan(Span originalSpan, Next* next) { | |
| 635 SkASSERT(!originalSpan.isEmpty()); | |
| 636 SkPoint start; SkScalar length; int count; | |
| 637 std::tie(start, length, count) = originalSpan; | |
| 638 // Make x and y in range on the tile. | |
| 639 SkScalar x = tile_mod(X(start), fXMax[0]); | |
| 640 SkScalar y = tile_mod(Y(start), fYMax[0]); | |
| 641 SkScalar xMax = fXMax[0]; | |
| 642 SkScalar xMin = 0.0f; | |
| 643 SkScalar dx = length / (count - 1); | |
| 644 | |
| 645 // No need trying to go fast because the steps are larger than a tile or
there is one point. | |
| 646 if (SkScalarAbs(dx) >= xMax || count <= 1) { | |
| 647 return false; | |
| 648 } | |
| 649 | |
| 650 // A B C D Z | |
| 651 // +-------+-------+-------++-------+-------+-------++ +-------+----
---++------ | |
| 652 // | | *---|*---*--||-*---*-|---*---|*---*--|| |--*---*|
|| | |
| 653 // | | | || | | || ... | |
|| | |
| 654 // | | | || | | || | |
|| | |
| 655 // +-------+-------+-------++-------+-------+-------++ +-------+----
---++------ | |
| 656 // ^^ ^^
^^ | |
| 657 // xMax || xMin xMax || xMin xM
ax || xMin | |
| 658 // | |
| 659 // *---*---*---... - track of samples. * = sample | |
| 660 // | |
| 661 // +-+ || | |
| 662 // | | - pixels in source space. || - tile border. | |
| 663 // +-+ || | |
| 664 // | |
| 665 // | |
| 666 // The given span starts at A and continues on through several tiles to
sample point Z. | |
| 667 // The idea is to break this into several spans one on each tile the ent
ire span | |
| 668 // intersects. The A to B span only covers a partial tile and has a coun
t of 3 and the | |
| 669 // distance from A to B is (count - 1) * dx or 2 * dx. The distance from
A to the start of | |
| 670 // the next span is count * dx or 3 * dx. Span C to D covers an entire t
ile has a count | |
| 671 // of 5 and a length of 4 * dx. Remember, count is the number of pixels
needed for the | |
| 672 // destination and the number of samples. | |
| 673 // | |
| 674 // Overall Strategy: | |
| 675 // While the span hangs over the edge of the tile, draw the span coverin
g the tile then | |
| 676 // slide the span over to the next tile. | |
| 677 | |
| 678 // The guard could have been count > 0, but then a bunch of math would b
e done in the | |
| 679 // common case. | |
| 680 | |
| 681 Span span({x,y}, length, count); | |
| 682 if (dx > 0) { | |
| 683 while (!span.isEmpty() && span.endX() > xMax) { | |
| 684 Span toDraw = span.breakAt(xMax, dx); | |
| 685 next->pointSpan(toDraw); | |
| 686 span.offset(-xMax); | |
| 687 } | |
| 688 } else { | |
| 689 while (!span.isEmpty() && span.endX() < xMin) { | |
| 690 Span toDraw = span.breakAt(xMin, dx); | |
| 691 next->pointSpan(toDraw); | |
| 692 span.offset(xMax); | |
| 693 } | |
| 694 } | |
| 695 | |
| 696 // All on a single tile. | |
| 697 if (!span.isEmpty()) { | |
| 698 next->pointSpan(span); | |
| 699 } | |
| 700 | |
| 701 return true; | |
| 702 } | |
| 703 | |
| 704 template <typename Next> | |
| 705 bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) { | |
| 706 return false; | |
| 707 } | |
| 708 | |
| 709 private: | |
| 710 const Sk4s fXMax{0.0f}; | |
| 711 const Sk4s fXInvMax{0.0f}; | |
| 712 const Sk4s fYMax{0.0f}; | |
| 713 const Sk4s fYInvMax{0.0f}; | |
| 714 }; | |
| 715 | |
| 716 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 236 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
| 717 using Repeat = BilerpProcessor<RepeatStrategy, Next>; | 237 using Repeat = BilerpProcessor<RepeatStrategy, Next>; |
| 718 | 238 |
| 719 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( | 239 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( |
| 720 SkLinearBitmapPipeline::BilerpProcessorInterface* next, | 240 SkLinearBitmapPipeline::BilerpProcessorInterface* next, |
| 721 SkSize dimensions, | 241 SkSize dimensions, |
| 722 SkShader::TileMode xMode, | 242 SkShader::TileMode xMode, |
| 723 SkShader::TileMode yMode, | 243 SkShader::TileMode yMode, |
| 724 SkLinearBitmapPipeline::TileStage* tileProcXOrBoth, | 244 SkLinearBitmapPipeline::TileStage* tileProcXOrBoth, |
| 725 SkLinearBitmapPipeline::TileStage* tileProcY) { | 245 SkLinearBitmapPipeline::TileStage* tileProcY) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 755 tileProcXOrBoth->Initialize<Repeat<>>(tileProcY->get(), X(dimens
ions)); | 275 tileProcXOrBoth->Initialize<Repeat<>>(tileProcY->get(), X(dimens
ions)); |
| 756 break; | 276 break; |
| 757 case SkShader::kMirror_TileMode: | 277 case SkShader::kMirror_TileMode: |
| 758 SkFAIL("Not implemented."); | 278 SkFAIL("Not implemented."); |
| 759 break; | 279 break; |
| 760 } | 280 } |
| 761 } | 281 } |
| 762 return tileProcXOrBoth->get(); | 282 return tileProcXOrBoth->get(); |
| 763 } | 283 } |
| 764 | 284 |
| 285 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 286 // Source Sampling Stage |
| 765 class sRGBFast { | 287 class sRGBFast { |
| 766 public: | 288 public: |
| 767 static Sk4s VECTORCALL sRGBToLinear(Sk4s pixel) { | 289 static Sk4s VECTORCALL sRGBToLinear(Sk4s pixel) { |
| 768 Sk4s l = pixel * pixel; | 290 Sk4s l = pixel * pixel; |
| 769 return Sk4s{l[0], l[1], l[2], pixel[3]}; | 291 return Sk4s{l[0], l[1], l[2], pixel[3]}; |
| 770 } | 292 } |
| 771 }; | 293 }; |
| 772 | 294 |
| 773 enum class ColorOrder { | 295 enum class ColorOrder { |
| 774 kRGBA = false, | 296 kRGBA = false, |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1021 sampleStage->Initialize<Sampler<Pixel8888LBGR>>(next, srcPixmap)
; | 543 sampleStage->Initialize<Sampler<Pixel8888LBGR>>(next, srcPixmap)
; |
| 1022 } | 544 } |
| 1023 break; | 545 break; |
| 1024 default: | 546 default: |
| 1025 SkFAIL("Not implemented. Unsupported src"); | 547 SkFAIL("Not implemented. Unsupported src"); |
| 1026 break; | 548 break; |
| 1027 } | 549 } |
| 1028 return sampleStage->get(); | 550 return sampleStage->get(); |
| 1029 } | 551 } |
| 1030 | 552 |
| 553 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 554 // Pixel Placement Stage |
| 1031 template <SkAlphaType alphaType> | 555 template <SkAlphaType alphaType> |
| 1032 class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface { | 556 class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface { |
| 1033 public: | 557 public: |
| 1034 void VECTORCALL placePixel(Sk4f pixel) override { | 558 void VECTORCALL placePixel(Sk4f pixel) override { |
| 1035 PlacePixel(fDst, pixel, 0); | 559 PlacePixel(fDst, pixel, 0); |
| 1036 fDst += 1; | 560 fDst += 1; |
| 1037 } | 561 } |
| 1038 | 562 |
| 1039 void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override { | 563 void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override { |
| 1040 SkPM4f* dst = fDst; | 564 SkPM4f* dst = fDst; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1071 if (alphaType == kUnpremul_SkAlphaType) { | 595 if (alphaType == kUnpremul_SkAlphaType) { |
| 1072 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>(); | 596 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>(); |
| 1073 } else { | 597 } else { |
| 1074 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType | 598 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType |
| 1075 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>(); | 599 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>(); |
| 1076 } | 600 } |
| 1077 return placerStage->get(); | 601 return placerStage->get(); |
| 1078 } | 602 } |
| 1079 } // namespace | 603 } // namespace |
| 1080 | 604 |
| 605 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 1081 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {} | 606 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {} |
| 1082 | 607 |
| 1083 SkLinearBitmapPipeline::SkLinearBitmapPipeline( | 608 SkLinearBitmapPipeline::SkLinearBitmapPipeline( |
| 1084 const SkMatrix& inverse, | 609 const SkMatrix& inverse, |
| 1085 SkFilterQuality filterQuality, | 610 SkFilterQuality filterQuality, |
| 1086 SkShader::TileMode xTile, SkShader::TileMode yTile, | 611 SkShader::TileMode xTile, SkShader::TileMode yTile, |
| 1087 const SkPixmap& srcPixmap) { | 612 const SkPixmap& srcPixmap) { |
| 1088 SkSize size = SkSize::Make(srcPixmap.width(), srcPixmap.height()); | 613 SkSize size = SkSize::Make(srcPixmap.width(), srcPixmap.height()); |
| 1089 const SkImageInfo& srcImageInfo = srcPixmap.info(); | 614 const SkImageInfo& srcImageInfo = srcPixmap.info(); |
| 1090 | 615 |
| 1091 // As the stages are built, the chooser function may skip a stage. For examp
le, with the | 616 // As the stages are built, the chooser function may skip a stage. For examp
le, with the |
| 1092 // identity matrix, the matrix stage is skipped, and the tilerStage is the f
irst stage. | 617 // identity matrix, the matrix stage is skipped, and the tilerStage is the f
irst stage. |
| 1093 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelS
tage); | 618 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelS
tage); |
| 1094 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp
leStage); | 619 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp
leStage); |
| 1095 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX
OrBothStage, | 620 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX
OrBothStage, |
| 1096 &fTileYStage); | 621 &fTileYStage); |
| 1097 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage
); | 622 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage
); |
| 1098 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); | 623 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); |
| 1099 } | 624 } |
| 1100 | 625 |
| 1101 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { | 626 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { |
| 1102 SkASSERT(count > 0); | 627 SkASSERT(count > 0); |
| 1103 fPixelStage->setDestination(dst); | 628 fPixelStage->setDestination(dst); |
| 1104 // The count and length arguments start out in a precise relation in order t
o keep the | 629 // The count and length arguments start out in a precise relation in order t
o keep the |
| 1105 // math correct through the different stages. Count is the number of pixel t
o produce. | 630 // math correct through the different stages. Count is the number of pixel t
o produce. |
| 1106 // Since the code samples at pixel centers, length is the distance from the
center of the | 631 // Since the code samples at pixel centers, length is the distance from the
center of the |
| 1107 // first pixel to the center of the last pixel. This implies that length is
count-1. | 632 // first pixel to the center of the last pixel. This implies that length is
count-1. |
| 1108 fFirstStage->pointSpan(Span{SkPoint{x + 0.5f, y + 0.5f}, count - 1.0f, count
}); | 633 fFirstStage->pointSpan(Span{SkPoint{x + 0.5f, y + 0.5f}, count - 1.0f, count
}); |
| 1109 } | 634 } |
| OLD | NEW |