| 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 |
| 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 XClampStrategy { | 18 class XClampStrategy { |
| 19 public: | 19 public: |
| 20 XClampStrategy(int32_t max) | 20 XClampStrategy(int32_t max) |
| 21 : fXsMax{SkScalar(max - 0.5f)} | 21 : fXMaxPixel{SkScalar(max - 0.5f)} |
| 22 , fXMax{SkScalar(max)} { } | 22 , fXMax{SkScalar(max)} { } |
| 23 | 23 |
| 24 void tileXPoints(Sk4s* xs) { | 24 void tileXPoints(Sk4s* xs) { |
| 25 *xs = Sk4s::Min(Sk4s::Max(*xs, 0.0f), fXsMax); | 25 *xs = Sk4s::Min(Sk4s::Max(*xs, 0.0f), fXMaxPixel); |
| 26 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); | 26 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); |
| 27 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); | 27 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); |
| 28 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); | 28 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); |
| 29 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); | 29 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); |
| 30 } | 30 } |
| 31 | 31 |
| 32 template<typename Next> | 32 template<typename Next> |
| 33 bool maybeProcessSpan(Span originalSpan, Next* next) { | 33 bool maybeProcessSpan(Span originalSpan, Next* next) { |
| 34 SkASSERT(!originalSpan.isEmpty()); | 34 SkASSERT(!originalSpan.isEmpty()); |
| 35 SkPoint start; SkScalar length; int count; | 35 SkPoint start; SkScalar length; int count; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 } | 101 } |
| 102 if (!span.isEmpty()) { | 102 if (!span.isEmpty()) { |
| 103 span.clampToSinglePixel({0.0f, y}); | 103 span.clampToSinglePixel({0.0f, y}); |
| 104 next->pointSpan(span); | 104 next->pointSpan(span); |
| 105 } | 105 } |
| 106 } | 106 } |
| 107 return true; | 107 return true; |
| 108 } | 108 } |
| 109 | 109 |
| 110 private: | 110 private: |
| 111 const Sk4s fXsMax; | 111 const SkScalar fXMaxPixel; |
| 112 const SkScalar fXMax; | 112 const SkScalar fXMax; |
| 113 }; | 113 }; |
| 114 | 114 |
| 115 class YClampStrategy { | 115 class YClampStrategy { |
| 116 public: | 116 public: |
| 117 YClampStrategy(int32_t max) | 117 YClampStrategy(int32_t max) |
| 118 : fYMax{SkScalar(max) - 0.5f} | 118 : fYMax{SkScalar(max) - 0.5f} { } |
| 119 , fYsMax{SkScalar(max) - 0.5f} { } | |
| 120 | 119 |
| 121 void tileYPoints(Sk4s* ys) { | 120 void tileYPoints(Sk4s* ys) { |
| 122 *ys = Sk4s::Min(Sk4s::Max(*ys, 0.0f), fYsMax); | 121 *ys = Sk4s::Min(Sk4s::Max(*ys, 0.0f), fYMax); |
| 123 SkASSERT(0 <= (*ys)[0] && (*ys)[0] <= fYMax); | 122 SkASSERT(0 <= (*ys)[0] && (*ys)[0] <= fYMax); |
| 124 SkASSERT(0 <= (*ys)[1] && (*ys)[1] <= fYMax); | 123 SkASSERT(0 <= (*ys)[1] && (*ys)[1] <= fYMax); |
| 125 SkASSERT(0 <= (*ys)[2] && (*ys)[2] <= fYMax); | 124 SkASSERT(0 <= (*ys)[2] && (*ys)[2] <= fYMax); |
| 126 SkASSERT(0 <= (*ys)[3] && (*ys)[3] <= fYMax); | 125 SkASSERT(0 <= (*ys)[3] && (*ys)[3] <= fYMax); |
| 127 } | 126 } |
| 128 | 127 |
| 129 SkScalar tileY(SkScalar y) { | 128 SkScalar tileY(SkScalar y) { |
| 130 return std::min(std::max<SkScalar>(0.0f, y), fYMax); | 129 return std::min(std::max<SkScalar>(0.0f, y), fYMax); |
| 131 } | 130 } |
| 132 | 131 |
| 133 private: | 132 private: |
| 134 const SkScalar fYMax; | 133 const SkScalar fYMax; |
| 135 const Sk4s fYsMax; | |
| 136 }; | 134 }; |
| 137 | 135 |
| 138 SkScalar tile_mod(SkScalar x, SkScalar base) { | 136 SkScalar tile_mod(SkScalar x, SkScalar base) { |
| 139 return x - SkScalarFloorToScalar(x / base) * base; | 137 return x - SkScalarFloorToScalar(x / base) * base; |
| 140 } | 138 } |
| 141 | 139 |
| 142 class XRepeatStrategy { | 140 class XRepeatStrategy { |
| 143 public: | 141 public: |
| 144 XRepeatStrategy(int32_t max) | 142 XRepeatStrategy(int32_t max) |
| 145 : fXMax{SkScalar(max)} | 143 : fXMax{SkScalar(max)} |
| 146 , fXsMax{SkScalar(max)} | 144 , fXCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} |
| 147 , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} | 145 , fXInvMax{1.0f / SkScalar(max)} { } |
| 148 , fXsInvMax{1.0f / SkScalar(max)} { } | |
| 149 | 146 |
| 150 void tileXPoints(Sk4s* xs) { | 147 void tileXPoints(Sk4s* xs) { |
| 151 Sk4s divX = *xs * fXsInvMax; | 148 Sk4s divX = *xs * fXInvMax; |
| 152 Sk4s modX = *xs - divX.floor() * fXsMax; | 149 Sk4s modX = *xs - divX.floor() * fXMax; |
| 153 *xs = Sk4s::Min(fXsCap, modX); | 150 *xs = Sk4s::Min(fXCap, modX); |
| 154 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); | 151 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); |
| 155 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); | 152 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); |
| 156 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); | 153 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); |
| 157 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); | 154 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); |
| 158 } | 155 } |
| 159 | 156 |
| 160 template<typename Next> | 157 template<typename Next> |
| 161 bool maybeProcessSpan(Span originalSpan, Next* next) { | 158 bool maybeProcessSpan(Span originalSpan, Next* next) { |
| 162 SkASSERT(!originalSpan.isEmpty()); | 159 SkASSERT(!originalSpan.isEmpty()); |
| 163 SkPoint start; SkScalar length; int count; | 160 SkPoint start; SkScalar length; int count; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 // All on a single tile. | 218 // All on a single tile. |
| 222 if (!span.isEmpty()) { | 219 if (!span.isEmpty()) { |
| 223 next->pointSpan(span); | 220 next->pointSpan(span); |
| 224 } | 221 } |
| 225 | 222 |
| 226 return true; | 223 return true; |
| 227 } | 224 } |
| 228 | 225 |
| 229 private: | 226 private: |
| 230 const SkScalar fXMax; | 227 const SkScalar fXMax; |
| 231 const Sk4s fXsMax; | 228 const SkScalar fXCap; |
| 232 const Sk4s fXsCap; | 229 const SkScalar fXInvMax; |
| 233 const Sk4s fXsInvMax; | |
| 234 }; | 230 }; |
| 235 | 231 |
| 236 // The XRepeatUnitScaleStrategy exploits the situation where dx = 1.0. The main
advantage is that | 232 // The XRepeatUnitScaleStrategy exploits the situation where dx = 1.0. The main
advantage is that |
| 237 // the relationship between the sample points and the source pixels does not cha
nge from tile to | 233 // the relationship between the sample points and the source pixels does not cha
nge from tile to |
| 238 // repeated tile. This allows the tiler to calculate the span once and re-use it
for each | 234 // repeated tile. This allows the tiler to calculate the span once and re-use it
for each |
| 239 // repeated tile. This is later exploited by some samplers to avoid converting p
ixels to linear | 235 // repeated tile. This is later exploited by some samplers to avoid converting p
ixels to linear |
| 240 // space allowing the use of memmove to place pixel in the destination. | 236 // space allowing the use of memmove to place pixel in the destination. |
| 241 class XRepeatUnitScaleStrategy { | 237 class XRepeatUnitScaleStrategy { |
| 242 public: | 238 public: |
| 243 XRepeatUnitScaleStrategy(int32_t max) | 239 XRepeatUnitScaleStrategy(int32_t max) |
| 244 : fXMax{SkScalar(max)} | 240 : fXMax{SkScalar(max)} |
| 245 , fXsMax{SkScalar(max)} | 241 , fXCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} |
| 246 , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} | 242 , fXInvMax{1.0f / SkScalar(max)} { } |
| 247 , fXsInvMax{1.0f / SkScalar(max)} { } | |
| 248 | 243 |
| 249 void tileXPoints(Sk4s* xs) { | 244 void tileXPoints(Sk4s* xs) { |
| 250 Sk4s divX = *xs * fXsInvMax; | 245 Sk4s divX = *xs * fXInvMax; |
| 251 Sk4s modX = *xs - divX.floor() * fXsMax; | 246 Sk4s modX = *xs - divX.floor() * fXMax; |
| 252 *xs = Sk4s::Min(fXsCap, modX); | 247 *xs = Sk4s::Min(fXCap, modX); |
| 253 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); | 248 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); |
| 254 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); | 249 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); |
| 255 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); | 250 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); |
| 256 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); | 251 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); |
| 257 } | 252 } |
| 258 | 253 |
| 259 template<typename Next> | 254 template<typename Next> |
| 260 bool maybeProcessSpan(Span originalSpan, Next* next) { | 255 bool maybeProcessSpan(Span originalSpan, Next* next) { |
| 261 SkASSERT(!originalSpan.isEmpty()); | 256 SkASSERT(!originalSpan.isEmpty()); |
| 262 SkPoint start; SkScalar length; int count; | 257 SkPoint start; SkScalar length; int count; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 span.offset(-advance); | 307 span.offset(-advance); |
| 313 SkASSERT(0.0f <= span.startX() && span.endX() < fXMax); | 308 SkASSERT(0.0f <= span.startX() && span.endX() < fXMax); |
| 314 next->pointSpan(span); | 309 next->pointSpan(span); |
| 315 } | 310 } |
| 316 | 311 |
| 317 return true; | 312 return true; |
| 318 } | 313 } |
| 319 | 314 |
| 320 private: | 315 private: |
| 321 const SkScalar fXMax; | 316 const SkScalar fXMax; |
| 322 const Sk4s fXsMax; | 317 const SkScalar fXCap; |
| 323 const Sk4s fXsCap; | 318 const SkScalar fXInvMax; |
| 324 const Sk4s fXsInvMax; | |
| 325 }; | 319 }; |
| 326 | 320 |
| 327 class YRepeatStrategy { | 321 class YRepeatStrategy { |
| 328 public: | 322 public: |
| 329 YRepeatStrategy(int32_t max) | 323 YRepeatStrategy(int32_t max) |
| 330 : fYMax{SkScalar(max)} | 324 : fYMax{SkScalar(max)} |
| 331 , fYsMax{SkScalar(max)} | |
| 332 , fYsInvMax{1.0f / SkScalar(max)} { } | 325 , fYsInvMax{1.0f / SkScalar(max)} { } |
| 333 | 326 |
| 334 void tileYPoints(Sk4s* ys) { | 327 void tileYPoints(Sk4s* ys) { |
| 335 Sk4s divY = *ys * fYsInvMax; | 328 Sk4s divY = *ys * fYsInvMax; |
| 336 Sk4s modY = *ys - divY.floor() * fYsMax; | 329 Sk4s modY = *ys - divY.floor() * fYMax; |
| 337 *ys = modY; | 330 *ys = modY; |
| 338 SkASSERT(0 <= (*ys)[0] && (*ys)[0] < fYMax); | 331 SkASSERT(0 <= (*ys)[0] && (*ys)[0] < fYMax); |
| 339 SkASSERT(0 <= (*ys)[1] && (*ys)[1] < fYMax); | 332 SkASSERT(0 <= (*ys)[1] && (*ys)[1] < fYMax); |
| 340 SkASSERT(0 <= (*ys)[2] && (*ys)[2] < fYMax); | 333 SkASSERT(0 <= (*ys)[2] && (*ys)[2] < fYMax); |
| 341 SkASSERT(0 <= (*ys)[3] && (*ys)[3] < fYMax); | 334 SkASSERT(0 <= (*ys)[3] && (*ys)[3] < fYMax); |
| 342 } | 335 } |
| 343 | 336 |
| 344 SkScalar tileY(SkScalar y) { | 337 SkScalar tileY(SkScalar y) { |
| 345 SkScalar answer = tile_mod(y, fYMax); | 338 SkScalar answer = tile_mod(y, fYMax); |
| 346 SkASSERT(0 <= answer && answer < fYMax); | 339 SkASSERT(0 <= answer && answer < fYMax); |
| 347 return answer; | 340 return answer; |
| 348 } | 341 } |
| 349 | 342 |
| 350 private: | 343 private: |
| 351 const SkScalar fYMax; | 344 const SkScalar fYMax; |
| 352 const Sk4s fYsMax; | 345 const SkScalar fYsInvMax; |
| 353 const Sk4s fYsInvMax; | |
| 354 }; | 346 }; |
| 355 // max = 40 | 347 // max = 40 |
| 356 // mq2[x_] := Abs[(x - 40) - Floor[(x - 40)/80] * 80 - 40] | 348 // mq2[x_] := Abs[(x - 40) - Floor[(x - 40)/80] * 80 - 40] |
| 357 class XMirrorStrategy { | 349 class XMirrorStrategy { |
| 358 public: | 350 public: |
| 359 XMirrorStrategy(int32_t max) | 351 XMirrorStrategy(int32_t max) |
| 360 : fXsMax{SkScalar(max)} | 352 : fXMax{SkScalar(max)} |
| 361 , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} | 353 , fXCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} |
| 362 , fXsDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { } | 354 , fXDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { } |
| 363 | 355 |
| 364 void tileXPoints(Sk4s* xs) { | 356 void tileXPoints(Sk4s* xs) { |
| 365 Sk4f bias = *xs - fXsMax; | 357 Sk4f bias = *xs - fXMax; |
| 366 Sk4f div = bias * fXsDoubleInvMax; | 358 Sk4f div = bias * fXDoubleInvMax; |
| 367 Sk4f mod = bias - div.floor() * 2.0f * fXsMax; | 359 Sk4f mod = bias - div.floor() * 2.0f * fXMax; |
| 368 Sk4f unbias = mod - fXsMax; | 360 Sk4f unbias = mod - fXMax; |
| 369 *xs = Sk4f::Min(unbias.abs(), fXsCap); | 361 *xs = Sk4f::Min(unbias.abs(), fXCap); |
| 370 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXsMax[0]); | 362 SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); |
| 371 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXsMax[0]); | 363 SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); |
| 372 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXsMax[0]); | 364 SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); |
| 373 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXsMax[0]); | 365 SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); |
| 374 } | 366 } |
| 375 | 367 |
| 376 template <typename Next> | 368 template <typename Next> |
| 377 bool maybeProcessSpan(Span originalSpan, Next* next) { return false; } | 369 bool maybeProcessSpan(Span originalSpan, Next* next) { return false; } |
| 378 | 370 |
| 379 private: | 371 private: |
| 380 Sk4f fXsMax; | 372 SkScalar fXMax; |
| 381 Sk4f fXsCap; | 373 SkScalar fXCap; |
| 382 Sk4f fXsDoubleInvMax; | 374 SkScalar fXDoubleInvMax; |
| 383 }; | 375 }; |
| 384 | 376 |
| 385 class YMirrorStrategy { | 377 class YMirrorStrategy { |
| 386 public: | 378 public: |
| 387 YMirrorStrategy(int32_t max) | 379 YMirrorStrategy(int32_t max) |
| 388 : fYMax{SkScalar(max)} | 380 : fYMax{SkScalar(max)} |
| 389 , fYsMax{SkScalar(max)} | 381 , fYCap{nextafterf(SkScalar(max), 0.0f)} |
| 390 , fYsCap{nextafterf(SkScalar(max), 0.0f)} | 382 , fYDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { } |
| 391 , fYsDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { } | |
| 392 | 383 |
| 393 void tileYPoints(Sk4s* ys) { | 384 void tileYPoints(Sk4s* ys) { |
| 394 Sk4f bias = *ys - fYsMax; | 385 Sk4f bias = *ys - fYMax; |
| 395 Sk4f div = bias * fYsDoubleInvMax; | 386 Sk4f div = bias * fYDoubleInvMax; |
| 396 Sk4f mod = bias - div.floor() * 2.0f * fYsMax; | 387 Sk4f mod = bias - div.floor() * 2.0f * fYMax; |
| 397 Sk4f unbias = mod - fYsMax; | 388 Sk4f unbias = mod - fYMax; |
| 398 *ys = Sk4f::Min(unbias.abs(), fYsCap); | 389 *ys = Sk4f::Min(unbias.abs(), fYCap); |
| 399 SkASSERT(0 <= (*ys)[0] && (*ys)[0] < fYMax); | 390 SkASSERT(0 <= (*ys)[0] && (*ys)[0] < fYMax); |
| 400 SkASSERT(0 <= (*ys)[1] && (*ys)[1] < fYMax); | 391 SkASSERT(0 <= (*ys)[1] && (*ys)[1] < fYMax); |
| 401 SkASSERT(0 <= (*ys)[2] && (*ys)[2] < fYMax); | 392 SkASSERT(0 <= (*ys)[2] && (*ys)[2] < fYMax); |
| 402 SkASSERT(0 <= (*ys)[3] && (*ys)[3] < fYMax); | 393 SkASSERT(0 <= (*ys)[3] && (*ys)[3] < fYMax); |
| 403 } | 394 } |
| 404 | 395 |
| 405 SkScalar tileY(SkScalar y) { | 396 SkScalar tileY(SkScalar y) { |
| 406 SkScalar bias = y - fYMax; | 397 SkScalar bias = y - fYMax; |
| 407 SkScalar div = bias * fYsDoubleInvMax[0]; | 398 SkScalar div = bias * fYDoubleInvMax; |
| 408 SkScalar mod = bias - SkScalarFloorToScalar(div) * 2.0f * fYMax; | 399 SkScalar mod = bias - SkScalarFloorToScalar(div) * 2.0f * fYMax; |
| 409 SkScalar unbias = mod - fYMax; | 400 SkScalar unbias = mod - fYMax; |
| 410 SkScalar answer = SkMinScalar(SkScalarAbs(unbias), fYsCap[0]); | 401 SkScalar answer = SkMinScalar(SkScalarAbs(unbias), fYCap); |
| 411 SkASSERT(0 <= answer && answer < fYMax); | 402 SkASSERT(0 <= answer && answer < fYMax); |
| 412 return answer; | 403 return answer; |
| 413 } | 404 } |
| 414 | 405 |
| 415 private: | 406 private: |
| 416 SkScalar fYMax; | 407 SkScalar fYMax; |
| 417 Sk4f fYsMax; | 408 SkScalar fYCap; |
| 418 Sk4f fYsCap; | 409 SkScalar fYDoubleInvMax; |
| 419 Sk4f fYsDoubleInvMax; | |
| 420 }; | 410 }; |
| 421 | 411 |
| 422 } // namespace | 412 } // namespace |
| 423 #endif // SkLinearBitmapPipeline_tile_DEFINED | 413 #endif // SkLinearBitmapPipeline_tile_DEFINED |
| OLD | NEW |