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 // Note: The span length has an unintuitive relation to the tile width.
The tile width is |
| 292 // a half open interval [tb, te), but the span is a closed interval [sb,
se]. In order to |
| 293 // compare the two, you need to convert the span to a half open interval
. This is done by |
| 294 // adding dx to se. So, the span becomes: [sb, se + dx). Hence the + 1.0
f below. |
| 295 SkScalar div = (span.length() + 1.0f) / fXMax; |
| 296 int32_t repeatCount = SkScalarFloorToInt(div); |
| 297 Span repeatableSpan{{0.0f, y}, fXMax - 1.0f, SkScalarFloorToInt(fXMax)}; |
| 298 |
| 299 // Repeat the center section. |
| 300 SkASSERT(0.0f <= repeatableSpan.startX() && repeatableSpan.endX() < fXMa
x); |
| 301 next->repeatSpan(repeatableSpan, repeatCount); |
| 302 |
| 303 // Calculate the advance past the center portion. |
| 304 SkScalar advance = SkScalar(repeatCount) * fXMax; |
| 305 |
| 306 // There may be some of the span left over. |
| 307 span.breakAt(advance, 1.0f); |
| 308 |
| 309 // All on a single tile. |
| 310 if (!span.isEmpty()) { |
| 311 span.offset(-advance); |
| 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 |