| 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 |
| 10 #include "SkPM4f.h" | 10 #include "SkPM4f.h" |
| 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 #include "SkLinearBitmapPipeline_core.h" | 17 #include "SkLinearBitmapPipeline_core.h" |
| 18 #include "SkLinearBitmapPipeline_matrix.h" | 18 #include "SkLinearBitmapPipeline_matrix.h" |
| 19 #include "SkLinearBitmapPipeline_tile.h" | 19 #include "SkLinearBitmapPipeline_tile.h" |
| 20 #include "SkLinearBitmapPipeline_sample.h" |
| 20 | 21 |
| 21 class SkLinearBitmapPipeline::PointProcessorInterface { | 22 class SkLinearBitmapPipeline::PointProcessorInterface { |
| 22 public: | 23 public: |
| 23 virtual ~PointProcessorInterface() { } | 24 virtual ~PointProcessorInterface() { } |
| 25 // Take the first n (where 0 < n && n < 4) items from xs and ys and sample t
hose points. For |
| 26 // nearest neighbor, that means just taking the floor xs and ys. For bilerp,
this means |
| 27 // to expand the bilerp filter around the point and sample using that filter
. |
| 24 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; | 28 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; |
| 29 // Same as pointListFew, but n = 4. |
| 25 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; | 30 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; |
| 31 // A span is a compact form of sample points that are obtained by mapping po
ints from |
| 32 // destination space to source space. This is used for horizontal lines only
, and is mainly |
| 33 // used to take advantage of memory coherence for horizontal spans. |
| 26 virtual void pointSpan(Span span) = 0; | 34 virtual void pointSpan(Span span) = 0; |
| 27 }; | 35 }; |
| 28 | 36 |
| 29 class SkLinearBitmapPipeline::BilerpProcessorInterface | 37 class SkLinearBitmapPipeline::BilerpProcessorInterface |
| 30 : public SkLinearBitmapPipeline::PointProcessorInterface { | 38 : public SkLinearBitmapPipeline::PointProcessorInterface { |
| 31 public: | 39 public: |
| 32 // The x's and y's are setup in the following order: | 40 // The x's and y's are setup in the following order: |
| 33 // +--------+--------+ | 41 // +--------+--------+ |
| 34 // | | | | 42 // | | | |
| 35 // | px00 | px10 | | 43 // | px00 | px10 | |
| 36 // | 0 | 1 | | 44 // | 0 | 1 | |
| 37 // +--------+--------+ | 45 // +--------+--------+ |
| 38 // | | | | 46 // | | | |
| 39 // | px01 | px11 | | 47 // | px01 | px11 | |
| 40 // | 2 | 3 | | 48 // | 2 | 3 | |
| 41 // +--------+--------+ | 49 // +--------+--------+ |
| 42 // These pixels coordinates are arranged in the following order in xs and ys
: | 50 // These pixels coordinates are arranged in the following order in xs and ys
: |
| 43 // px00 px10 px01 px11 | 51 // px00 px10 px01 px11 |
| 44 virtual void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) = 0; | 52 virtual void VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) = 0; |
| 45 virtual void bilerpSpan(BilerpSpan span) = 0; | 53 |
| 54 // A span represents sample points that have been mapped from destination sp
ace to source |
| 55 // space. Each sample point is then expanded to the four bilerp points by ad
d +/- 0.5. The |
| 56 // resulting Y values my be off the tile. When y +/- 0.5 are more than 1 apa
rt because of |
| 57 // tiling, the second Y is used to denote the retiled Y value. |
| 58 virtual void bilerpSpan(Span span, SkScalar y) = 0; |
| 46 }; | 59 }; |
| 47 | 60 |
| 48 class SkLinearBitmapPipeline::PixelPlacerInterface { | 61 class SkLinearBitmapPipeline::PixelPlacerInterface { |
| 49 public: | 62 public: |
| 50 virtual ~PixelPlacerInterface() { } | 63 virtual ~PixelPlacerInterface() { } |
| 51 virtual void setDestination(SkPM4f* dst) = 0; | 64 virtual void setDestination(SkPM4f* dst) = 0; |
| 52 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; | 65 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; |
| 53 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0
; | 66 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0
; |
| 54 }; | 67 }; |
| 55 | 68 |
| 56 namespace { | 69 namespace { |
| 70 |
| 71 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 72 // Matrix Stage |
| 57 // PointProcessor uses a strategy to help complete the work of the different sta
ges. The strategy | 73 // PointProcessor uses a strategy to help complete the work of the different sta
ges. The strategy |
| 58 // must implement the following methods: | 74 // must implement the following methods: |
| 59 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. | 75 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. |
| 60 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixel
s | 76 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixel
s |
| 61 // to work over. | 77 // to work over. |
| 62 // span - encapsulation of span. | 78 // span - encapsulation of span. |
| 63 // next - a pointer to the next stage. | 79 // next - a pointer to the next stage. |
| 64 // maybeProcessSpan - returns false if it can not process the span and needs t
o fallback to | 80 // maybeProcessSpan - returns false if it can not process the span and needs t
o fallback to |
| 65 // point lists for processing. | 81 // point lists for processing. |
| 66 template<typename Strategy, typename Next> | 82 template<typename Strategy, typename Next> |
| 67 class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterf
ace { | 83 class MatrixStage final : public SkLinearBitmapPipeline::PointProcessorInterface
{ |
| 68 public: | 84 public: |
| 69 template <typename... Args> | 85 template <typename... Args> |
| 70 PointProcessor(Next* next, Args&&... args) | 86 MatrixStage(Next* next, Args&&... args) |
| 71 : fNext{next} | 87 : fNext{next} |
| 72 , fStrategy{std::forward<Args>(args)...}{ } | 88 , fStrategy{std::forward<Args>(args)...}{ } |
| 73 | 89 |
| 74 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { | 90 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
| 75 fStrategy.processPoints(&xs, &ys); | 91 fStrategy.processPoints(&xs, &ys); |
| 76 fNext->pointListFew(n, xs, ys); | 92 fNext->pointListFew(n, xs, ys); |
| 77 } | 93 } |
| 78 | 94 |
| 79 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { | 95 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
| 80 fStrategy.processPoints(&xs, &ys); | 96 fStrategy.processPoints(&xs, &ys); |
| 81 fNext->pointList4(xs, ys); | 97 fNext->pointList4(xs, ys); |
| 82 } | 98 } |
| 83 | 99 |
| 84 // The span you pass must not be empty. | 100 // The span you pass must not be empty. |
| 85 void pointSpan(Span span) override { | 101 void pointSpan(Span span) override { |
| 86 SkASSERT(!span.isEmpty()); | 102 SkASSERT(!span.isEmpty()); |
| 87 if (!fStrategy.maybeProcessSpan(span, fNext)) { | 103 if (!fStrategy.maybeProcessSpan(span, fNext)) { |
| 88 span_fallback(span, this); | 104 span_fallback(span, this); |
| 89 } | 105 } |
| 90 } | 106 } |
| 91 | 107 |
| 92 private: | 108 private: |
| 93 Next* const fNext; | 109 Next* const fNext; |
| 94 Strategy fStrategy; | 110 Strategy fStrategy; |
| 95 }; | 111 }; |
| 96 | 112 |
| 97 // See PointProcessor for responsibilities of Strategy. | |
| 98 template<typename Strategy, typename Next> | |
| 99 class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInte
rface { | |
| 100 public: | |
| 101 template <typename... Args> | |
| 102 BilerpProcessor(Next* next, Args&&... args) | |
| 103 : fNext{next} | |
| 104 , fStrategy{std::forward<Args>(args)...}{ } | |
| 105 | |
| 106 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { | |
| 107 fStrategy.processPoints(&xs, &ys); | |
| 108 fNext->pointListFew(n, xs, ys); | |
| 109 } | |
| 110 | |
| 111 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { | |
| 112 fStrategy.processPoints(&xs, &ys); | |
| 113 fNext->pointList4(xs, ys); | |
| 114 } | |
| 115 | |
| 116 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { | |
| 117 fStrategy.processPoints(&xs, &ys); | |
| 118 fNext->bilerpList(xs, ys); | |
| 119 } | |
| 120 | |
| 121 void pointSpan(Span span) override { | |
| 122 SkASSERT(!span.isEmpty()); | |
| 123 if (!fStrategy.maybeProcessSpan(span, fNext)) { | |
| 124 span_fallback(span, this); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 void bilerpSpan(BilerpSpan bSpan) override { | |
| 129 SkASSERT(!bSpan.isEmpty()); | |
| 130 if (!fStrategy.maybeProcessBilerpSpan(bSpan, fNext)) { | |
| 131 bilerp_span_fallback(bSpan, this); | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 private: | |
| 136 Next* const fNext; | |
| 137 Strategy fStrategy; | |
| 138 }; | |
| 139 | |
| 140 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | |
| 141 // Matrix Stage | |
| 142 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 113 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
| 143 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; | 114 using TranslateMatrix = MatrixStage<TranslateMatrixStrategy, Next>; |
| 144 | 115 |
| 145 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 116 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
| 146 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; | 117 using ScaleMatrix = MatrixStage<ScaleMatrixStrategy, Next>; |
| 147 | 118 |
| 148 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 119 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
| 149 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; | 120 using AffineMatrix = MatrixStage<AffineMatrixStrategy, Next>; |
| 121 |
| 122 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
| 123 using PerspectiveMatrix = MatrixStage<PerspectiveMatrixStrategy, Next>; |
| 124 |
| 150 | 125 |
| 151 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( | 126 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( |
| 152 SkLinearBitmapPipeline::PointProcessorInterface* next, | 127 SkLinearBitmapPipeline::PointProcessorInterface* next, |
| 153 const SkMatrix& inverse, | 128 const SkMatrix& inverse, |
| 154 SkLinearBitmapPipeline::MatrixStage* matrixProc) { | 129 SkLinearBitmapPipeline::MatrixStage* matrixProc) { |
| 155 if (inverse.hasPerspective()) { | 130 if (inverse.hasPerspective()) { |
| 156 SkFAIL("Not implemented."); | 131 matrixProc->Initialize<PerspectiveMatrix<>>( |
| 132 next, |
| 133 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, |
| 134 SkVector{inverse.getScaleX(), inverse.getScaleY()}, |
| 135 SkVector{inverse.getSkewX(), inverse.getSkewY()}, |
| 136 SkVector{inverse.getPerspX(), inverse.getPerspY()}, |
| 137 inverse.get(SkMatrix::kMPersp2)); |
| 157 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { | 138 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { |
| 158 matrixProc->Initialize<AffineMatrix<>>( | 139 matrixProc->Initialize<AffineMatrix<>>( |
| 159 next, | 140 next, |
| 160 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, | 141 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, |
| 161 SkVector{inverse.getScaleX(), inverse.getScaleY()}, | 142 SkVector{inverse.getScaleX(), inverse.getScaleY()}, |
| 162 SkVector{inverse.getSkewX(), inverse.getSkewY()}); | 143 SkVector{inverse.getSkewX(), inverse.getSkewY()}); |
| 163 } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) { | 144 } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) { |
| 164 matrixProc->Initialize<ScaleMatrix<>>( | 145 matrixProc->Initialize<ScaleMatrix<>>( |
| 165 next, | 146 next, |
| 166 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, | 147 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, |
| 167 SkVector{inverse.getScaleX(), inverse.getScaleY()}); | 148 SkVector{inverse.getScaleX(), inverse.getScaleY()}); |
| 168 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0
f) { | 149 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0
f) { |
| 169 matrixProc->Initialize<TranslateMatrix<>>( | 150 matrixProc->Initialize<TranslateMatrix<>>( |
| 170 next, | 151 next, |
| 171 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); | 152 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); |
| 172 } else { | 153 } else { |
| 173 return next; | 154 return next; |
| 174 } | 155 } |
| 175 return matrixProc->get(); | 156 return matrixProc->get(); |
| 176 } | 157 } |
| 177 | 158 |
| 178 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 159 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 179 // Bilerp Expansion Stage | 160 // Tile Stage |
| 180 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 161 |
| 181 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac
e { | 162 template<typename XStrategy, typename YStrategy, typename Next> |
| 163 class NearestTileStage final : public SkLinearBitmapPipeline::PointProcessorInte
rface { |
| 182 public: | 164 public: |
| 183 ExpandBilerp(Next* next) : fNext{next} { } | 165 template <typename... Args> |
| 166 NearestTileStage(Next* next, SkISize dimensions) |
| 167 : fNext{next} |
| 168 , fXStrategy{dimensions.width()} |
| 169 , fYStrategy{dimensions.height()}{ } |
| 184 | 170 |
| 185 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { | 171 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
| 186 SkASSERT(0 < n && n < 4); | 172 fXStrategy.tileXPoints(&xs); |
| 187 // px00 px10 px01 px11 | 173 fYStrategy.tileYPoints(&ys); |
| 188 const Sk4s kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, | 174 fNext->pointListFew(n, xs, ys); |
| 189 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; | 175 } |
| 190 if (n >= 1) fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYO
ffsets); | 176 |
| 191 if (n >= 2) fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYO
ffsets); | 177 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
| 192 if (n >= 3) fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYO
ffsets); | 178 fXStrategy.tileXPoints(&xs); |
| 193 } | 179 fYStrategy.tileYPoints(&ys); |
| 194 | 180 fNext->pointList4(xs, ys); |
| 195 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 181 } |
| 196 // px00 px10 px01 px11 | 182 |
| 197 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, | 183 // The span you pass must not be empty. |
| 198 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; | |
| 199 fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYOffsets); | |
| 200 fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYOffsets); | |
| 201 fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYOffsets); | |
| 202 fNext->bilerpList(Sk4s{xs[3]} + kXOffsets, Sk4s{ys[3]} + kYOffsets); | |
| 203 } | |
| 204 | |
| 205 void pointSpan(Span span) override { | 184 void pointSpan(Span span) override { |
| 206 SkASSERT(!span.isEmpty()); | 185 SkASSERT(!span.isEmpty()); |
| 207 SkPoint start; SkScalar length; int count; | 186 SkPoint start; SkScalar length; int count; |
| 208 std::tie(start, length, count) = span; | 187 std::tie(start, length, count) = span; |
| 209 // Adjust the span so that it is in the correct phase with the pixel. | 188 SkScalar x = X(start); |
| 210 BilerpSpan bSpan{X(start) - 0.5f, Y(start) - 0.5f, Y(start) + 0.5f, leng
th, count}; | 189 SkScalar y = fYStrategy.tileY(Y(start)); |
| 211 fNext->bilerpSpan(bSpan); | 190 Span yAdjustedSpan{{x, y}, length, count}; |
| 191 if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) { |
| 192 span_fallback(span, this); |
| 193 } |
| 212 } | 194 } |
| 213 | 195 |
| 214 private: | 196 private: |
| 215 Next* const fNext; | 197 Next* const fNext; |
| 216 }; | 198 XStrategy fXStrategy; |
| 217 | 199 YStrategy fYStrategy; |
| 218 static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter( | 200 }; |
| 219 SkLinearBitmapPipeline::BilerpProcessorInterface* next, | 201 |
| 220 SkFilterQuality filterQuailty, | 202 template<typename XStrategy, typename YStrategy, typename Next> |
| 221 SkLinearBitmapPipeline::FilterStage* filterProc) { | 203 class BilerpTileStage final : public SkLinearBitmapPipeline::PointProcessorInter
face { |
| 222 if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) { | |
| 223 return next; | |
| 224 } else { | |
| 225 filterProc->Initialize<ExpandBilerp<>>(next); | |
| 226 return filterProc->get(); | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | |
| 231 // Tile Stage | |
| 232 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | |
| 233 using Clamp = BilerpProcessor<ClampStrategy, Next>; | |
| 234 | |
| 235 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | |
| 236 using Repeat = BilerpProcessor<RepeatStrategy, Next>; | |
| 237 | |
| 238 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( | |
| 239 SkLinearBitmapPipeline::BilerpProcessorInterface* next, | |
| 240 SkSize dimensions, | |
| 241 SkShader::TileMode xMode, | |
| 242 SkShader::TileMode yMode, | |
| 243 SkLinearBitmapPipeline::TileStage* tileProcXOrBoth, | |
| 244 SkLinearBitmapPipeline::TileStage* tileProcY) { | |
| 245 if (xMode == yMode) { | |
| 246 switch (xMode) { | |
| 247 case SkShader::kClamp_TileMode: | |
| 248 tileProcXOrBoth->Initialize<Clamp<>>(next, dimensions); | |
| 249 break; | |
| 250 case SkShader::kRepeat_TileMode: | |
| 251 tileProcXOrBoth->Initialize<Repeat<>>(next, dimensions); | |
| 252 break; | |
| 253 case SkShader::kMirror_TileMode: | |
| 254 SkFAIL("Not implemented."); | |
| 255 break; | |
| 256 } | |
| 257 } else { | |
| 258 switch (yMode) { | |
| 259 case SkShader::kClamp_TileMode: | |
| 260 tileProcY->Initialize<Clamp<>>(next, Y(dimensions)); | |
| 261 break; | |
| 262 case SkShader::kRepeat_TileMode: | |
| 263 tileProcY->Initialize<Repeat<>>(next, Y(dimensions)); | |
| 264 break; | |
| 265 case SkShader::kMirror_TileMode: | |
| 266 SkFAIL("Not implemented."); | |
| 267 break; | |
| 268 } | |
| 269 switch (xMode) { | |
| 270 case SkShader::kClamp_TileMode: | |
| 271 tileProcXOrBoth->Initialize<Clamp<>>(tileProcY->get(), X(dimensi
ons)); | |
| 272 break; | |
| 273 case SkShader::kRepeat_TileMode: | |
| 274 tileProcXOrBoth->Initialize<Repeat<>>(tileProcY->get(), X(dimens
ions)); | |
| 275 break; | |
| 276 case SkShader::kMirror_TileMode: | |
| 277 SkFAIL("Not implemented."); | |
| 278 break; | |
| 279 } | |
| 280 } | |
| 281 return tileProcXOrBoth->get(); | |
| 282 } | |
| 283 | |
| 284 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | |
| 285 // Source Sampling Stage | |
| 286 class sRGBFast { | |
| 287 public: | |
| 288 static Sk4s VECTORCALL sRGBToLinear(Sk4s pixel) { | |
| 289 Sk4s l = pixel * pixel; | |
| 290 return Sk4s{l[0], l[1], l[2], pixel[3]}; | |
| 291 } | |
| 292 }; | |
| 293 | |
| 294 enum class ColorOrder { | |
| 295 kRGBA = false, | |
| 296 kBGRA = true, | |
| 297 }; | |
| 298 template <SkColorProfileType colorProfile, ColorOrder colorOrder> | |
| 299 class Pixel8888 { | |
| 300 public: | |
| 301 Pixel8888(int width, const uint32_t* src) : fSrc{src}, fWidth{width}{ } | |
| 302 Pixel8888(const SkPixmap& srcPixmap) | |
| 303 : fSrc{srcPixmap.addr32()} | |
| 304 , fWidth{static_cast<int>(srcPixmap.rowBytes() / 4)} { } | |
| 305 | |
| 306 void VECTORCALL getFewPixels(int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1,
Sk4f* px2) { | |
| 307 Sk4i XIs = SkNx_cast<int, SkScalar>(xs); | |
| 308 Sk4i YIs = SkNx_cast<int, SkScalar>(ys); | |
| 309 Sk4i bufferLoc = YIs * fWidth + XIs; | |
| 310 switch (n) { | |
| 311 case 3: | |
| 312 *px2 = this->getPixel(fSrc, bufferLoc[2]); | |
| 313 case 2: | |
| 314 *px1 = this->getPixel(fSrc, bufferLoc[1]); | |
| 315 case 1: | |
| 316 *px0 = this->getPixel(fSrc, bufferLoc[0]); | |
| 317 default: | |
| 318 break; | |
| 319 } | |
| 320 } | |
| 321 | |
| 322 void VECTORCALL get4Pixels(Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2
, Sk4f* px3) { | |
| 323 Sk4i XIs = SkNx_cast<int, SkScalar>(xs); | |
| 324 Sk4i YIs = SkNx_cast<int, SkScalar>(ys); | |
| 325 Sk4i bufferLoc = YIs * fWidth + XIs; | |
| 326 *px0 = this->getPixel(fSrc, bufferLoc[0]); | |
| 327 *px1 = this->getPixel(fSrc, bufferLoc[1]); | |
| 328 *px2 = this->getPixel(fSrc, bufferLoc[2]); | |
| 329 *px3 = this->getPixel(fSrc, bufferLoc[3]); | |
| 330 } | |
| 331 | |
| 332 void get4Pixels(const void* vsrc, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2
, Sk4f* px3) { | |
| 333 const uint32_t* src = static_cast<const uint32_t*>(vsrc); | |
| 334 *px0 = this->getPixel(src, index + 0); | |
| 335 *px1 = this->getPixel(src, index + 1); | |
| 336 *px2 = this->getPixel(src, index + 2); | |
| 337 *px3 = this->getPixel(src, index + 3); | |
| 338 } | |
| 339 | |
| 340 Sk4f getPixel(const void* vsrc, int index) { | |
| 341 const uint32_t* src = static_cast<const uint32_t*>(vsrc); | |
| 342 Sk4b bytePixel = Sk4b::Load((uint8_t *)(&src[index])); | |
| 343 Sk4f pixel = SkNx_cast<float, uint8_t>(bytePixel); | |
| 344 if (colorOrder == ColorOrder::kBGRA) { | |
| 345 pixel = SkNx_shuffle<2, 1, 0, 3>(pixel); | |
| 346 } | |
| 347 pixel = pixel * Sk4f{1.0f/255.0f}; | |
| 348 if (colorProfile == kSRGB_SkColorProfileType) { | |
| 349 pixel = sRGBFast::sRGBToLinear(pixel); | |
| 350 } | |
| 351 return pixel; | |
| 352 } | |
| 353 | |
| 354 const uint32_t* row(int y) { return fSrc + y * fWidth[0]; } | |
| 355 | |
| 356 private: | |
| 357 const uint32_t* const fSrc; | |
| 358 const Sk4i fWidth; | |
| 359 }; | |
| 360 | |
| 361 // Explaination of the math: | |
| 362 // 1 - x x | |
| 363 // +--------+--------+ | |
| 364 // | | | | |
| 365 // 1 - y | px00 | px10 | | |
| 366 // | | | | |
| 367 // +--------+--------+ | |
| 368 // | | | | |
| 369 // y | px01 | px11 | | |
| 370 // | | | | |
| 371 // +--------+--------+ | |
| 372 // | |
| 373 // | |
| 374 // Given a pixelxy each is multiplied by a different factor derived from the fra
ctional part of x | |
| 375 // and y: | |
| 376 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy | |
| 377 // * px10 -> x(1 - y) = x - xy | |
| 378 // * px01 -> (1 - x)y = y - xy | |
| 379 // * px11 -> xy | |
| 380 // So x * y is calculated first and then used to calculate all the other factors
. | |
| 381 static Sk4s VECTORCALL bilerp4(Sk4s xs, Sk4s ys, Sk4f px00, Sk4f px10, | |
| 382 Sk4f px01, Sk4f px11) { | |
| 383 // Calculate fractional xs and ys. | |
| 384 Sk4s fxs = xs - xs.floor(); | |
| 385 Sk4s fys = ys - ys.floor(); | |
| 386 Sk4s fxys{fxs * fys}; | |
| 387 Sk4f sum = px11 * fxys; | |
| 388 sum = sum + px01 * (fys - fxys); | |
| 389 sum = sum + px10 * (fxs - fxys); | |
| 390 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys); | |
| 391 return sum; | |
| 392 } | |
| 393 | |
| 394 template <typename SourceStrategy> | |
| 395 class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface { | |
| 396 public: | 204 public: |
| 397 template <typename... Args> | 205 template <typename... Args> |
| 398 Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args) | 206 BilerpTileStage(Next* next, SkISize dimensions) |
| 399 : fNext{next} | 207 : fXMax(dimensions.width()) |
| 400 , fStrategy{std::forward<Args>(args)...} { } | 208 , fYMax(dimensions.height()) |
| 209 , fNext{next} |
| 210 , fXStrategy{dimensions.width()} |
| 211 , fYStrategy{dimensions.height()}{ } |
| 401 | 212 |
| 402 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { | 213 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
| 403 SkASSERT(0 < n && n < 4); | 214 fXStrategy.tileXPoints(&xs); |
| 404 Sk4f px0, px1, px2; | 215 fYStrategy.tileYPoints(&ys); |
| 405 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); | 216 // TODO: check to see if xs and ys are in range then just call pointList
Few on next. |
| 406 if (n >= 1) fNext->placePixel(px0); | 217 if (n >= 1) this->bilerpPoint(xs[0], ys[0]); |
| 407 if (n >= 2) fNext->placePixel(px1); | 218 if (n >= 2) this->bilerpPoint(xs[1], ys[1]); |
| 408 if (n >= 3) fNext->placePixel(px2); | 219 if (n >= 3) this->bilerpPoint(xs[2], ys[2]); |
| 409 } | 220 } |
| 410 | 221 |
| 411 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { | 222 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
| 412 Sk4f px0, px1, px2, px3; | 223 fXStrategy.tileXPoints(&xs); |
| 413 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); | 224 fYStrategy.tileYPoints(&ys); |
| 414 fNext->place4Pixels(px0, px1, px2, px3); | 225 // TODO: check to see if xs and ys are in range then just call pointList
4 on next. |
| 415 } | 226 this->bilerpPoint(xs[0], ys[0]); |
| 416 | 227 this->bilerpPoint(xs[1], ys[1]); |
| 417 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { | 228 this->bilerpPoint(xs[2], ys[2]); |
| 418 Sk4f px00, px10, px01, px11; | 229 this->bilerpPoint(xs[3], ys[3]); |
| 419 fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11); | 230 } |
| 420 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11); | 231 |
| 421 fNext->placePixel(pixel); | 232 struct Wrapper { |
| 422 } | 233 void pointSpan(Span span) { |
| 423 | 234 processor->breakIntoEdges(span); |
| 235 } |
| 236 |
| 237 BilerpTileStage* processor; |
| 238 }; |
| 239 |
| 240 // The span you pass must not be empty. |
| 424 void pointSpan(Span span) override { | 241 void pointSpan(Span span) override { |
| 425 SkASSERT(!span.isEmpty()); | 242 SkASSERT(!span.isEmpty()); |
| 426 SkPoint start; SkScalar length; int count; | 243 |
| 427 std::tie(start, length, count) = span; | 244 Wrapper wrapper = {this}; |
| 428 if (length < (count - 1)) { | 245 if (!fXStrategy.maybeProcessSpan(span, &wrapper)) { |
| 429 this->pointSpanSlowRate(span); | 246 span_fallback(span, this); |
| 430 } else if (length == (count - 1)) { | |
| 431 this->pointSpanUnitRate(span); | |
| 432 } else { | |
| 433 this->pointSpanFastRate(span); | |
| 434 } | 247 } |
| 435 } | 248 } |
| 436 | 249 |
| 437 private: | 250 private: |
| 438 // When moving through source space more slowly than dst space (zoomed in), | 251 void bilerpPoint(SkScalar x, SkScalar y) { |
| 439 // we'll be sampling from the same source pixel more than once. | 252 Sk4f txs = Sk4f{x} + Sk4f{-0.5f, 0.5f, -0.5f, 0.5f}; |
| 440 void pointSpanSlowRate(Span span) { | 253 Sk4f tys = Sk4f{y} + Sk4f{-0.5f, -0.5f, 0.5f, 0.5f}; |
| 254 fXStrategy.tileXPoints(&txs); |
| 255 fYStrategy.tileYPoints(&tys); |
| 256 fNext->bilerpEdge(txs, tys); |
| 257 } |
| 258 |
| 259 void handleEdges(Span span, SkScalar dx) { |
| 441 SkPoint start; SkScalar length; int count; | 260 SkPoint start; SkScalar length; int count; |
| 442 std::tie(start, length, count) = span; | 261 std::tie(start, length, count) = span; |
| 443 SkScalar x = X(start); | 262 SkScalar x = X(start); |
| 444 SkFixed fx = SkScalarToFixed(x); | 263 SkScalar y = Y(start); |
| 445 SkScalar dx = length / (count - 1); | 264 SkScalar tiledY = fYStrategy.tileY(y); |
| 446 SkFixed fdx = SkScalarToFixed(dx); | 265 while (count > 0) { |
| 447 | 266 this->bilerpPoint(x, tiledY); |
| 448 const void* row = fStrategy.row((int)std::floor(Y(start))); | 267 x += dx; |
| 449 SkLinearBitmapPipeline::PixelPlacerInterface* next = fNext; | 268 count -= 1; |
| 450 | 269 } |
| 451 int ix = SkFixedFloorToInt(fx); | 270 } |
| 452 int prevIX = ix; | 271 |
| 453 Sk4f fpixel = fStrategy.getPixel(row, ix); | 272 void yProcessSpan(Span span) { |
| 454 | 273 SkScalar tiledY = fYStrategy.tileY(span.startY()); |
| 455 // When dx is less than one, each pixel is used more than once. Using th
e fixed point fx | 274 if (0.5f <= tiledY && tiledY < fYMax - 0.5f ) { |
| 456 // allows the code to quickly check that the same pixel is being used. T
he code uses this | 275 Span tiledSpan{{span.startX(), tiledY}, span.length(), span.count()}
; |
| 457 // same pixel check to do the sRGB and normalization only once. | 276 fNext->pointSpan(tiledSpan); |
| 458 auto getNextPixel = [&]() { | 277 } else { |
| 459 if (ix != prevIX) { | 278 // Convert to the Y0 bilerp sample set by shifting by -0.5f. Then ti
le that new y |
| 460 fpixel = fStrategy.getPixel(row, ix); | 279 // value and shift it back resulting in the working Y0. Do the same
thing with Y1 but |
| 461 prevIX = ix; | 280 // in the opposite direction. |
| 281 SkScalar y0 = fYStrategy.tileY(span.startY() - 0.5f) + 0.5f; |
| 282 SkScalar y1 = fYStrategy.tileY(span.startY() + 0.5f) - 0.5f; |
| 283 Span newSpan{{span.startX(), y0}, span.length(), span.count()}; |
| 284 fNext->bilerpSpan(newSpan, y1); |
| 285 } |
| 286 } |
| 287 void breakIntoEdges(Span span) { |
| 288 if (span.length() == 0) { |
| 289 yProcessSpan(span); |
| 290 } else { |
| 291 SkScalar dx = span.length() / (span.count() - 1); |
| 292 if (span.length() > 0) { |
| 293 Span leftBorder = span.breakAt(0.5f, dx); |
| 294 if (!leftBorder.isEmpty()) { |
| 295 this->handleEdges(leftBorder, dx); |
| 296 } |
| 297 Span center = span.breakAt(fXMax - 0.5f, dx); |
| 298 if (!center.isEmpty()) { |
| 299 this->yProcessSpan(center); |
| 300 } |
| 301 |
| 302 if (!span.isEmpty()) { |
| 303 this->handleEdges(span, dx); |
| 304 } |
| 305 } else { |
| 306 Span center = span.breakAt(fXMax + 0.5f, dx); |
| 307 if (!span.isEmpty()) { |
| 308 this->handleEdges(span, dx); |
| 309 } |
| 310 Span leftEdge = center.breakAt(0.5f, dx); |
| 311 if (!center.isEmpty()) { |
| 312 this->yProcessSpan(center); |
| 313 } |
| 314 if (!leftEdge.isEmpty()) { |
| 315 this->handleEdges(leftEdge, dx); |
| 316 } |
| 317 |
| 462 } | 318 } |
| 463 fx += fdx; | 319 } |
| 464 ix = SkFixedFloorToInt(fx); | 320 } |
| 465 return fpixel; | 321 |
| 466 }; | 322 SkScalar fXMax; |
| 467 | 323 SkScalar fYMax; |
| 468 while (count >= 4) { | 324 Next* const fNext; |
| 469 Sk4f px0 = getNextPixel(); | 325 XStrategy fXStrategy; |
| 470 Sk4f px1 = getNextPixel(); | 326 YStrategy fYStrategy; |
| 471 Sk4f px2 = getNextPixel(); | 327 }; |
| 472 Sk4f px3 = getNextPixel(); | 328 |
| 473 next->place4Pixels(px0, px1, px2, px3); | 329 template <typename XStrategy, typename YStrategy, typename Next> |
| 474 count -= 4; | 330 void make_tile_stage( |
| 475 } | 331 SkFilterQuality filterQuality, SkISize dimensions, |
| 476 while (count > 0) { | 332 Next* next, SkLinearBitmapPipeline::TileStage* tileStage) { |
| 477 next->placePixel(getNextPixel()); | 333 if (filterQuality == kNone_SkFilterQuality) { |
| 478 count -= 1; | 334 tileStage->Initialize<NearestTileStage<XStrategy, YStrategy, Next>>(next
, dimensions); |
| 479 } | 335 } else { |
| 480 } | 336 tileStage->Initialize<BilerpTileStage<XStrategy, YStrategy, Next>>(next,
dimensions); |
| 481 | 337 } |
| 482 // We're moving through source space at a rate of 1 source pixel per 1 dst p
ixel. | 338 } |
| 483 // We'll never re-use pixels, but we can at least load contiguous pixels. | 339 template <typename XStrategy> |
| 484 void pointSpanUnitRate(Span span) { | 340 void choose_tiler_ymode( |
| 485 SkPoint start; SkScalar length; int count; | 341 SkShader::TileMode yMode, SkFilterQuality filterQuality, SkISize dimensions, |
| 486 std::tie(start, length, count) = span; | 342 SkLinearBitmapPipeline::BilerpProcessorInterface* next, |
| 487 int ix = SkScalarFloorToInt(X(start)); | 343 SkLinearBitmapPipeline::TileStage* tileStage) { |
| 488 const void* row = fStrategy.row((int)std::floor(Y(start))); | 344 switch (yMode) { |
| 489 SkLinearBitmapPipeline::PixelPlacerInterface* next = fNext; | 345 case SkShader::kClamp_TileMode: |
| 490 while (count >= 4) { | 346 make_tile_stage<XStrategy, YClampStrategy>(filterQuality, dimensions
, next, tileStage); |
| 491 Sk4f px0, px1, px2, px3; | 347 break; |
| 492 fStrategy.get4Pixels(row, ix, &px0, &px1, &px2, &px3); | 348 case SkShader::kRepeat_TileMode: |
| 493 next->place4Pixels(px0, px1, px2, px3); | 349 make_tile_stage<XStrategy, YRepeatStrategy>(filterQuality, dimension
s, next, tileStage); |
| 494 ix += 4; | 350 break; |
| 495 count -= 4; | 351 case SkShader::kMirror_TileMode: |
| 496 } | 352 make_tile_stage<XStrategy, YMirrorStrategy>(filterQuality, dimension
s, next, tileStage); |
| 497 | 353 break; |
| 498 while (count > 0) { | 354 } |
| 499 next->placePixel(fStrategy.getPixel(row, ix)); | 355 }; |
| 500 ix += 1; | 356 |
| 501 count -= 1; | 357 static SkLinearBitmapPipeline::PointProcessorInterface* choose_tiler( |
| 502 } | 358 SkLinearBitmapPipeline::BilerpProcessorInterface* next, |
| 503 } | 359 SkISize dimensions, |
| 504 | 360 SkShader::TileMode xMode, |
| 505 // We're moving through source space faster than dst (zoomed out), | 361 SkShader::TileMode yMode, |
| 506 // so we'll never reuse a source pixel or be able to do contiguous loads. | 362 SkFilterQuality filterQuality, |
| 507 void pointSpanFastRate(Span span) { | 363 SkLinearBitmapPipeline::TileStage* tileStage) { |
| 508 span_fallback(span, this); | 364 switch (xMode) { |
| 509 } | 365 case SkShader::kClamp_TileMode: |
| 510 | 366 choose_tiler_ymode<XClampStrategy>(yMode, filterQuality, dimensions,
next, tileStage); |
| 511 void bilerpSpan(BilerpSpan span) override { | 367 break; |
| 512 bilerp_span_fallback(span, this); | 368 case SkShader::kRepeat_TileMode: |
| 369 choose_tiler_ymode<XRepeatStrategy>(yMode, filterQuality, dimensions
, next, tileStage); |
| 370 break; |
| 371 case SkShader::kMirror_TileMode: |
| 372 choose_tiler_ymode<XMirrorStrategy>(yMode, filterQuality, dimensions
, next, tileStage); |
| 373 break; |
| 374 } |
| 375 |
| 376 return tileStage->get(); |
| 377 } |
| 378 |
| 379 |
| 380 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 381 // Source Sampling Stage |
| 382 template <typename SourceStrategy, typename Next> |
| 383 class NearestNeighborSampler final : public SkLinearBitmapPipeline::BilerpProces
sorInterface { |
| 384 public: |
| 385 template <typename... Args> |
| 386 NearestNeighborSampler(Next* next, Args&&... args) |
| 387 : fSampler{next, std::forward<Args>(args)...} { } |
| 388 |
| 389 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
| 390 fSampler.nearestListFew(n, xs, ys); |
| 391 } |
| 392 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
| 393 fSampler.nearestList4(xs, ys); |
| 394 } |
| 395 void pointSpan(Span span) override { |
| 396 fSampler.nearestSpan(span); |
| 397 } |
| 398 void VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override { |
| 399 SkFAIL("Using nearest neighbor sampler, but calling a bilerpEdge."); |
| 400 } |
| 401 |
| 402 virtual void bilerpSpan(Span span, SkScalar y) override { |
| 403 SkFAIL("Using nearest neighbor sampler, but calling a bilerpSpan."); |
| 513 } | 404 } |
| 514 | 405 |
| 515 private: | 406 private: |
| 516 SkLinearBitmapPipeline::PixelPlacerInterface* const fNext; | 407 GeneralSampler<SourceStrategy, Next> fSampler; |
| 517 SourceStrategy fStrategy; | 408 }; |
| 518 }; | 409 |
| 519 | 410 template <typename SourceStrategy, typename Next> |
| 520 using Pixel8888SRGB = Pixel8888<kSRGB_SkColorProfileType, ColorOrder::kRGBA>; | 411 class BilerpSampler final : public SkLinearBitmapPipeline::BilerpProcessorInterf
ace { |
| 521 using Pixel8888LRGB = Pixel8888<kLinear_SkColorProfileType, ColorOrder::kRGBA>; | 412 public: |
| 522 using Pixel8888SBGR = Pixel8888<kSRGB_SkColorProfileType, ColorOrder::kBGRA>; | 413 template <typename... Args> |
| 523 using Pixel8888LBGR = Pixel8888<kLinear_SkColorProfileType, ColorOrder::kBGRA>; | 414 BilerpSampler(Next* next, Args&&... args) |
| 524 | 415 : fSampler{next, std::forward<Args>(args)...} { } |
| 525 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler( | 416 |
| 526 SkLinearBitmapPipeline::PixelPlacerInterface* next, | 417 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
| 418 fSampler.bilerpListFew(n, xs, ys); |
| 419 } |
| 420 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
| 421 fSampler.bilerpList4(xs, ys); |
| 422 } |
| 423 void pointSpan(Span span) override { |
| 424 fSampler.bilerpSpan(span); |
| 425 } |
| 426 void VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override { |
| 427 fSampler.bilerpEdge(xs, ys); |
| 428 } |
| 429 |
| 430 virtual void bilerpSpan(Span span, SkScalar y) override { |
| 431 fSampler.bilerpSpanWithY(span, y); |
| 432 } |
| 433 |
| 434 private: |
| 435 GeneralSampler<SourceStrategy, Next> fSampler; |
| 436 }; |
| 437 |
| 438 using Placer = SkLinearBitmapPipeline::PixelPlacerInterface; |
| 439 |
| 440 template<template <typename, typename> class Sampler> |
| 441 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler_ba
se( |
| 442 Placer* next, |
| 527 const SkPixmap& srcPixmap, | 443 const SkPixmap& srcPixmap, |
| 528 SkLinearBitmapPipeline::SampleStage* sampleStage) { | 444 SkLinearBitmapPipeline::SampleStage* sampleStage) { |
| 529 const SkImageInfo& imageInfo = srcPixmap.info(); | 445 const SkImageInfo& imageInfo = srcPixmap.info(); |
| 530 switch (imageInfo.colorType()) { | 446 switch (imageInfo.colorType()) { |
| 531 case kRGBA_8888_SkColorType: | 447 case kRGBA_8888_SkColorType: |
| 532 if (imageInfo.profileType() == kSRGB_SkColorProfileType) { | 448 if (imageInfo.profileType() == kSRGB_SkColorProfileType) { |
| 533 sampleStage->Initialize<Sampler<Pixel8888SRGB>>(next, srcPixmap)
; | 449 sampleStage->Initialize<Sampler<Pixel8888SRGB, Placer>>(next, sr
cPixmap); |
| 534 } else { | 450 } else { |
| 535 sampleStage->Initialize<Sampler<Pixel8888LRGB>>(next, srcPixmap)
; | 451 sampleStage->Initialize<Sampler<Pixel8888LRGB, Placer>>(next, sr
cPixmap); |
| 536 } | 452 } |
| 537 break; | 453 break; |
| 538 case kBGRA_8888_SkColorType: | 454 case kBGRA_8888_SkColorType: |
| 539 if (imageInfo.profileType() == kSRGB_SkColorProfileType) { | 455 if (imageInfo.profileType() == kSRGB_SkColorProfileType) { |
| 540 sampleStage->Initialize<Sampler<Pixel8888SBGR>>(next, srcPixmap)
; | 456 sampleStage->Initialize<Sampler<Pixel8888SBGR, Placer>>(next, sr
cPixmap); |
| 541 } else { | 457 } else { |
| 542 sampleStage->Initialize<Sampler<Pixel8888LBGR>>(next, srcPixmap)
; | 458 sampleStage->Initialize<Sampler<Pixel8888LBGR, Placer>>(next, sr
cPixmap); |
| 543 } | 459 } |
| 544 break; | 460 break; |
| 545 default: | 461 default: |
| 546 SkFAIL("Not implemented. Unsupported src"); | 462 SkFAIL("Not implemented. Unsupported src"); |
| 547 break; | 463 break; |
| 548 } | 464 } |
| 549 return sampleStage->get(); | 465 return sampleStage->get(); |
| 550 } | 466 } |
| 551 | 467 |
| 468 SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler( |
| 469 Placer* next, |
| 470 SkFilterQuality filterQuality, |
| 471 const SkPixmap& srcPixmap, |
| 472 SkLinearBitmapPipeline::SampleStage* sampleStage) { |
| 473 if (filterQuality == kNone_SkFilterQuality) { |
| 474 return choose_pixel_sampler_base<NearestNeighborSampler>(next, srcPixmap
, sampleStage); |
| 475 } else { |
| 476 return choose_pixel_sampler_base<BilerpSampler>(next, srcPixmap, sampleS
tage); |
| 477 } |
| 478 } |
| 479 |
| 552 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 480 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 553 // Pixel Placement Stage | 481 // Pixel Placement Stage |
| 554 template <SkAlphaType alphaType> | 482 template <SkAlphaType alphaType> |
| 555 class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface { | 483 class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface { |
| 556 public: | 484 public: |
| 485 PlaceFPPixel(float postAlpha) : fPostAlpha{postAlpha} { } |
| 557 void VECTORCALL placePixel(Sk4f pixel) override { | 486 void VECTORCALL placePixel(Sk4f pixel) override { |
| 558 PlacePixel(fDst, pixel, 0); | 487 PlacePixel(fDst, pixel, 0); |
| 559 fDst += 1; | 488 fDst += 1; |
| 560 } | 489 } |
| 561 | 490 |
| 562 void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override { | 491 void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override { |
| 563 SkPM4f* dst = fDst; | 492 SkPM4f* dst = fDst; |
| 564 PlacePixel(dst, p0, 0); | 493 PlacePixel(dst, p0, 0); |
| 565 PlacePixel(dst, p1, 1); | 494 PlacePixel(dst, p1, 1); |
| 566 PlacePixel(dst, p2, 2); | 495 PlacePixel(dst, p2, 2); |
| 567 PlacePixel(dst, p3, 3); | 496 PlacePixel(dst, p3, 3); |
| 568 fDst += 4; | 497 fDst += 4; |
| 569 } | 498 } |
| 570 | 499 |
| 571 void setDestination(SkPM4f* dst) override { | 500 void setDestination(SkPM4f* dst) override { |
| 572 fDst = dst; | 501 fDst = dst; |
| 573 } | 502 } |
| 574 | 503 |
| 575 private: | 504 private: |
| 576 static void VECTORCALL PlacePixel(SkPM4f* dst, Sk4f pixel, int index) { | 505 void VECTORCALL PlacePixel(SkPM4f* dst, Sk4f pixel, int index) { |
| 577 Sk4f newPixel = pixel; | 506 Sk4f newPixel = pixel; |
| 578 if (alphaType == kUnpremul_SkAlphaType) { | 507 if (alphaType == kUnpremul_SkAlphaType) { |
| 579 newPixel = Premultiply(pixel); | 508 newPixel = Premultiply(pixel); |
| 580 } | 509 } |
| 510 newPixel = newPixel * fPostAlpha; |
| 581 newPixel.store(dst + index); | 511 newPixel.store(dst + index); |
| 582 } | 512 } |
| 583 static Sk4f VECTORCALL Premultiply(Sk4f pixel) { | 513 static Sk4f VECTORCALL Premultiply(Sk4f pixel) { |
| 584 float alpha = pixel[3]; | 514 float alpha = pixel[3]; |
| 585 return pixel * Sk4f{alpha, alpha, alpha, 1.0f}; | 515 return pixel * Sk4f{alpha, alpha, alpha, 1.0f}; |
| 586 } | 516 } |
| 587 | 517 |
| 588 SkPM4f* fDst; | 518 SkPM4f* fDst; |
| 519 Sk4f fPostAlpha; |
| 589 }; | 520 }; |
| 590 | 521 |
| 591 static SkLinearBitmapPipeline::PixelPlacerInterface* choose_pixel_placer( | 522 static SkLinearBitmapPipeline::PixelPlacerInterface* choose_pixel_placer( |
| 592 SkAlphaType alphaType, | 523 SkAlphaType alphaType, |
| 524 float postAlpha, |
| 593 SkLinearBitmapPipeline::PixelStage* placerStage) { | 525 SkLinearBitmapPipeline::PixelStage* placerStage) { |
| 594 if (alphaType == kUnpremul_SkAlphaType) { | 526 if (alphaType == kUnpremul_SkAlphaType) { |
| 595 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>(); | 527 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>(postAlpha); |
| 596 } else { | 528 } else { |
| 597 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType | 529 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType |
| 598 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>(); | 530 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>(postAlpha); |
| 599 } | 531 } |
| 600 return placerStage->get(); | 532 return placerStage->get(); |
| 601 } | 533 } |
| 602 } // namespace | 534 } // namespace |
| 603 | 535 |
| 604 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 536 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 605 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {} | 537 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {} |
| 606 | 538 |
| 607 SkLinearBitmapPipeline::SkLinearBitmapPipeline( | 539 SkLinearBitmapPipeline::SkLinearBitmapPipeline( |
| 608 const SkMatrix& inverse, | 540 const SkMatrix& inverse, |
| 609 SkFilterQuality filterQuality, | 541 SkFilterQuality filterQuality, |
| 610 SkShader::TileMode xTile, SkShader::TileMode yTile, | 542 SkShader::TileMode xTile, SkShader::TileMode yTile, |
| 543 float postAlpha, |
| 611 const SkPixmap& srcPixmap) { | 544 const SkPixmap& srcPixmap) { |
| 612 SkSize size = SkSize::Make(srcPixmap.width(), srcPixmap.height()); | 545 SkISize dimensions = srcPixmap.info().dimensions(); |
| 613 const SkImageInfo& srcImageInfo = srcPixmap.info(); | 546 const SkImageInfo& srcImageInfo = srcPixmap.info(); |
| 614 | 547 |
| 548 SkMatrix adjustedInverse = inverse; |
| 549 if (filterQuality == kNone_SkFilterQuality) { |
| 550 if (inverse.getScaleX() >= 0.0f) { |
| 551 adjustedInverse.setTranslateX( |
| 552 nextafterf(inverse.getTranslateX(), std::floor(inverse.getTransl
ateX()))); |
| 553 } |
| 554 if (inverse.getScaleY() >= 0.0f) { |
| 555 adjustedInverse.setTranslateY( |
| 556 nextafterf(inverse.getTranslateY(), std::floor(inverse.getTransl
ateY()))); |
| 557 } |
| 558 } |
| 559 |
| 615 // As the stages are built, the chooser function may skip a stage. For examp
le, with the | 560 // As the stages are built, the chooser function may skip a stage. For examp
le, with the |
| 616 // identity matrix, the matrix stage is skipped, and the tilerStage is the f
irst stage. | 561 // identity matrix, the matrix stage is skipped, and the tilerStage is the f
irst stage. |
| 617 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelS
tage); | 562 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), postAlph
a, &fPixelStage); |
| 618 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp
leStage); | 563 auto samplerStage = choose_pixel_sampler(placementStage, |
| 619 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX
OrBothStage, | 564 filterQuality, srcPixmap, &fSampl
eStage); |
| 620 &fTileYStage); | 565 auto tilerStage = choose_tiler(samplerStage, |
| 621 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage
); | 566 dimensions, xTile, yTile, filterQuality,
&fTiler); |
| 622 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); | 567 fFirstStage = choose_matrix(tilerStage, adjustedInverse, &fMatrixSta
ge); |
| 623 } | 568 } |
| 624 | 569 |
| 625 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { | 570 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { |
| 626 SkASSERT(count > 0); | 571 SkASSERT(count > 0); |
| 627 fPixelStage->setDestination(dst); | 572 fPixelStage->setDestination(dst); |
| 628 // The count and length arguments start out in a precise relation in order t
o keep the | 573 // The count and length arguments start out in a precise relation in order t
o keep the |
| 629 // math correct through the different stages. Count is the number of pixel t
o produce. | 574 // math correct through the different stages. Count is the number of pixel t
o produce. |
| 630 // Since the code samples at pixel centers, length is the distance from the
center of the | 575 // Since the code samples at pixel centers, length is the distance from the
center of the |
| 631 // first pixel to the center of the last pixel. This implies that length is
count-1. | 576 // first pixel to the center of the last pixel. This implies that length is
count-1. |
| 632 fFirstStage->pointSpan(Span{SkPoint{x + 0.5f, y + 0.5f}, count - 1.0f, count
}); | 577 fFirstStage->pointSpan(Span{{x + 0.5f, y + 0.5f}, count - 1.0f, count}); |
| 633 } | 578 } |
| 579 |
| OLD | NEW |