Chromium Code Reviews| 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 |
| 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 | 16 |
| 17 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. | 17 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. |
| 18 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 | 18 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
| 19 #define VECTORCALL __vectorcall | 19 #define VECTORCALL __vectorcall |
| 20 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) | 20 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) |
| 21 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) | 21 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) |
| 22 #else | 22 #else |
| 23 #define VECTORCALL | 23 #define VECTORCALL |
| 24 #endif | 24 #endif |
| 25 | 25 |
| 26 class SkLinearBitmapPipeline::PointProcessorInterface { | 26 class SkLinearBitmapPipeline::PointProcessorInterface { |
| 27 public: | 27 public: |
| 28 virtual ~PointProcessorInterface() { } | 28 virtual ~PointProcessorInterface() { } |
| 29 virtual void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) = 0; | 29 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; |
| 30 virtual void VECTORCALL pointList4(Sk4f xs, Sk4f ys) = 0; | 30 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; |
| 31 | 31 |
| 32 // The pointSpan method efficiently process horizontal spans of pixels. | 32 // The pointSpan method efficiently process horizontal spans of pixels. |
| 33 // * start - the point where to start the span. | 33 // * start - the point where to start the span. |
| 34 // * length - the number of pixels to traverse in source space. | 34 // * length - the number of pixels to traverse in source space. |
| 35 // * count - the number of pixels to produce in destination space. | 35 // * count - the number of pixels to produce in destination space. |
| 36 // Both start and length are mapped through the inversion matrix to produce values in source | 36 // Both start and length are mapped through the inversion matrix to produce values in source |
| 37 // space. After the matrix operation, the tilers may break the spans up into smaller spans. | 37 // space. After the matrix operation, the tilers may break the spans up into smaller spans. |
| 38 // The tilers can produce spans that seem nonsensical. | 38 // The tilers can produce spans that seem nonsensical. |
| 39 // * The clamp tiler can create spans with length of 0. This indicates to co py an edge pixel out | 39 // * The clamp tiler can create spans with length of 0. This indicates to co py an edge pixel out |
| 40 // to the edge of the destination scan. | 40 // to the edge of the destination scan. |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 51 // | | | | 51 // | | | |
| 52 // | px00 | px10 | | 52 // | px00 | px10 | |
| 53 // | 0 | 1 | | 53 // | 0 | 1 | |
| 54 // +--------+--------+ | 54 // +--------+--------+ |
| 55 // | | | | 55 // | | | |
| 56 // | px01 | px11 | | 56 // | px01 | px11 | |
| 57 // | 2 | 3 | | 57 // | 2 | 3 | |
| 58 // +--------+--------+ | 58 // +--------+--------+ |
| 59 // These pixels coordinates are arranged in the following order in xs and ys : | 59 // These pixels coordinates are arranged in the following order in xs and ys : |
| 60 // px00 px10 px01 px11 | 60 // px00 px10 px01 px11 |
| 61 virtual void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) = 0; | 61 virtual void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) = 0; |
| 62 }; | 62 }; |
| 63 | 63 |
| 64 class SkLinearBitmapPipeline::PixelPlacerInterface { | 64 class SkLinearBitmapPipeline::PixelPlacerInterface { |
| 65 public: | 65 public: |
| 66 virtual ~PixelPlacerInterface() { } | 66 virtual ~PixelPlacerInterface() { } |
| 67 virtual void setDestination(SkPM4f* dst) = 0; | 67 virtual void setDestination(SkPM4f* dst) = 0; |
| 68 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; | 68 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; |
| 69 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0 ; | 69 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0 ; |
| 70 }; | 70 }; |
| 71 | 71 |
| 72 namespace { | 72 namespace { |
| 73 | 73 |
| 74 struct X { | 74 struct X { |
| 75 explicit X(SkScalar val) : fVal{val} { } | 75 explicit X(SkScalar val) : fVal{val} { } |
| 76 explicit X(SkPoint pt) : fVal{pt.fX} { } | 76 explicit X(SkPoint pt) : fVal{pt.fX} { } |
| 77 explicit X(SkSize s) : fVal{s.fWidth} { } | 77 explicit X(SkSize s) : fVal{s.fWidth} { } |
| 78 explicit X(SkISize s) : fVal(s.fWidth) { } | 78 explicit X(SkISize s) : fVal(s.fWidth) { } |
| 79 operator float () const {return fVal;} | 79 operator SkScalar () const {return fVal;} |
| 80 private: | 80 private: |
| 81 float fVal; | 81 SkScalar fVal; |
| 82 }; | 82 }; |
| 83 | 83 |
| 84 struct Y { | 84 struct Y { |
| 85 explicit Y(SkScalar val) : fVal{val} { } | 85 explicit Y(SkScalar val) : fVal{val} { } |
| 86 explicit Y(SkPoint pt) : fVal{pt.fY} { } | 86 explicit Y(SkPoint pt) : fVal{pt.fY} { } |
| 87 explicit Y(SkSize s) : fVal{s.fHeight} { } | 87 explicit Y(SkSize s) : fVal{s.fHeight} { } |
| 88 explicit Y(SkISize s) : fVal(s.fHeight) { } | 88 explicit Y(SkISize s) : fVal(s.fHeight) { } |
| 89 operator float () const {return fVal;} | 89 operator SkScalar () const {return fVal;} |
| 90 private: | 90 private: |
| 91 float fVal; | 91 SkScalar fVal; |
| 92 }; | 92 }; |
| 93 | 93 |
| 94 template <typename Stage> | 94 template <typename Stage> |
| 95 void span_fallback(SkPoint start, SkScalar length, int count, Stage* stage) { | 95 void span_fallback(SkPoint start, SkScalar length, int count, Stage* stage) { |
| 96 // If count == 1 use PointListFew instead. | 96 Sk4f xs{X(start)}; |
| 97 SkASSERT(count > 1); | 97 Sk4f ys{Y(start)}; |
| 98 | 98 Sk4s fourDx; |
| 99 float dx = length / (count - 1); | 99 if (count > 1) { |
| 100 Sk4f Xs = Sk4f(X(start)) + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * Sk4f{dx}; | 100 SkScalar dx = length / (count - 1); |
| 101 Sk4f Ys{Y(start)}; | 101 xs = xs + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * dx; |
| 102 Sk4f fourDx = {4.0f * dx}; | 102 // Only used if count is >= 4. |
| 103 fourDx = Sk4f{4.0f * dx}; | |
| 104 } | |
| 103 | 105 |
| 104 while (count >= 4) { | 106 while (count >= 4) { |
| 105 stage->pointList4(Xs, Ys); | 107 stage->pointList4(xs, ys); |
| 106 Xs = Xs + fourDx; | 108 xs = xs + fourDx; |
| 107 count -= 4; | 109 count -= 4; |
| 108 } | 110 } |
| 109 if (count > 0) { | 111 if (count > 0) { |
| 110 stage->pointListFew(count, Xs, Ys); | 112 stage->pointListFew(count, xs, ys); |
| 111 } | 113 } |
| 112 } | 114 } |
| 113 | 115 |
| 114 // PointProcessor uses a strategy to help complete the work of the different sta ges. The strategy | 116 // PointProcessor uses a strategy to help complete the work of the different sta ges. The strategy |
| 115 // must implement the following methods: | 117 // must implement the following methods: |
| 116 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. | 118 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. |
| 117 // * maybeProcessSpan(start, length, count) - This represents a horizontal serie s of pixels | 119 // * maybeProcessSpan(start, length, count) - This represents a horizontal serie s of pixels |
| 118 // to work over. | 120 // to work over. |
| 119 // start - is the starting pixel. This is in destination space before the matr ix stage, and in | 121 // start - is the starting pixel. This is in destination space before the matr ix stage, and in |
| 120 // source space after the matrix stage. | 122 // source space after the matrix stage. |
| 121 // length - is this distance between the first pixel center and the last pixel center. Like start, | 123 // length - is this distance between the first pixel center and the last pixel center. Like start, |
| 122 // this is in destination space before the matrix stage, and in source space after. | 124 // this is in destination space before the matrix stage, and in source space after. |
| 123 // count - the number of pixels in source space to produce. | 125 // count - the number of pixels in source space to produce. |
| 124 // next - a pointer to the next stage. | 126 // next - a pointer to the next stage. |
| 125 // maybeProcessSpan - returns false if it can not process the span and needs t o fallback to | 127 // maybeProcessSpan - returns false if it can not process the span and needs t o fallback to |
| 126 // point lists for processing. | 128 // point lists for processing. |
| 127 template<typename Strategy, typename Next> | 129 template<typename Strategy, typename Next> |
| 128 class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterf ace { | 130 class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterf ace { |
| 129 public: | 131 public: |
| 130 template <typename... Args> | 132 template <typename... Args> |
| 131 PointProcessor(Next* next, Args&&... args) | 133 PointProcessor(Next* next, Args&&... args) |
| 132 : fNext{next} | 134 : fNext{next} |
| 133 , fStrategy{std::forward<Args>(args)...}{ } | 135 , fStrategy{std::forward<Args>(args)...}{ } |
| 134 | 136 |
| 135 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 137 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
| 136 fStrategy.processPoints(&xs, &ys); | 138 fStrategy.processPoints(&xs, &ys); |
| 137 fNext->pointListFew(n, xs, ys); | 139 fNext->pointListFew(n, xs, ys); |
| 138 } | 140 } |
| 139 | 141 |
| 140 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 142 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
| 141 fStrategy.processPoints(&xs, &ys); | 143 fStrategy.processPoints(&xs, &ys); |
| 142 fNext->pointList4(xs, ys); | 144 fNext->pointList4(xs, ys); |
| 143 } | 145 } |
| 144 | 146 |
| 145 void pointSpan(SkPoint start, SkScalar length, int count) override { | 147 void pointSpan(SkPoint start, SkScalar length, int count) override { |
| 146 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { | 148 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { |
| 147 span_fallback(start, length, count, this); | 149 span_fallback(start, length, count, this); |
| 148 } | 150 } |
| 149 } | 151 } |
| 150 | 152 |
| 151 private: | 153 private: |
| 152 Next* const fNext; | 154 Next* const fNext; |
| 153 Strategy fStrategy; | 155 Strategy fStrategy; |
| 154 }; | 156 }; |
| 155 | 157 |
| 156 // See PointProcessor for responsibilities of Strategy. | 158 // See PointProcessor for responsibilities of Strategy. |
| 157 template<typename Strategy, typename Next> | 159 template<typename Strategy, typename Next> |
| 158 class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInte rface { | 160 class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInte rface { |
| 159 public: | 161 public: |
| 160 template <typename... Args> | 162 template <typename... Args> |
| 161 BilerpProcessor(Next* next, Args&&... args) | 163 BilerpProcessor(Next* next, Args&&... args) |
| 162 : fNext{next} | 164 : fNext{next} |
| 163 , fStrategy{std::forward<Args>(args)...}{ } | 165 , fStrategy{std::forward<Args>(args)...}{ } |
| 164 | 166 |
| 165 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 167 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
| 166 fStrategy.processPoints(&xs, &ys); | 168 fStrategy.processPoints(&xs, &ys); |
| 167 fNext->pointListFew(n, xs, ys); | 169 fNext->pointListFew(n, xs, ys); |
| 168 } | 170 } |
| 169 | 171 |
| 170 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 172 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
| 171 fStrategy.processPoints(&xs, &ys); | 173 fStrategy.processPoints(&xs, &ys); |
| 172 fNext->pointList4(xs, ys); | 174 fNext->pointList4(xs, ys); |
| 173 } | 175 } |
| 174 | 176 |
| 175 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { | 177 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { |
| 176 fStrategy.processPoints(&xs, &ys); | 178 fStrategy.processPoints(&xs, &ys); |
| 177 fNext->bilerpList(xs, ys); | 179 fNext->bilerpList(xs, ys); |
| 178 } | 180 } |
| 179 | 181 |
| 180 void pointSpan(SkPoint start, SkScalar length, int count) override { | 182 void pointSpan(SkPoint start, SkScalar length, int count) override { |
| 181 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { | 183 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { |
| 182 span_fallback(start, length, count, this); | 184 span_fallback(start, length, count, this); |
| 183 } | 185 } |
| 184 } | 186 } |
| 185 | 187 |
| 186 private: | 188 private: |
| 187 Next* const fNext; | 189 Next* const fNext; |
| 188 Strategy fStrategy; | 190 Strategy fStrategy; |
| 189 }; | 191 }; |
| 190 | 192 |
| 191 class SkippedStage final : public SkLinearBitmapPipeline::BilerpProcessorInterfa ce { | 193 class SkippedStage final : public SkLinearBitmapPipeline::BilerpProcessorInterfa ce { |
| 192 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 194 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
| 193 SkFAIL("Skipped stage."); | 195 SkFAIL("Skipped stage."); |
| 194 } | 196 } |
| 195 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 197 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
| 196 SkFAIL("Skipped stage."); | 198 SkFAIL("Skipped stage."); |
| 197 } | 199 } |
| 198 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { | 200 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { |
| 199 SkFAIL("Skipped stage."); | 201 SkFAIL("Skipped stage."); |
| 200 } | 202 } |
| 201 void pointSpan(SkPoint start, SkScalar length, int count) override { | 203 void pointSpan(SkPoint start, SkScalar length, int count) override { |
| 202 SkFAIL("Skipped stage."); | 204 SkFAIL("Skipped stage."); |
| 203 } | 205 } |
| 204 }; | 206 }; |
| 205 | 207 |
| 206 class TranslateMatrixStrategy { | 208 class TranslateMatrixStrategy { |
| 207 public: | 209 public: |
| 208 TranslateMatrixStrategy(SkVector offset) | 210 TranslateMatrixStrategy(SkVector offset) |
| 209 : fXOffset{X(offset)} | 211 : fXOffset{X(offset)} |
| 210 , fYOffset{Y(offset)} { } | 212 , fYOffset{Y(offset)} { } |
| 211 | 213 |
| 212 void processPoints(Sk4f* xs, Sk4f* ys) { | 214 void processPoints(Sk4s* xs, Sk4s* ys) { |
| 213 *xs = *xs + fXOffset; | 215 *xs = *xs + fXOffset; |
| 214 *ys = *ys + fYOffset; | 216 *ys = *ys + fYOffset; |
| 215 } | 217 } |
| 216 | 218 |
| 217 template <typename Next> | 219 template <typename Next> |
| 218 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { | 220 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { |
| 219 next->pointSpan(start + SkPoint{fXOffset[0], fYOffset[0]}, length, count ); | 221 next->pointSpan(start + SkPoint{fXOffset[0], fYOffset[0]}, length, count ); |
| 220 return true; | 222 return true; |
| 221 } | 223 } |
| 222 | 224 |
| 223 private: | 225 private: |
| 224 const Sk4f fXOffset, fYOffset; | 226 const Sk4s fXOffset, fYOffset; |
| 225 }; | 227 }; |
| 226 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 228 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
| 227 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; | 229 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; |
| 228 | 230 |
| 229 class ScaleMatrixStrategy { | 231 class ScaleMatrixStrategy { |
| 230 public: | 232 public: |
| 231 ScaleMatrixStrategy(SkVector offset, SkVector scale) | 233 ScaleMatrixStrategy(SkVector offset, SkVector scale) |
| 232 : fXOffset{X(offset)}, fYOffset{Y(offset)} | 234 : fXOffset{X(offset)}, fYOffset{Y(offset)} |
| 233 , fXScale{X(scale)}, fYScale{Y(scale)} { } | 235 , fXScale{X(scale)}, fYScale{Y(scale)} { } |
| 234 void processPoints(Sk4f* xs, Sk4f* ys) { | 236 void processPoints(Sk4s* xs, Sk4s* ys) { |
| 235 *xs = *xs * fXScale + fXOffset; | 237 *xs = *xs * fXScale + fXOffset; |
| 236 *ys = *ys * fYScale + fYOffset; | 238 *ys = *ys * fYScale + fYOffset; |
| 237 } | 239 } |
| 238 | 240 |
| 239 template <typename Next> | 241 template <typename Next> |
| 240 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { | 242 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { |
| 241 SkPoint newStart = | 243 SkPoint newStart = |
| 242 SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] + fYOffset[0]}; | 244 SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] + fYOffset[0]}; |
| 243 SkScalar newLength = length * fXScale[0]; | 245 SkScalar newLength = length * fXScale[0]; |
| 244 next->pointSpan(newStart, newLength, count); | 246 next->pointSpan(newStart, newLength, count); |
| 245 return true; | 247 return true; |
| 246 } | 248 } |
| 247 | 249 |
| 248 private: | 250 private: |
| 249 const Sk4f fXOffset, fYOffset; | 251 const Sk4s fXOffset, fYOffset; |
| 250 const Sk4f fXScale, fYScale; | 252 const Sk4s fXScale, fYScale; |
| 251 }; | 253 }; |
| 252 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 254 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
| 253 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; | 255 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; |
| 254 | 256 |
| 255 class AffineMatrixStrategy { | 257 class AffineMatrixStrategy { |
| 256 public: | 258 public: |
| 257 AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew) | 259 AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew) |
| 258 : fXOffset{X(offset)}, fYOffset{Y(offset)} | 260 : fXOffset{X(offset)}, fYOffset{Y(offset)} |
| 259 , fXScale{X(scale)}, fYScale{Y(scale)} | 261 , fXScale{X(scale)}, fYScale{Y(scale)} |
| 260 , fXSkew{X(skew)}, fYSkew{Y(skew)} { } | 262 , fXSkew{X(skew)}, fYSkew{Y(skew)} { } |
| 261 void processPoints(Sk4f* xs, Sk4f* ys) { | 263 void processPoints(Sk4s* xs, Sk4s* ys) { |
| 262 Sk4f newXs = fXScale * *xs + fXSkew * *ys + fXOffset; | 264 Sk4s newXs = fXScale * *xs + fXSkew * *ys + fXOffset; |
| 263 Sk4f newYs = fYSkew * *xs + fYScale * *ys + fYOffset; | 265 Sk4s newYs = fYSkew * *xs + fYScale * *ys + fYOffset; |
| 264 | 266 |
| 265 *xs = newXs; | 267 *xs = newXs; |
| 266 *ys = newYs; | 268 *ys = newYs; |
| 267 } | 269 } |
| 268 | 270 |
| 269 template <typename Next> | 271 template <typename Next> |
| 270 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { | 272 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { |
| 271 return false; | 273 return false; |
| 272 } | 274 } |
| 273 | 275 |
| 274 private: | 276 private: |
| 275 const Sk4f fXOffset, fYOffset; | 277 const Sk4s fXOffset, fYOffset; |
| 276 const Sk4f fXScale, fYScale; | 278 const Sk4s fXScale, fYScale; |
| 277 const Sk4f fXSkew, fYSkew; | 279 const Sk4s fXSkew, fYSkew; |
| 278 }; | 280 }; |
| 279 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 281 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
| 280 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; | 282 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; |
| 281 | 283 |
| 282 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( | 284 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( |
| 283 SkLinearBitmapPipeline::PointProcessorInterface* next, | 285 SkLinearBitmapPipeline::PointProcessorInterface* next, |
| 284 const SkMatrix& inverse, | 286 const SkMatrix& inverse, |
| 285 SkLinearBitmapPipeline::MatrixStage* matrixProc) { | 287 SkLinearBitmapPipeline::MatrixStage* matrixProc) { |
| 286 if (inverse.hasPerspective()) { | 288 if (inverse.hasPerspective()) { |
| 287 SkFAIL("Not implemented."); | 289 SkFAIL("Not implemented."); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 305 return next; | 307 return next; |
| 306 } | 308 } |
| 307 return matrixProc->get(); | 309 return matrixProc->get(); |
| 308 } | 310 } |
| 309 | 311 |
| 310 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 312 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
| 311 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac e { | 313 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac e { |
| 312 public: | 314 public: |
| 313 ExpandBilerp(Next* next) : fNext{next} { } | 315 ExpandBilerp(Next* next) : fNext{next} { } |
| 314 | 316 |
| 315 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 317 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
| 316 SkASSERT(0 < n && n < 4); | 318 SkASSERT(0 < n && n < 4); |
| 317 // px00 px10 px01 px11 | 319 // px00 px10 px01 px11 |
| 318 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, | 320 const Sk4s kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, |
| 319 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; | 321 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; |
| 320 if (n >= 1) fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYO ffsets); | 322 if (n >= 1) fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYO ffsets); |
| 321 if (n >= 2) fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYO ffsets); | 323 if (n >= 2) fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYO ffsets); |
| 322 if (n >= 3) fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYO ffsets); | 324 if (n >= 3) fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYO ffsets); |
| 323 } | 325 } |
| 324 | 326 |
| 325 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 327 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { |
| 326 // px00 px10 px01 px11 | 328 // px00 px10 px01 px11 |
| 327 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, | 329 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, |
| 328 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; | 330 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; |
| 329 fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets); | 331 fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYOffsets); |
| 330 fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets); | 332 fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYOffsets); |
| 331 fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets); | 333 fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYOffsets); |
| 332 fNext->bilerpList(Sk4f{xs[3]} + kXOffsets, Sk4f{ys[3]} + kYOffsets); | 334 fNext->bilerpList(Sk4s{xs[3]} + kXOffsets, Sk4s{ys[3]} + kYOffsets); |
| 333 } | 335 } |
| 334 | 336 |
| 335 void pointSpan(SkPoint start, SkScalar length, int count) override { | 337 void pointSpan(SkPoint start, SkScalar length, int count) override { |
| 336 span_fallback(start, length, count, this); | 338 span_fallback(start, length, count, this); |
| 337 } | 339 } |
| 338 | 340 |
| 339 private: | 341 private: |
| 340 Next* const fNext; | 342 Next* const fNext; |
| 341 }; | 343 }; |
| 342 | 344 |
| 343 static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter( | 345 static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter( |
| 344 SkLinearBitmapPipeline::BilerpProcessorInterface* next, | 346 SkLinearBitmapPipeline::BilerpProcessorInterface* next, |
| 345 SkFilterQuality filterQuailty, | 347 SkFilterQuality filterQuailty, |
| 346 SkLinearBitmapPipeline::FilterStage* filterProc) { | 348 SkLinearBitmapPipeline::FilterStage* filterProc) { |
| 347 if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) { | 349 if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) { |
| 348 filterProc->Initialize<SkippedStage>(); | 350 filterProc->Initialize<SkippedStage>(); |
| 349 return next; | 351 return next; |
| 350 } else { | 352 } else { |
| 351 filterProc->Initialize<ExpandBilerp<>>(next); | 353 filterProc->Initialize<ExpandBilerp<>>(next); |
| 352 return filterProc->get(); | 354 return filterProc->get(); |
| 353 } | 355 } |
| 354 } | 356 } |
| 355 | 357 |
| 358 class Span { | |
| 359 public: | |
| 360 Span(SkPoint start, SkScalar length, int count) | |
| 361 : fStart{start} | |
| 362 , fLength(length) | |
| 363 , fCount{count} { | |
| 364 SkASSERT(std::isfinite(length)); | |
| 365 } | |
| 366 | |
| 367 bool isEmpty() const { return 0 == count(); } | |
| 368 int count() const { return fCount; } | |
| 369 SkScalar length() const { return fLength; } | |
| 370 SkScalar startX() const { return X(fStart); } | |
| 371 SkScalar endX() const { return startX() + length(); } | |
| 372 | |
| 373 bool inRange(SkScalar xMin, SkScalar xMax) const { | |
|
mtklein
2016/02/25 21:47:41
-> completelyWithin? inRange seems ambiguous abou
herb_g
2016/02/26 04:05:53
Done.
| |
| 374 SkScalar sMin, sMax; | |
| 375 std::tie(sMin, sMax) = std::minmax(startX(), endX()); | |
| 376 return xMin <= sMin && sMax <= xMax; | |
| 377 } | |
| 378 | |
| 379 void offset(SkScalar offsetX) { | |
| 380 fStart.offset(offsetX, 0.0f); | |
| 381 } | |
| 382 | |
| 383 Span breakAt(SkScalar breakX, SkScalar dx) { | |
|
mtklein
2016/02/25 21:47:41
I find the countToBreak() and lengthToBreakAndAdju
herb_g
2016/02/26 04:05:54
Done.
| |
| 384 SkPoint newStart = fStart; | |
| 385 | |
| 386 int newCount = countToBreak(breakX, dx); | |
|
mtklein
2016/02/25 21:47:41
all self calls need this->
herb_g
2016/02/26 04:05:54
Done.
| |
| 387 | |
| 388 // The length is one dx less than the count * dx like the example above. There are | |
|
mtklein
2016/02/25 21:47:40
this comment doesn't belong here given the code th
herb_g
2016/02/26 04:05:54
Done.
| |
| 389 // middleCount samples, but dx is advanced one less time to get to the l ast sample. | |
| 390 SkScalar newLength = lengthToBreakAndAdjust(newCount, dx); | |
| 391 | |
| 392 return Span{newStart, newLength, newCount}; | |
| 393 } | |
| 394 | |
| 395 Span breakAtSingleColor(SkScalar breakX, SkScalar dx) { | |
|
mtklein
2016/02/25 21:47:41
I don't understand where colors are getting involv
herb_g
2016/02/26 04:05:54
Changed the way this is done.
| |
| 396 | |
| 397 int newCount = countToBreak(breakX, dx); | |
| 398 | |
| 399 lengthToBreakAndAdjust(newCount, dx); | |
| 400 return Span{{breakX, Y(fStart)}, 0.0f, newCount}; | |
| 401 } | |
| 402 | |
| 403 template <typename Next> | |
| 404 void nextStage(Next* next) { | |
| 405 SkASSERT(next != nullptr); | |
| 406 SkASSERT(fCount > 0); | |
| 407 next->pointSpan(fStart, fLength, fCount); | |
|
mtklein
2016/02/25 21:47:41
why does this function exist? doesn't this sugges
herb_g
2016/02/26 04:05:53
This is still a work in progress. Doing it now.
| |
| 408 } | |
| 409 | |
| 410 private: | |
| 411 int countToBreak(SkScalar breakX, SkScalar dx) { | |
| 412 SkASSERT(std::isfinite(breakX)); | |
| 413 SkASSERT(std::isfinite(dx)); | |
| 414 SkScalar x = X(fStart); | |
| 415 // newCount will be at least 1. | |
| 416 int newCount = SkScalarFloorToInt((breakX - x) / dx) + 1; | |
| 417 SkASSERT(newCount > 0); | |
| 418 return newCount; | |
| 419 } | |
| 420 | |
| 421 SkScalar lengthToBreakAndAdjust(int count, SkScalar dx) { | |
| 422 SkScalar lengthToStart = count * dx; | |
| 423 fLength -= lengthToStart; | |
| 424 fCount -= count; | |
| 425 fStart = {X(fStart) + lengthToStart, Y(fStart)}; | |
| 426 // The length is one dx less than the count * dx like the example above. There are | |
|
mtklein
2016/02/25 21:47:41
there is no example above
herb_g
2016/02/26 04:05:54
Done.
| |
| 427 // middleCount samples, but dx is advanced one less time to get to the l ast sample. | |
| 428 return lengthToStart - dx; | |
| 429 } | |
| 430 | |
| 431 SkPoint fStart; | |
| 432 SkScalar fLength; | |
| 433 int fCount; | |
| 434 }; | |
| 435 | |
| 356 class ClampStrategy { | 436 class ClampStrategy { |
| 357 public: | 437 public: |
| 358 ClampStrategy(X max) | 438 ClampStrategy(X max) |
| 359 : fXMin{0.0f} | 439 : fXMin{0.0f} |
| 360 , fXMax{max - 1.0f} { } | 440 , fXMax{max - 1.0f} { } |
| 361 ClampStrategy(Y max) | 441 ClampStrategy(Y max) |
| 362 : fYMin{0.0f} | 442 : fYMin{0.0f} |
| 363 , fYMax{max - 1.0f} { } | 443 , fYMax{max - 1.0f} { } |
| 364 ClampStrategy(SkSize max) | 444 ClampStrategy(SkSize max) |
| 365 : fXMin{0.0f} | 445 : fXMin{0.0f} |
| 366 , fYMin{0.0f} | 446 , fYMin{0.0f} |
| 367 , fXMax{X(max) - 1.0f} | 447 , fXMax{X(max) - 1.0f} |
| 368 , fYMax{Y(max) - 1.0f} { } | 448 , fYMax{Y(max) - 1.0f} { } |
| 369 | 449 |
| 370 void processPoints(Sk4f* xs, Sk4f* ys) { | 450 void processPoints(Sk4s* xs, Sk4s* ys) { |
| 371 *xs = Sk4f::Min(Sk4f::Max(*xs, fXMin), fXMax); | 451 *xs = Sk4s::Min(Sk4s::Max(*xs, fXMin), fXMax); |
| 372 *ys = Sk4f::Min(Sk4f::Max(*ys, fYMin), fYMax); | 452 *ys = Sk4s::Min(Sk4s::Max(*ys, fYMin), fYMax); |
| 373 } | 453 } |
| 374 | 454 |
| 375 template <typename Next> | 455 template <typename Next> |
| 376 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { | 456 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { |
| 377 return false; | 457 SkASSERT(count > 0); |
| 458 SkASSERT(std::isfinite(length)); | |
|
mtklein
2016/02/25 21:47:41
We seem to assert this multiple times, but count >
herb_g
2016/02/26 04:05:54
Acknowledged.
| |
| 459 SkScalar xMin = fXMin[0]; | |
| 460 SkScalar xMax = fXMax[0] + 1.0f; | |
| 461 SkScalar yMin = fYMin[0]; | |
| 462 SkScalar yMax = fYMax[0]; | |
| 463 SkScalar x = X(start); | |
| 464 SkScalar y = std::min(std::max<SkScalar>(yMin, Y(start)), yMax); | |
| 465 | |
| 466 Span span{{x, y}, length, count}; | |
| 467 | |
| 468 // Handle the Span is on the tile if xMin and xMax not infinities or han dle the case where | |
|
mtklein
2016/02/25 21:47:40
please make this a sentence or delete it?
herb_g
2016/02/26 04:05:53
Done.
| |
| 469 // the x component is a pass through when xMin and xMax are infinities. | |
| 470 if (span.inRange(xMin, xMax)) { | |
| 471 span.nextStage(next); | |
| 472 return true; | |
| 473 } | |
| 474 | |
| 475 SkScalar dx = length / (count - 1); | |
| 476 | |
| 477 // This is only the case where the count is one and it is in x < xMin || xMax < x, | |
|
mtklein
2016/02/25 21:47:41
...and it it outside [xMin, xMax]?
Is it really i
herb_g
2016/02/26 04:05:54
Acknowledged.
| |
| 478 // otherwise it was handled above. | |
| 479 if (1 == count || dx < 0) { | |
|
mtklein
2016/02/25 21:47:41
if (count == 1 || length < 0) {
return false;
herb_g
2016/02/26 04:05:53
Changed logic
| |
| 480 return false; | |
| 481 } | |
| 482 | |
| 483 // A B C | |
| 484 // +-------+-------+-------++-------+-------+-------+ +-------+----- --++------ | |
| 485 // | *---*|---*---|*---*--||-*---*-|---*---|*---...| |--*---*|---*- --||*---*.... | |
| 486 // | | | || | | | ... | | || | |
| 487 // | | | || | | | | | || | |
| 488 // +-------+-------+-------++-------+-------+-------+ +-------+----- --++------ | |
| 489 // ^ ^ | |
| 490 // | xMin xMax- 1 | xMax | |
| 491 // | |
| 492 // *---*---*---... - track of samples. * = sample | |
| 493 // | |
| 494 // +-+ || | |
| 495 // | | - pixels in source space. || - tile border. | |
| 496 // +-+ || | |
| 497 // | |
| 498 // The length from A to B is the length in source space or 4 * dx or (co unt - 1) * dx | |
| 499 // where dx is the distance between samples. There are 5 destination pix els | |
| 500 // corresponding to 5 samples specified in the A, B span. The distance f rom A to the next | |
| 501 // span starting at C is 5 * dx, so count * dx. | |
| 502 // Remember, count is the number of pixels needed for the destination an d the number of | |
| 503 // samples. | |
| 504 // Overall Strategy: | |
| 505 // * Under - for portions of the span < xMin, take the color at pixel {x Min, y} and use it | |
| 506 // to fill in the 5 pixel sampled from A to B. | |
| 507 // * Middle - for the portion of the span between xMin and xMax sample n ormally. | |
| 508 // * Over - for the portion of the span > xMax, take the color at pixel {xMax-1, y} and | |
| 509 // use it to fill in the rest of the destination pixels. | |
| 510 | |
| 511 if (dx > 0) { | |
| 512 if (span.startX() < xMin) { | |
| 513 if (span.endX() > xMin) { | |
| 514 Span toDraw = span.breakAtSingleColor(xMin, dx); | |
|
mtklein
2016/02/25 21:47:40
This breakAtSingleColor seems like something Span
mtklein
2016/02/25 21:47:41
We're not drawing anything here...
herb_g
2016/02/26 04:05:54
Totally redid logic.
| |
| 515 toDraw.nextStage(next); | |
| 516 } else { | |
| 517 span.nextStage(next); | |
|
mtklein
2016/02/25 21:47:41
I don't think I follow this case. It's entirely o
herb_g
2016/02/26 04:05:54
Redid logic
| |
| 518 return true; | |
| 519 } | |
| 520 } | |
| 521 if (!span.isEmpty() && span.startX() < xMax) { | |
|
mtklein
2016/02/25 21:47:40
All these if cases are really complicated. Seems
herb_g
2016/02/26 04:05:53
Done.
| |
| 522 if (span.endX() > xMax) { | |
| 523 Span toDraw = span.breakAt(xMax, dx); | |
| 524 toDraw.nextStage(next); | |
| 525 } else { | |
| 526 span.nextStage(next); | |
| 527 return true; | |
| 528 }; | |
| 529 } | |
| 530 if (!span.isEmpty()) { | |
| 531 next->pointSpan({xMax - 1.0f, y}, 0.0f, span.count()); | |
| 532 } | |
| 533 } else { | |
|
mtklein
2016/02/25 21:47:41
How did we get dx == 0 here? Some sort of degener
herb_g
2016/02/26 04:05:54
Done.
| |
| 534 if (span.startX() > xMax) { | |
| 535 if (span.endX() < xMax) { | |
| 536 Span toDraw = span.breakAtSingleColor(xMax - 1.0f, dx); | |
| 537 toDraw.nextStage(next); | |
| 538 } else { | |
| 539 span.nextStage(next); | |
| 540 return true; | |
| 541 } | |
| 542 } | |
| 543 if (!span.isEmpty() && span.startX() > xMin) { | |
| 544 if (span.endX() < xMin) { | |
| 545 Span toDraw = span.breakAt(xMin, dx); | |
| 546 toDraw.nextStage(next); | |
| 547 } else { | |
| 548 span.nextStage(next); | |
| 549 return true; | |
| 550 } | |
| 551 } | |
| 552 if (!span.isEmpty()) { | |
| 553 next->pointSpan({xMin, y}, 0.0f, span.count()); | |
| 554 } | |
| 555 } | |
| 556 return true; | |
| 378 } | 557 } |
| 379 | 558 |
| 380 private: | 559 private: |
| 381 const Sk4f fXMin{SK_FloatNegativeInfinity}; | 560 const Sk4s fXMin{SK_FloatNegativeInfinity}; |
| 382 const Sk4f fYMin{SK_FloatNegativeInfinity}; | 561 const Sk4s fYMin{SK_FloatNegativeInfinity}; |
| 383 const Sk4f fXMax{SK_FloatInfinity}; | 562 const Sk4s fXMax{SK_FloatInfinity}; |
| 384 const Sk4f fYMax{SK_FloatInfinity}; | 563 const Sk4s fYMax{SK_FloatInfinity}; |
| 385 }; | 564 }; |
| 386 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 565 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
| 387 using Clamp = BilerpProcessor<ClampStrategy, Next>; | 566 using Clamp = BilerpProcessor<ClampStrategy, Next>; |
| 388 | 567 |
| 568 static SkScalar tile_mod(SkScalar x, SkScalar base) { | |
| 569 return x - std::floor(x / base) * base; | |
| 570 } | |
| 571 | |
| 389 class RepeatStrategy { | 572 class RepeatStrategy { |
| 390 public: | 573 public: |
| 391 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { } | 574 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { } |
| 392 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { } | 575 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { } |
| 393 RepeatStrategy(SkSize max) | 576 RepeatStrategy(SkSize max) |
| 394 : fXMax{X(max)} | 577 : fXMax{X(max)} |
| 395 , fXInvMax{1.0f / X(max)} | 578 , fXInvMax{1.0f / X(max)} |
| 396 , fYMax{Y(max)} | 579 , fYMax{Y(max)} |
| 397 , fYInvMax{1.0f / Y(max)} { } | 580 , fYInvMax{1.0f / Y(max)} { } |
| 398 | 581 |
| 399 void processPoints(Sk4f* xs, Sk4f* ys) { | 582 void processPoints(Sk4s* xs, Sk4s* ys) { |
| 400 Sk4f divX = (*xs * fXInvMax).floor(); | 583 Sk4s divX = (*xs * fXInvMax).floor(); |
| 401 Sk4f divY = (*ys * fYInvMax).floor(); | 584 Sk4s divY = (*ys * fYInvMax).floor(); |
| 402 Sk4f baseX = (divX * fXMax); | 585 Sk4s baseX = (divX * fXMax); |
| 403 Sk4f baseY = (divY * fYMax); | 586 Sk4s baseY = (divY * fYMax); |
| 404 *xs = *xs - baseX; | 587 *xs = *xs - baseX; |
| 405 *ys = *ys - baseY; | 588 *ys = *ys - baseY; |
| 406 } | 589 } |
| 407 | 590 |
| 408 template <typename Next> | 591 template <typename Next> |
| 409 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { | 592 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { |
| 410 return false; | 593 SkASSERT(count > 0); |
| 594 SkASSERT(std::isfinite(length)); | |
| 595 // Make x and y in range on the tile. | |
| 596 SkScalar x = tile_mod(X(start), fXMax[0]); | |
| 597 SkScalar y = tile_mod(Y(start), fYMax[0]); | |
| 598 SkScalar xMax = fXMax[0]; | |
| 599 SkScalar xMin = 0.0f; | |
| 600 SkScalar dx = length / (count - 1); | |
| 601 | |
| 602 if (SkScalarAbs(dx) >= xMax) { | |
| 603 return false; | |
| 604 } | |
| 605 | |
| 606 // A B C D Z | |
| 607 // +-------+-------+-------++-------+-------+-------++ +-------+---- ---++------ | |
| 608 // | | *---|*---*--||-*---*-|---*---|*---*--|| |--*---*| || | |
| 609 // | | | || | | || ... | | || | |
| 610 // | | | || | | || | | || | |
| 611 // +-------+-------+-------++-------+-------+-------++ +-------+---- ---++------ | |
| 612 // ^^ ^^ ^^ | |
| 613 // xMax || xMin xMax || xMin xM ax || xMin | |
| 614 // | |
| 615 // *---*---*---... - track of samples. * = sample | |
| 616 // | |
| 617 // +-+ || | |
| 618 // | | - pixels in source space. || - tile border. | |
| 619 // +-+ || | |
| 620 // | |
| 621 // | |
| 622 // The given span starts at A and continues on through several tiles to sample point Z. | |
| 623 // The idea is to break this into several spans one on each tile the ent ire span | |
| 624 // intersects. The A to B span only covers a partial tile and has a coun t of 3 and the | |
| 625 // distance from A to B is (count - 1) * dx or 2 * dx. The distance from A to the start of | |
| 626 // the next span is count * dx or 3 * dx. Span C to D covers an entire t ile has a count | |
| 627 // of 5 and a length of 4 * dx. Remember, count is the number of pixels needed for the | |
| 628 // destination and the number of samples. | |
| 629 // | |
| 630 // Overall Strategy: | |
| 631 // While the span hangs over the edge of the tile, draw the span coverin g the tile then | |
| 632 // slide the span over to the next tile. | |
| 633 | |
| 634 // The guard could have been count > 0, but then a bunch of math would b e done in the | |
| 635 // common case. | |
| 636 | |
| 637 Span span{{x, y}, length, count}; | |
| 638 if (dx > 0) { | |
| 639 while (!span.isEmpty() && span.endX() > xMax) { | |
| 640 Span toDraw = span.breakAt(xMax, dx); | |
| 641 toDraw.nextStage(next); | |
| 642 span.offset(-xMax); | |
| 643 } | |
| 644 } else { | |
| 645 while (!span.isEmpty() && span.endX() < xMin) { | |
| 646 Span toDraw = span.breakAt(xMin, dx); | |
| 647 toDraw.nextStage(next); | |
| 648 span.offset(xMax); | |
| 649 } | |
| 650 } | |
| 651 | |
| 652 // All on a single tile. | |
| 653 if (!span.isEmpty()) { | |
| 654 span.nextStage(next); | |
| 655 } | |
| 656 | |
| 657 return true; | |
| 411 } | 658 } |
| 412 | 659 |
| 413 private: | 660 private: |
| 414 const Sk4f fXMax{0.0f}; | 661 const Sk4s fXMax{0.0f}; |
| 415 const Sk4f fXInvMax{0.0f}; | 662 const Sk4s fXInvMax{0.0f}; |
| 416 const Sk4f fYMax{0.0f}; | 663 const Sk4s fYMax{0.0f}; |
| 417 const Sk4f fYInvMax{0.0f}; | 664 const Sk4s fYInvMax{0.0f}; |
| 418 }; | 665 }; |
| 419 | 666 |
| 420 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 667 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
| 421 using Repeat = BilerpProcessor<RepeatStrategy, Next>; | 668 using Repeat = BilerpProcessor<RepeatStrategy, Next>; |
| 422 | 669 |
| 423 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( | 670 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( |
| 424 SkLinearBitmapPipeline::BilerpProcessorInterface* next, | 671 SkLinearBitmapPipeline::BilerpProcessorInterface* next, |
| 425 SkSize dimensions, | 672 SkSize dimensions, |
| 426 SkShader::TileMode xMode, | 673 SkShader::TileMode xMode, |
| 427 SkShader::TileMode yMode, | 674 SkShader::TileMode yMode, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 462 case SkShader::kMirror_TileMode: | 709 case SkShader::kMirror_TileMode: |
| 463 SkFAIL("Not implemented."); | 710 SkFAIL("Not implemented."); |
| 464 break; | 711 break; |
| 465 } | 712 } |
| 466 } | 713 } |
| 467 return tileProcXOrBoth->get(); | 714 return tileProcXOrBoth->get(); |
| 468 } | 715 } |
| 469 | 716 |
| 470 class sRGBFast { | 717 class sRGBFast { |
| 471 public: | 718 public: |
| 472 static Sk4f VECTORCALL sRGBToLinear(Sk4f pixel) { | 719 static Sk4s VECTORCALL sRGBToLinear(Sk4s pixel) { |
| 473 Sk4f l = pixel * pixel; | 720 Sk4s l = pixel * pixel; |
| 474 return Sk4f{l[0], l[1], l[2], pixel[3]}; | 721 return Sk4s{l[0], l[1], l[2], pixel[3]}; |
| 475 } | 722 } |
| 476 }; | 723 }; |
| 477 | 724 |
| 478 template <SkColorProfileType colorProfile> | 725 template <SkColorProfileType colorProfile> |
| 479 class Passthrough8888 { | 726 class Passthrough8888 { |
| 480 public: | 727 public: |
| 481 Passthrough8888(int width, const uint32_t* src) | 728 Passthrough8888(int width, const uint32_t* src) |
| 482 : fSrc{src}, fWidth{width}{ } | 729 : fSrc{src}, fWidth{width}{ } |
| 483 | 730 |
| 484 void VECTORCALL getFewPixels(int n, Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) { | 731 void VECTORCALL getFewPixels(int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) { |
| 485 Sk4i XIs = SkNx_cast<int, float>(xs); | 732 Sk4i XIs = SkNx_cast<int, SkScalar>(xs); |
| 486 Sk4i YIs = SkNx_cast<int, float>(ys); | 733 Sk4i YIs = SkNx_cast<int, SkScalar>(ys); |
| 487 Sk4i bufferLoc = YIs * fWidth + XIs; | 734 Sk4i bufferLoc = YIs * fWidth + XIs; |
| 488 switch (n) { | 735 switch (n) { |
| 489 case 3: | 736 case 3: |
| 490 *px2 = getPixel(fSrc, bufferLoc[2]); | 737 *px2 = getPixel(fSrc, bufferLoc[2]); |
| 491 case 2: | 738 case 2: |
| 492 *px1 = getPixel(fSrc, bufferLoc[1]); | 739 *px1 = getPixel(fSrc, bufferLoc[1]); |
| 493 case 1: | 740 case 1: |
| 494 *px0 = getPixel(fSrc, bufferLoc[0]); | 741 *px0 = getPixel(fSrc, bufferLoc[0]); |
| 495 default: | 742 default: |
| 496 break; | 743 break; |
| 497 } | 744 } |
| 498 } | 745 } |
| 499 | 746 |
| 500 void VECTORCALL get4Pixels(Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2 , Sk4f* px3) { | 747 void VECTORCALL get4Pixels(Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2 , Sk4f* px3) { |
| 501 Sk4i XIs = SkNx_cast<int, float>(xs); | 748 Sk4i XIs = SkNx_cast<int, SkScalar>(xs); |
| 502 Sk4i YIs = SkNx_cast<int, float>(ys); | 749 Sk4i YIs = SkNx_cast<int, SkScalar>(ys); |
| 503 Sk4i bufferLoc = YIs * fWidth + XIs; | 750 Sk4i bufferLoc = YIs * fWidth + XIs; |
| 504 *px0 = getPixel(fSrc, bufferLoc[0]); | 751 *px0 = getPixel(fSrc, bufferLoc[0]); |
| 505 *px1 = getPixel(fSrc, bufferLoc[1]); | 752 *px1 = getPixel(fSrc, bufferLoc[1]); |
| 506 *px2 = getPixel(fSrc, bufferLoc[2]); | 753 *px2 = getPixel(fSrc, bufferLoc[2]); |
| 507 *px3 = getPixel(fSrc, bufferLoc[3]); | 754 *px3 = getPixel(fSrc, bufferLoc[3]); |
| 508 } | 755 } |
| 509 | 756 |
| 510 const uint32_t* row(int y) { return fSrc + y * fWidth[0]; } | 757 const uint32_t* row(int y) { return fSrc + y * fWidth[0]; } |
| 511 | 758 |
| 512 private: | 759 private: |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 536 // +--------+--------+ | 783 // +--------+--------+ |
| 537 // | 784 // |
| 538 // | 785 // |
| 539 // Given a pixelxy each is multiplied by a different factor derived from the fra ctional part of x | 786 // Given a pixelxy each is multiplied by a different factor derived from the fra ctional part of x |
| 540 // and y: | 787 // and y: |
| 541 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy | 788 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy |
| 542 // * px10 -> x(1 - y) = x - xy | 789 // * px10 -> x(1 - y) = x - xy |
| 543 // * px01 -> (1 - x)y = y - xy | 790 // * px01 -> (1 - x)y = y - xy |
| 544 // * px11 -> xy | 791 // * px11 -> xy |
| 545 // So x * y is calculated first and then used to calculate all the other factors . | 792 // So x * y is calculated first and then used to calculate all the other factors . |
| 546 static Sk4f VECTORCALL bilerp4(Sk4f xs, Sk4f ys, Sk4f px00, Sk4f px10, | 793 static Sk4s VECTORCALL bilerp4(Sk4s xs, Sk4s ys, Sk4f px00, Sk4f px10, |
| 547 Sk4f px01, Sk4f px11) { | 794 Sk4f px01, Sk4f px11) { |
| 548 // Calculate fractional xs and ys. | 795 // Calculate fractional xs and ys. |
| 549 Sk4f fxs = xs - xs.floor(); | 796 Sk4s fxs = xs - xs.floor(); |
| 550 Sk4f fys = ys - ys.floor(); | 797 Sk4s fys = ys - ys.floor(); |
| 551 Sk4f fxys{fxs * fys}; | 798 Sk4s fxys{fxs * fys}; |
| 552 Sk4f sum = px11 * fxys; | 799 Sk4f sum = px11 * fxys; |
| 553 sum = sum + px01 * (fys - fxys); | 800 sum = sum + px01 * (fys - fxys); |
| 554 sum = sum + px10 * (fxs - fxys); | 801 sum = sum + px10 * (fxs - fxys); |
| 555 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys); | 802 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys); |
| 556 return sum; | 803 return sum; |
| 557 } | 804 } |
| 558 | 805 |
| 559 template <typename SourceStrategy> | 806 template <typename SourceStrategy> |
| 560 class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface { | 807 class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface { |
| 561 public: | 808 public: |
| 562 template <typename... Args> | 809 template <typename... Args> |
| 563 Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args) | 810 Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args) |
| 564 : fNext{next} | 811 : fNext{next} |
| 565 , fStrategy{std::forward<Args>(args)...} { } | 812 , fStrategy{std::forward<Args>(args)...} { } |
| 566 | 813 |
| 567 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 814 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
| 568 SkASSERT(0 < n && n < 4); | 815 SkASSERT(0 < n && n < 4); |
| 569 Sk4f px0, px1, px2; | 816 Sk4f px0, px1, px2; |
| 570 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); | 817 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); |
| 571 if (n >= 1) fNext->placePixel(px0); | 818 if (n >= 1) fNext->placePixel(px0); |
| 572 if (n >= 2) fNext->placePixel(px1); | 819 if (n >= 2) fNext->placePixel(px1); |
| 573 if (n >= 3) fNext->placePixel(px2); | 820 if (n >= 3) fNext->placePixel(px2); |
| 574 } | 821 } |
| 575 | 822 |
| 576 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 823 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
| 577 Sk4f px0, px1, px2, px3; | 824 Sk4f px0, px1, px2, px3; |
| 578 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); | 825 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); |
| 579 fNext->place4Pixels(px0, px1, px2, px3); | 826 fNext->place4Pixels(px0, px1, px2, px3); |
| 580 } | 827 } |
| 581 | 828 |
| 582 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { | 829 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { |
| 583 Sk4f px00, px10, px01, px11; | 830 Sk4f px00, px10, px01, px11; |
| 584 fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11); | 831 fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11); |
| 585 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11); | 832 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11); |
| 586 fNext->placePixel(pixel); | 833 fNext->placePixel(pixel); |
| 587 } | 834 } |
| 588 | 835 |
| 589 void pointSpan(SkPoint start, SkScalar length, int count) override { | 836 void pointSpan(SkPoint start, SkScalar length, int count) override { |
| 590 span_fallback(start, length, count, this); | 837 span_fallback(start, length, count, this); |
| 591 } | 838 } |
| 592 | 839 |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 690 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp leStage); | 937 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp leStage); |
| 691 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX OrBothStage, | 938 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX OrBothStage, |
| 692 &fTileYStage); | 939 &fTileYStage); |
| 693 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage ); | 940 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage ); |
| 694 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); | 941 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); |
| 695 } | 942 } |
| 696 | 943 |
| 697 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { | 944 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { |
| 698 SkASSERT(count > 0); | 945 SkASSERT(count > 0); |
| 699 fPixelStage->setDestination(dst); | 946 fPixelStage->setDestination(dst); |
| 700 // Adjust points by 0.5, 0.5 to sample from the center of the pixels. | 947 // The count and length arguments start out in a precise relation in order t o keep the |
| 701 if (count == 1) { | 948 // math correct through the different stages. Count is the number of pixel t o produce. |
| 702 fFirstStage->pointListFew(1, Sk4f{x + 0.5f}, Sk4f{y + 0.5f}); | 949 // Since the code samples at pixel centers, length is the distance from the center of the |
| 703 } else { | 950 // first pixel to the center of the last pixel. This implies that length is count-1. |
| 704 // The count and length arguments start out in a precise relation in ord er to keep the | 951 fFirstStage->pointSpan(SkPoint{x + 0.5f, y + 0.5f}, count - 1, count); |
| 705 // math correct through the different stages. Count is the number of pix el to produce. | |
| 706 // Since the code samples at pixel centers, length is the distance from the center of the | |
| 707 // first pixel to the center of the last pixel. This implies that length is count-1. | |
| 708 fFirstStage->pointSpan(SkPoint{x + 0.5f, y + 0.5f}, count - 1, count); | |
| 709 } | |
| 710 } | 952 } |
| OLD | NEW |