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 |