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 #ifndef SkLinearBitmapPipeline_tile_DEFINED | 8 #ifndef SkLinearBitmapPipeline_tile_DEFINED |
9 #define SkLinearBitmapPipeline_tile_DEFINED | 9 #define SkLinearBitmapPipeline_tile_DEFINED |
10 | 10 |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
227 return true; | 227 return true; |
228 } | 228 } |
229 | 229 |
230 private: | 230 private: |
231 const SkScalar fXMax; | 231 const SkScalar fXMax; |
232 const Sk4s fXsMax; | 232 const Sk4s fXsMax; |
233 const Sk4s fXsCap; | 233 const Sk4s fXsCap; |
234 const Sk4s fXsInvMax; | 234 const Sk4s fXsInvMax; |
235 }; | 235 }; |
236 | 236 |
237 // The XRepeatUnitScaleStrategy exploits the situation where dx = 1.0. The main advantage is that | |
238 // the relationship between the sample points and the source pixels does not cha nge from tile to | |
239 // repeated tile. This allows the tiler to calculate the span once and re-use it for each | |
240 // repeated tile. This is later exploited by some samplers to avoid converting p ixels to linear | |
241 // space allowing the use of memmove to place pixel in the destination. | |
242 class XRepeatUnitScaleStrategy { | |
243 public: | |
244 XRepeatUnitScaleStrategy(int32_t max) | |
245 : fXMax{SkScalar(max)} | |
246 , fXsMax{SkScalar(max)} | |
247 , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} | |
248 , fXsInvMax{1.0f / SkScalar(max)} { } | |
249 | |
250 void tileXPoints(Sk4s* xs) { | |
251 Sk4s divX = *xs * fXsInvMax; | |
252 Sk4s modX = *xs - divX.floor() * fXsMax; | |
253 *xs = Sk4s::Min(fXsCap, modX); | |
254 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); | |
255 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); | |
256 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); | |
257 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); | |
258 } | |
259 | |
260 template<typename Next> | |
261 bool maybeProcessSpan(Span originalSpan, Next* next) { | |
262 SkASSERT(!originalSpan.isEmpty()); | |
263 SkPoint start; SkScalar length; int count; | |
264 std::tie(start, length, count) = originalSpan; | |
265 // Make x and y in range on the tile. | |
266 SkScalar x = tile_mod(X(start), fXMax); | |
267 SkScalar y = Y(start); | |
268 | |
269 // No need trying to go fast because the steps are larger than a tile or there is one point. | |
270 if (fXMax == 1 || count <= 1) { | |
271 return false; | |
272 } | |
273 | |
274 // x should be on the tile. | |
275 SkASSERT(0.0f <= x && x < fXMax); | |
276 Span span({x, y}, length, count); | |
277 | |
278 if (SkScalarFloorToScalar(x) != 0.0f) { | |
279 Span toDraw = span.breakAt(fXMax, 1.0f); | |
280 SkASSERT(0.0f <= toDraw.startX() && toDraw.endX() < fXMax); | |
281 next->pointSpan(toDraw); | |
282 span.offset(-fXMax); | |
283 } | |
284 | |
285 // All of the span could have been on the first tile. If so, then no wor k to do. | |
286 if (span.isEmpty()) return true; | |
287 | |
288 // At this point the span should be aligned to zero. | |
289 SkASSERT(SkScalarFloorToScalar(span.startX()) == 0.0f); | |
290 | |
291 // At this point the span should be aligned to zero. | |
292 SkASSERT(SkScalarFloorToScalar(span.startX()) == 0.0f); | |
f(malita)
2016/04/07 00:56:45
Nit: double-paste?
herb_g
2016/04/07 14:37:03
Done.
| |
293 | |
294 // Note: The span length has an unintuitive relation to the tile width. The tile width is | |
295 // a half open interval [tb, te), but the span is a closed interval [sb, se]. In order to | |
296 // compare the two, you need to convert the span to a half open interval . This is done by | |
297 // adding dx to se. So, the span becomes: [sb, se + dx). Hence the + 1.0 f below. | |
298 SkScalar div = (span.length() + 1.0f) / fXMax; | |
299 int32_t repeatCount = SkScalarFloorToInt(div); | |
300 Span repeatableSpan{{0.0f, y}, fXMax - 1.0f, SkScalarFloorToInt(fXMax)}; | |
301 | |
302 // Repeat the center section. | |
303 SkASSERT(0.0f <= repeatableSpan.startX() && repeatableSpan.endX() < fXMa x); | |
304 next->repeatSpan(repeatableSpan, repeatCount); | |
305 | |
306 // There may be some of the span left over. | |
307 span.breakAt(SkScalar(repeatCount) * fXMax, 1.0f); | |
308 | |
309 // All on a single tile. | |
310 if (!span.isEmpty()) { | |
311 span.offset(-fXMax * SkScalar(repeatCount)); | |
f(malita)
2016/04/07 00:56:45
Nit: maybe use a const SkScalar advance = fXMax *
herb_g
2016/04/07 14:37:03
Done.
| |
312 SkASSERT(0.0f <= span.startX() && span.endX() < fXMax); | |
313 next->pointSpan(span); | |
314 } | |
315 | |
316 return true; | |
317 } | |
318 | |
319 private: | |
320 const SkScalar fXMax; | |
321 const Sk4s fXsMax; | |
322 const Sk4s fXsCap; | |
323 const Sk4s fXsInvMax; | |
324 }; | |
325 | |
237 class YRepeatStrategy { | 326 class YRepeatStrategy { |
238 public: | 327 public: |
239 YRepeatStrategy(int32_t max) | 328 YRepeatStrategy(int32_t max) |
240 : fYMax{SkScalar(max)} | 329 : fYMax{SkScalar(max)} |
241 , fYsMax{SkScalar(max)} | 330 , fYsMax{SkScalar(max)} |
242 , fYsInvMax{1.0f / SkScalar(max)} { } | 331 , fYsInvMax{1.0f / SkScalar(max)} { } |
243 | 332 |
244 void tileYPoints(Sk4s* ys) { | 333 void tileYPoints(Sk4s* ys) { |
245 Sk4s divY = *ys * fYsInvMax; | 334 Sk4s divY = *ys * fYsInvMax; |
246 Sk4s modY = *ys - divY.floor() * fYsMax; | 335 Sk4s modY = *ys - divY.floor() * fYsMax; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
324 | 413 |
325 private: | 414 private: |
326 SkScalar fYMax; | 415 SkScalar fYMax; |
327 Sk4f fYsMax; | 416 Sk4f fYsMax; |
328 Sk4f fYsCap; | 417 Sk4f fYsCap; |
329 Sk4f fYsDoubleInvMax; | 418 Sk4f fYsDoubleInvMax; |
330 }; | 419 }; |
331 | 420 |
332 } // namespace | 421 } // namespace |
333 #endif // SkLinearBitmapPipeline_tile_DEFINED | 422 #endif // SkLinearBitmapPipeline_tile_DEFINED |
OLD | NEW |