Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: src/core/SkLinearBitmapPipeline_tile.h

Issue 1775963002: Bilerp + mirror + perspective (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address comments. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkLinearBitmapPipeline_sample.h ('k') | tests/SkLinearBitmapPipelineTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #ifndef SkLinearBitmapPipeline_tile_DEFINED 8 #ifndef SkLinearBitmapPipeline_tile_DEFINED
9 #define SkLinearBitmapPipeline_tile_DEFINED 9 #define SkLinearBitmapPipeline_tile_DEFINED
10 10
11 #include "SkLinearBitmapPipeline_core.h" 11 #include "SkLinearBitmapPipeline_core.h"
12 #include "SkPM4f.h" 12 #include "SkPM4f.h"
13 #include <algorithm> 13 #include <algorithm>
14 #include <cmath> 14 #include <cmath>
15 #include <limits> 15 #include <limits>
16 16
17 namespace { 17 namespace {
18 class ClampStrategy { 18 class XClampStrategy {
19 public: 19 public:
20 ClampStrategy(X max) 20 XClampStrategy(int32_t max)
21 : fXMin{0.0f}, fXMax{max - 1.0f} { } 21 : fXsMax{SkScalar(max - 0.5f)}
22 , fXMax{SkScalar(max)} { }
22 23
23 ClampStrategy(Y max) 24 void tileXPoints(Sk4s* xs) {
24 : fYMin{0.0f}, fYMax{max - 1.0f} { } 25 *xs = Sk4s::Min(Sk4s::Max(*xs, 0.0f), fXsMax);
25 26 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax);
26 ClampStrategy(SkSize max) 27 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax);
27 : fXMin{0.0f}, fYMin{0.0f}, fXMax{X(max) - 1.0f}, fYMax{Y(max) - 1.0f} { } 28 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax);
28 29 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax);
29 void processPoints(Sk4s* xs, Sk4s* ys) {
30 *xs = Sk4s::Min(Sk4s::Max(*xs, fXMin), fXMax);
31 *ys = Sk4s::Min(Sk4s::Max(*ys, fYMin), fYMax);
32 } 30 }
33 31
34 template<typename Next> 32 template<typename Next>
35 bool maybeProcessSpan(Span originalSpan, Next* next) { 33 bool maybeProcessSpan(Span originalSpan, Next* next) {
36 SkASSERT(!originalSpan.isEmpty()); 34 SkASSERT(!originalSpan.isEmpty());
37 SkPoint start; 35 SkPoint start; SkScalar length; int count;
38 SkScalar length;
39 int count;
40 std::tie(start, length, count) = originalSpan; 36 std::tie(start, length, count) = originalSpan;
41 SkScalar xMin = fXMin[0];
42 SkScalar xMax = fXMax[0] + 1.0f;
43 SkScalar yMin = fYMin[0];
44 SkScalar yMax = fYMax[0];
45 SkScalar x = X(start); 37 SkScalar x = X(start);
46 SkScalar y = std::min(std::max<SkScalar>(yMin, Y(start)), yMax); 38 SkScalar y = Y(start);
47
48 Span span{{x, y}, length, count}; 39 Span span{{x, y}, length, count};
49 40
50 if (span.completelyWithin(xMin, xMax)) { 41 if (span.completelyWithin(0.0f, fXMax)) {
51 next->pointSpan(span); 42 next->pointSpan(span);
52 return true; 43 return true;
53 } 44 }
54 if (1 == count || 0.0f == length) { 45 if (1 == count || 0.0f == length) {
55 return false; 46 return false;
56 } 47 }
57 48
58 SkScalar dx = length / (count - 1); 49 SkScalar dx = length / (count - 1);
59 50
60 // A B C 51 // A B C
(...skipping 17 matching lines...) Expand all
78 // span starting at C is 5 * dx, so count * dx. 69 // span starting at C is 5 * dx, so count * dx.
79 // Remember, count is the number of pixels needed for the destination an d the number of 70 // Remember, count is the number of pixels needed for the destination an d the number of
80 // samples. 71 // samples.
81 // Overall Strategy: 72 // Overall Strategy:
82 // * Under - for portions of the span < xMin, take the color at pixel {x Min, y} and use it 73 // * Under - for portions of the span < xMin, take the color at pixel {x Min, y} and use it
83 // to fill in the 5 pixel sampled from A to B. 74 // to fill in the 5 pixel sampled from A to B.
84 // * Middle - for the portion of the span between xMin and xMax sample n ormally. 75 // * Middle - for the portion of the span between xMin and xMax sample n ormally.
85 // * Over - for the portion of the span > xMax, take the color at pixel {xMax-1, y} and 76 // * Over - for the portion of the span > xMax, take the color at pixel {xMax-1, y} and
86 // use it to fill in the rest of the destination pixels. 77 // use it to fill in the rest of the destination pixels.
87 if (dx >= 0) { 78 if (dx >= 0) {
88 Span leftClamped = span.breakAt(xMin, dx); 79 Span leftClamped = span.breakAt(0.0f, dx);
89 if (!leftClamped.isEmpty()) { 80 if (!leftClamped.isEmpty()) {
90 leftClamped.clampToSinglePixel({xMin, y}); 81 leftClamped.clampToSinglePixel({0.0f, y});
91 next->pointSpan(leftClamped); 82 next->pointSpan(leftClamped);
92 } 83 }
93 Span middle = span.breakAt(xMax, dx); 84 Span center = span.breakAt(fXMax, dx);
94 if (!middle.isEmpty()) { 85 if (!center.isEmpty()) {
95 next->pointSpan(middle); 86 next->pointSpan(center);
96 } 87 }
97 if (!span.isEmpty()) { 88 if (!span.isEmpty()) {
98 span.clampToSinglePixel({xMax - 1, y}); 89 span.clampToSinglePixel({fXMax - 1, y});
99 next->pointSpan(span); 90 next->pointSpan(span);
100 } 91 }
101 } else { 92 } else {
102 Span rightClamped = span.breakAt(xMax, dx); 93 Span center = span.breakAt(fXMax, dx);
103 94
104 if (!rightClamped.isEmpty()) { 95 if (!span.isEmpty()) {
105 rightClamped.clampToSinglePixel({xMax - 1, y}); 96 span.clampToSinglePixel({fXMax - 1, y});
106 next->pointSpan(rightClamped); 97 next->pointSpan(span);
107 } 98 }
108 Span middle = span.breakAt(xMin, dx); 99 Span leftEdge = center.breakAt(0.0f, dx);
109 if (!middle.isEmpty()) { 100 if (!center.isEmpty()) {
110 next->pointSpan(middle); 101 next->pointSpan(center);
111 } 102 }
112 if (!span.isEmpty()) { 103 if (!leftEdge.isEmpty()) {
113 span.clampToSinglePixel({xMin, y}); 104 leftEdge.clampToSinglePixel({0.0f, y});
114 next->pointSpan(span); 105 next->pointSpan(leftEdge);
115 } 106 }
116 } 107 }
117 return true; 108 return true;
118 } 109 }
119 110
120 template <typename Next> 111 private:
121 bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) { 112 const Sk4s fXsMax;
122 return false; 113 const SkScalar fXMax;
114 };
115
116 class YClampStrategy {
117 public:
118 YClampStrategy(int32_t max)
119 : fYMax{SkScalar(max) - 0.5f}
120 , fYsMax{SkScalar(max) - 0.5f} { }
121
122 void tileYPoints(Sk4s* ys) {
123 *ys = Sk4s::Min(Sk4s::Max(*ys, 0.0f), fYsMax);
124 SkASSERT(0 <= (*ys)[0] && (*ys)[0] <= fYMax);
125 SkASSERT(0 <= (*ys)[1] && (*ys)[1] <= fYMax);
126 SkASSERT(0 <= (*ys)[2] && (*ys)[2] <= fYMax);
127 SkASSERT(0 <= (*ys)[3] && (*ys)[3] <= fYMax);
128 }
129
130 SkScalar tileY(SkScalar y) {
131 return std::min(std::max<SkScalar>(0.0f, y), fYMax);
123 } 132 }
124 133
125 private: 134 private:
126 const Sk4s fXMin{SK_FloatNegativeInfinity}; 135 const SkScalar fYMax;
127 const Sk4s fYMin{SK_FloatNegativeInfinity}; 136 const Sk4s fYsMax;
128 const Sk4s fXMax{SK_FloatInfinity};
129 const Sk4s fYMax{SK_FloatInfinity};
130 }; 137 };
131 138
132 class RepeatStrategy { 139 SkScalar tile_mod(SkScalar x, SkScalar base) {
140 return x - SkScalarFloorToScalar(x / base) * base;
141 }
142
143 class XRepeatStrategy {
133 public: 144 public:
134 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f / max} { } 145 XRepeatStrategy(int32_t max)
146 : fXMax{SkScalar(max)}
147 , fXsMax{SkScalar(max)}
148 , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))}
149 , fXsInvMax{1.0f / SkScalar(max)} { }
135 150
136 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f / max} { } 151 void tileXPoints(Sk4s* xs) {
137 152 Sk4s divX = *xs * fXsInvMax;
138 RepeatStrategy(SkSize max) 153 Sk4s modX = *xs - divX.floor() * fXsMax;
139 : fXMax{X(max)}, fXInvMax{1.0f / X(max)}, fYMax{Y(max)}, fYInvMax{1.0f / Y(max)} { } 154 *xs = Sk4s::Min(fXsCap, modX);
140 155 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax);
141 void processPoints(Sk4s* xs, Sk4s* ys) { 156 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax);
142 Sk4s divX = (*xs * fXInvMax).floor(); 157 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax);
143 Sk4s divY = (*ys * fYInvMax).floor(); 158 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax);
144 Sk4s baseX = (divX * fXMax);
145 Sk4s baseY = (divY * fYMax);
146 *xs = *xs - baseX;
147 *ys = *ys - baseY;
148 } 159 }
149 160
150 template<typename Next> 161 template<typename Next>
151 bool maybeProcessSpan(Span originalSpan, Next* next) { 162 bool maybeProcessSpan(Span originalSpan, Next* next) {
152 SkASSERT(!originalSpan.isEmpty()); 163 SkASSERT(!originalSpan.isEmpty());
153 SkPoint start; 164 SkPoint start; SkScalar length; int count;
154 SkScalar length;
155 int count;
156 std::tie(start, length, count) = originalSpan; 165 std::tie(start, length, count) = originalSpan;
157 // Make x and y in range on the tile. 166 // Make x and y in range on the tile.
158 SkScalar x = TileMod(X(start), fXMax[0]); 167 SkScalar x = tile_mod(X(start), fXMax);
159 SkScalar y = TileMod(Y(start), fYMax[0]); 168 SkScalar y = Y(start);
160 SkScalar xMax = fXMax[0];
161 SkScalar xMin = 0.0f;
162 SkScalar dx = length / (count - 1); 169 SkScalar dx = length / (count - 1);
163 170
164 // No need trying to go fast because the steps are larger than a tile or there is one point. 171 // No need trying to go fast because the steps are larger than a tile or there is one point.
165 if (SkScalarAbs(dx) >= xMax || count <= 1) { 172 if (SkScalarAbs(dx) >= fXMax || count <= 1) {
166 return false; 173 return false;
167 } 174 }
168 175
169 // A B C D Z 176 // A B C D Z
170 // +-------+-------+-------++-------+-------+-------++ +-------+---- ---++------ 177 // +-------+-------+-------++-------+-------+-------++ +-------+---- ---++------
171 // | | *---|*---*--||-*---*-|---*---|*---*--|| |--*---*| || 178 // | | *---|*---*--||-*---*-|---*---|*---*--|| |--*---*| ||
172 // | | | || | | || ... | | || 179 // | | | || | | || ... | | ||
173 // | | | || | | || | | || 180 // | | | || | | || | | ||
174 // +-------+-------+-------++-------+-------+-------++ +-------+---- ---++------ 181 // +-------+-------+-------++-------+-------+-------++ +-------+---- ---++------
175 // ^^ ^^ ^^ 182 // ^^ ^^ ^^
(...skipping 16 matching lines...) Expand all
192 // 199 //
193 // Overall Strategy: 200 // Overall Strategy:
194 // While the span hangs over the edge of the tile, draw the span coverin g the tile then 201 // While the span hangs over the edge of the tile, draw the span coverin g the tile then
195 // slide the span over to the next tile. 202 // slide the span over to the next tile.
196 203
197 // The guard could have been count > 0, but then a bunch of math would b e done in the 204 // The guard could have been count > 0, but then a bunch of math would b e done in the
198 // common case. 205 // common case.
199 206
200 Span span({x, y}, length, count); 207 Span span({x, y}, length, count);
201 if (dx > 0) { 208 if (dx > 0) {
202 while (!span.isEmpty() && span.endX() >= xMax) { 209 while (!span.isEmpty() && span.endX() >= fXMax) {
203 Span toDraw = span.breakAt(xMax, dx); 210 Span toDraw = span.breakAt(fXMax, dx);
204 next->pointSpan(toDraw); 211 next->pointSpan(toDraw);
205 span.offset(-xMax); 212 span.offset(-fXMax);
206 } 213 }
207 } else { 214 } else {
208 while (!span.isEmpty() && span.endX() < xMin) { 215 while (!span.isEmpty() && span.endX() < 0.0f) {
209 Span toDraw = span.breakAt(xMin, dx); 216 Span toDraw = span.breakAt(0.0f, dx);
210 next->pointSpan(toDraw); 217 next->pointSpan(toDraw);
211 span.offset(xMax); 218 span.offset(fXMax);
212 } 219 }
213 } 220 }
214 221
215 // All on a single tile. 222 // All on a single tile.
216 if (!span.isEmpty()) { 223 if (!span.isEmpty()) {
217 next->pointSpan(span); 224 next->pointSpan(span);
218 } 225 }
219 226
220 return true; 227 return true;
221 } 228 }
222 229
223 template <typename Next> 230 private:
224 bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) { 231 const SkScalar fXMax;
225 return false; 232 const Sk4s fXsMax;
233 const Sk4s fXsCap;
234 const Sk4s fXsInvMax;
235 };
236
237 class YRepeatStrategy {
238 public:
239 YRepeatStrategy(int32_t max)
240 : fYMax{SkScalar(max)}
241 , fYsMax{SkScalar(max)}
242 , fYsInvMax{1.0f / SkScalar(max)} { }
243
244 void tileYPoints(Sk4s* ys) {
245 Sk4s divY = *ys * fYsInvMax;
246 Sk4s modY = *ys - divY.floor() * fYsMax;
247 *ys = modY;
248 SkASSERT(0 <= (*ys)[0] && (*ys)[0] < fYMax);
249 SkASSERT(0 <= (*ys)[1] && (*ys)[1] < fYMax);
250 SkASSERT(0 <= (*ys)[2] && (*ys)[2] < fYMax);
251 SkASSERT(0 <= (*ys)[3] && (*ys)[3] < fYMax);
252 }
253
254 SkScalar tileY(SkScalar y) {
255 SkScalar answer = tile_mod(y, fYMax);
256 SkASSERT(0 <= answer && answer < fYMax);
257 return answer;
226 } 258 }
227 259
228 private: 260 private:
229 SkScalar TileMod(SkScalar x, SkScalar base) { 261 const SkScalar fYMax;
230 return x - std::floor(x / base) * base; 262 const Sk4s fYsMax;
263 const Sk4s fYsInvMax;
264 };
265 // max = 40
266 // mq2[x_] := Abs[(x - 40) - Floor[(x - 40)/80] * 80 - 40]
267 class XMirrorStrategy {
268 public:
269 XMirrorStrategy(int32_t max)
270 : fXsMax{SkScalar(max)}
271 , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))}
272 , fXsDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { }
273
274 void tileXPoints(Sk4s* xs) {
275 Sk4f bias = *xs - fXsMax;
276 Sk4f div = bias * fXsDoubleInvMax;
277 Sk4f mod = bias - div.floor() * 2.0f * fXsMax;
278 Sk4f unbias = mod - fXsMax;
279 *xs = Sk4f::Min(unbias.abs(), fXsCap);
280 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXsMax[0]);
281 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXsMax[0]);
282 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXsMax[0]);
283 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXsMax[0]);
231 } 284 }
232 const Sk4s fXMax{0.0f}; 285
233 const Sk4s fXInvMax{0.0f}; 286 template <typename Next>
234 const Sk4s fYMax{0.0f}; 287 bool maybeProcessSpan(Span originalSpan, Next* next) { return false; }
235 const Sk4s fYInvMax{0.0f}; 288
289 private:
290 Sk4f fXsMax;
291 Sk4f fXsCap;
292 Sk4f fXsDoubleInvMax;
293 };
294
295 class YMirrorStrategy {
296 public:
297 YMirrorStrategy(int32_t max)
298 : fYMax{SkScalar(max)}
299 , fYsMax{SkScalar(max)}
300 , fYsCap{nextafterf(SkScalar(max), 0.0f)}
301 , fYsDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { }
302
303 void tileYPoints(Sk4s* ys) {
304 Sk4f bias = *ys - fYsMax;
305 Sk4f div = bias * fYsDoubleInvMax;
306 Sk4f mod = bias - div.floor() * 2.0f * fYsMax;
307 Sk4f unbias = mod - fYsMax;
308 *ys = Sk4f::Min(unbias.abs(), fYsCap);
309 SkASSERT(0 <= (*ys)[0] && (*ys)[0] < fYMax);
310 SkASSERT(0 <= (*ys)[1] && (*ys)[1] < fYMax);
311 SkASSERT(0 <= (*ys)[2] && (*ys)[2] < fYMax);
312 SkASSERT(0 <= (*ys)[3] && (*ys)[3] < fYMax);
313 }
314
315 SkScalar tileY(SkScalar y) {
316 SkScalar bias = y - fYMax;
317 SkScalar div = bias * fYsDoubleInvMax[0];
318 SkScalar mod = bias - SkScalarFloorToScalar(div) * 2.0f * fYMax;
319 SkScalar unbias = mod - fYMax;
320 SkScalar answer = SkMinScalar(SkScalarAbs(unbias), fYsCap[0]);
321 SkASSERT(0 <= answer && answer < fYMax);
322 return answer;
323 };
324
325 private:
326 SkScalar fYMax;
327 Sk4f fYsMax;
328 Sk4f fYsCap;
329 Sk4f fYsDoubleInvMax;
236 }; 330 };
237 331
238 } // namespace 332 } // namespace
239 #endif // SkLinearBitmapPipeline_tile_DEFINED 333 #endif // SkLinearBitmapPipeline_tile_DEFINED
OLDNEW
« no previous file with comments | « src/core/SkLinearBitmapPipeline_sample.h ('k') | tests/SkLinearBitmapPipelineTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698