1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkLinearBitmapPipeline.h" 9 #include "SkPM4f.h" 10 11 #include <algorithm> 12 #include <cmath> 13 #include <limits> 14 #include "SkColor.h" 15 #include "SkSize.h" 16 17 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. 18 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 19 #define VECTORCALL __vectorcall 20 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) 21 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) 22 #else 23 #define VECTORCALL 24 #endif 25 26 class SkLinearBitmapPipeline::PointProcessorInterface { 27 public: 28 virtual ~PointProcessorInterface() { } 29 virtual void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) = 0; 30 virtual void VECTORCALL pointList4(Sk4f xs, Sk4f ys) = 0; 31 32 // The pointSpan method efficiently process horizontal spans of pixels. 33 // * start - the point where to start the span. 34 // * length - the number of pixels to traverse in source space. 35 // * count - the number of pixels to produce in destination space. 36 // Both start and length are mapped through the inversion matrix to produce values in source 37 // space. After the matrix operation, the tilers may break the spans up into smaller spans. 38 // The tilers can produce spans that seem nonsensical. 39 // * The clamp tiler can create spans with length of 0. This indicates to copy an edge pixel out 40 // to the edge of the destination scan. 41 // * The mirror tiler can produce spans with negative length. This indicates that the source 42 // should be traversed in the opposite direction to the destination pixels. 43 virtual void pointSpan(SkPoint start, SkScalar length, int count) = 0; 44 }; 45 46 class SkLinearBitmapPipeline::BilerpProcessorInterface 47 : public SkLinearBitmapPipeline::PointProcessorInterface { 48 public: 49 // The x's and y's are setup in the following order: 50 // +--------+--------+ 51 // | | | 52 // | px00 | px10 | 53 // | 0 | 1 | 54 // +--------+--------+ 55 // | | | 56 // | px01 | px11 | 57 // | 2 | 3 | 58 // +--------+--------+ 59 // These pixels coordinates are arranged in the following order in xs and ys: 60 // px00 px10 px01 px11 61 virtual void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) = 0; 62 }; 63 64 class SkLinearBitmapPipeline::PixelPlacerInterface { 65 public: 66 virtual ~PixelPlacerInterface() { } 67 virtual void setDestination(SkPM4f* dst) = 0; 68 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; 69 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0; 70 }; 71 72 namespace { 73 74 struct X { 75 explicit X(SkScalar val) : fVal{val} { } 76 explicit X(SkPoint pt) : fVal{pt.fX} { } 77 explicit X(SkSize s) : fVal{s.fWidth} { } 78 explicit X(SkISize s) : fVal(s.fWidth) { } 79 operator float () const {return fVal;} 80 private: 81 float fVal; 82 }; 83 84 struct Y { 85 explicit Y(SkScalar val) : fVal{val} { } 86 explicit Y(SkPoint pt) : fVal{pt.fY} { } 87 explicit Y(SkSize s) : fVal{s.fHeight} { } 88 explicit Y(SkISize s) : fVal(s.fHeight) { } 89 operator float () const {return fVal;} 90 private: 91 float fVal; 92 }; 93 94 template <typename Stage> 95 void span_fallback(SkPoint start, SkScalar length, int count, Stage* stage) { 96 // If count == 1 use PointListFew instead. 97 SkASSERT(count > 1); 98 99 float dx = length / (count - 1); 100 Sk4f Xs = Sk4f(X(start)) + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * Sk4f{dx}; 101 Sk4f Ys{Y(start)}; 102 Sk4f fourDx = {4.0f * dx}; 103 104 while (count >= 4) { 105 stage->pointList4(Xs, Ys); 106 Xs = Xs + fourDx; 107 count -= 4; 108 } 109 if (count > 0) { 110 stage->pointListFew(count, Xs, Ys); 111 } 112 } 113 114 // PointProcessor uses a strategy to help complete the work of the different stages. The strategy 115 // must implement the following methods: 116 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. 117 // * maybeProcessSpan(start, length, count) - This represents a horizontal series of pixels 118 // to work over. 119 // start - is the starting pixel. This is in destination space before the matrix stage, and in 120 // source space after the matrix stage. 121 // length - is this distance between the first pixel center and the last pixel center. Like start, 122 // this is in destination space before the matrix stage, and in source space after. 123 // count - the number of pixels in source space to produce. 124 // next - a pointer to the next stage. 125 // maybeProcessSpan - returns false if it can not process the span and needs to fallback to 126 // point lists for processing. 127 template<typename Strategy, typename Next> 128 class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterface { 129 public: 130 template <typename... Args> 131 PointProcessor(Next* next, Args&&... args) 132 : fNext{next} 133 , fStrategy{std::forward<Args>(args)...}{ } 134 135 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { 136 fStrategy.processPoints(&xs, &ys); 137 fNext->pointListFew(n, xs, ys); 138 } 139 140 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { 141 fStrategy.processPoints(&xs, &ys); 142 fNext->pointList4(xs, ys); 143 } 144 145 void pointSpan(SkPoint start, SkScalar length, int count) override { 146 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { 147 span_fallback(start, length, count, this); 148 } 149 } 150 151 private: 152 Next* const fNext; 153 Strategy fStrategy; 154 }; 155 156 // See PointProcessor for responsibilities of Strategy. 157 template<typename Strategy, typename Next> 158 class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInterface { 159 public: 160 template <typename... Args> 161 BilerpProcessor(Next* next, Args&&... args) 162 : fNext{next} 163 , fStrategy{std::forward<Args>(args)...}{ } 164 165 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { 166 fStrategy.processPoints(&xs, &ys); 167 fNext->pointListFew(n, xs, ys); 168 } 169 170 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { 171 fStrategy.processPoints(&xs, &ys); 172 fNext->pointList4(xs, ys); 173 } 174 175 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { 176 fStrategy.processPoints(&xs, &ys); 177 fNext->bilerpList(xs, ys); 178 } 179 180 void pointSpan(SkPoint start, SkScalar length, int count) override { 181 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { 182 span_fallback(start, length, count, this); 183 } 184 } 185 186 private: 187 Next* const fNext; 188 Strategy fStrategy; 189 }; 190 191 class SkippedStage final : public SkLinearBitmapPipeline::BilerpProcessorInterface { 192 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { 193 SkFAIL("Skipped stage."); 194 } 195 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { 196 SkFAIL("Skipped stage."); 197 } 198 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { 199 SkFAIL("Skipped stage."); 200 } 201 void pointSpan(SkPoint start, SkScalar length, int count) override { 202 SkFAIL("Skipped stage."); 203 } 204 }; 205 206 class TranslateMatrixStrategy { 207 public: 208 TranslateMatrixStrategy(SkVector offset) 209 : fXOffset{X(offset)} 210 , fYOffset{Y(offset)} { } 211 212 void processPoints(Sk4f* xs, Sk4f* ys) { 213 *xs = *xs + fXOffset; 214 *ys = *ys + fYOffset; 215 } 216 217 template <typename Next> 218 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { 219 next->pointSpan(start + SkPoint{fXOffset[0], fYOffset[0]}, length, count); 220 return true; 221 } 222 223 private: 224 const Sk4f fXOffset, fYOffset; 225 }; 226 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 227 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; 228 229 class ScaleMatrixStrategy { 230 public: 231 ScaleMatrixStrategy(SkVector offset, SkVector scale) 232 : fXOffset{X(offset)}, fYOffset{Y(offset)} 233 , fXScale{X(scale)}, fYScale{Y(scale)} { } 234 void processPoints(Sk4f* xs, Sk4f* ys) { 235 *xs = *xs * fXScale + fXOffset; 236 *ys = *ys * fYScale + fYOffset; 237 } 238 239 template <typename Next> 240 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { 241 SkPoint newStart = 242 SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] + fYOffset[0]}; 243 SkScalar newLength = length * fXScale[0]; 244 next->pointSpan(newStart, newLength, count); 245 return true; 246 } 247 248 private: 249 const Sk4f fXOffset, fYOffset; 250 const Sk4f fXScale, fYScale; 251 }; 252 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 253 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; 254 255 class AffineMatrixStrategy { 256 public: 257 AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew) 258 : fXOffset{X(offset)}, fYOffset{Y(offset)} 259 , fXScale{X(scale)}, fYScale{Y(scale)} 260 , fXSkew{X(skew)}, fYSkew{Y(skew)} { } 261 void processPoints(Sk4f* xs, Sk4f* ys) { 262 Sk4f newXs = fXScale * *xs + fXSkew * *ys + fXOffset; 263 Sk4f newYs = fYSkew * *xs + fYScale * *ys + fYOffset; 264 265 *xs = newXs; 266 *ys = newYs; 267 } 268 269 template <typename Next> 270 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { 271 return false; 272 } 273 274 private: 275 const Sk4f fXOffset, fYOffset; 276 const Sk4f fXScale, fYScale; 277 const Sk4f fXSkew, fYSkew; 278 }; 279 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 280 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; 281 282 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( 283 SkLinearBitmapPipeline::PointProcessorInterface* next, 284 const SkMatrix& inverse, 285 SkLinearBitmapPipeline::MatrixStage* matrixProc) { 286 if (inverse.hasPerspective()) { 287 SkFAIL("Not implemented."); 288 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { 289 matrixProc->Initialize<AffineMatrix<>>( 290 next, 291 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, 292 SkVector{inverse.getScaleX(), inverse.getScaleY()}, 293 SkVector{inverse.getSkewX(), inverse.getSkewY()}); 294 } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) { 295 matrixProc->Initialize<ScaleMatrix<>>( 296 next, 297 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, 298 SkVector{inverse.getScaleX(), inverse.getScaleY()}); 299 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) { 300 matrixProc->Initialize<TranslateMatrix<>>( 301 next, 302 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); 303 } else { 304 matrixProc->Initialize<SkippedStage>(); 305 return next; 306 } 307 return matrixProc->get(); 308 } 309 310 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> 311 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterface { 312 public: 313 ExpandBilerp(Next* next) : fNext{next} { } 314 315 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { 316 SkASSERT(0 < n && n < 4); 317 // px00 px10 px01 px11 318 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, 319 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; 320 if (n >= 1) fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets); 321 if (n >= 2) fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets); 322 if (n >= 3) fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets); 323 } 324 325 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { 326 // px00 px10 px01 px11 327 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, 328 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; 329 fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets); 330 fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets); 331 fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets); 332 fNext->bilerpList(Sk4f{xs[3]} + kXOffsets, Sk4f{ys[3]} + kYOffsets); 333 } 334 335 void pointSpan(SkPoint start, SkScalar length, int count) override { 336 span_fallback(start, length, count, this); 337 } 338 339 private: 340 Next* const fNext; 341 }; 342 343 static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter( 344 SkLinearBitmapPipeline::BilerpProcessorInterface* next, 345 SkFilterQuality filterQuailty, 346 SkLinearBitmapPipeline::FilterStage* filterProc) { 347 if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) { 348 filterProc->Initialize<SkippedStage>(); 349 return next; 350 } else { 351 filterProc->Initialize<ExpandBilerp<>>(next); 352 return filterProc->get(); 353 } 354 } 355 356 class ClampStrategy { 357 public: 358 ClampStrategy(X max) 359 : fXMin{0.0f} 360 , fXMax{max - 1.0f} { } 361 ClampStrategy(Y max) 362 : fYMin{0.0f} 363 , fYMax{max - 1.0f} { } 364 ClampStrategy(SkSize max) 365 : fXMin{0.0f} 366 , fYMin{0.0f} 367 , fXMax{X(max) - 1.0f} 368 , fYMax{Y(max) - 1.0f} { } 369 370 void processPoints(Sk4f* xs, Sk4f* ys) { 371 *xs = Sk4f::Min(Sk4f::Max(*xs, fXMin), fXMax); 372 *ys = Sk4f::Min(Sk4f::Max(*ys, fYMin), fYMax); 373 } 374 375 template <typename Next> 376 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { 377 return false; 378 } 379 380 private: 381 const Sk4f fXMin{SK_FloatNegativeInfinity}; 382 const Sk4f fYMin{SK_FloatNegativeInfinity}; 383 const Sk4f fXMax{SK_FloatInfinity}; 384 const Sk4f fYMax{SK_FloatInfinity}; 385 }; 386 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> 387 using Clamp = BilerpProcessor<ClampStrategy, Next>; 388 389 class RepeatStrategy { 390 public: 391 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { } 392 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { } 393 RepeatStrategy(SkSize max) 394 : fXMax{X(max)} 395 , fXInvMax{1.0f / X(max)} 396 , fYMax{Y(max)} 397 , fYInvMax{1.0f / Y(max)} { } 398 399 void processPoints(Sk4f* xs, Sk4f* ys) { 400 Sk4f divX = (*xs * fXInvMax).floor(); 401 Sk4f divY = (*ys * fYInvMax).floor(); 402 Sk4f baseX = (divX * fXMax); 403 Sk4f baseY = (divY * fYMax); 404 *xs = *xs - baseX; 405 *ys = *ys - baseY; 406 } 407 408 template <typename Next> 409 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { 410 return false; 411 } 412 413 private: 414 const Sk4f fXMax{0.0f}; 415 const Sk4f fXInvMax{0.0f}; 416 const Sk4f fYMax{0.0f}; 417 const Sk4f fYInvMax{0.0f}; 418 }; 419 420 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> 421 using Repeat = BilerpProcessor<RepeatStrategy, Next>; 422 423 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( 424 SkLinearBitmapPipeline::BilerpProcessorInterface* next, 425 SkSize dimensions, 426 SkShader::TileMode xMode, 427 SkShader::TileMode yMode, 428 SkLinearBitmapPipeline::TileStage* tileProcXOrBoth, 429 SkLinearBitmapPipeline::TileStage* tileProcY) { 430 if (xMode == yMode) { 431 switch (xMode) { 432 case SkShader::kClamp_TileMode: 433 tileProcXOrBoth->Initialize<Clamp<>>(next, dimensions); 434 break; 435 case SkShader::kRepeat_TileMode: 436 tileProcXOrBoth->Initialize<Repeat<>>(next, dimensions); 437 break; 438 case SkShader::kMirror_TileMode: 439 SkFAIL("Not implemented."); 440 break; 441 } 442 tileProcY->Initialize<SkippedStage>(); 443 } else { 444 switch (yMode) { 445 case SkShader::kClamp_TileMode: 446 tileProcY->Initialize<Clamp<>>(next, Y(dimensions)); 447 break; 448 case SkShader::kRepeat_TileMode: 449 tileProcY->Initialize<Repeat<>>(next, Y(dimensions)); 450 break; 451 case SkShader::kMirror_TileMode: 452 SkFAIL("Not implemented."); 453 break; 454 } 455 switch (xMode) { 456 case SkShader::kClamp_TileMode: 457 tileProcXOrBoth->Initialize<Clamp<>>(tileProcY->get(), X(dimensions)); 458 break; 459 case SkShader::kRepeat_TileMode: 460 tileProcXOrBoth->Initialize<Repeat<>>(tileProcY->get(), X(dimensions)); 461 break; 462 case SkShader::kMirror_TileMode: 463 SkFAIL("Not implemented."); 464 break; 465 } 466 } 467 return tileProcXOrBoth->get(); 468 } 469 470 class sRGBFast { 471 public: 472 static Sk4f VECTORCALL sRGBToLinear(Sk4f pixel) { 473 Sk4f l = pixel * pixel; 474 return Sk4f{l[0], l[1], l[2], pixel[3]}; 475 } 476 }; 477 478 template <SkColorProfileType colorProfile> 479 class Passthrough8888 { 480 public: 481 Passthrough8888(int width, const uint32_t* src) 482 : fSrc{src}, fWidth{width}{ } 483 484 void VECTORCALL getFewPixels(int n, Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) { 485 Sk4i XIs = SkNx_cast<int, float>(xs); 486 Sk4i YIs = SkNx_cast<int, float>(ys); 487 Sk4i bufferLoc = YIs * fWidth + XIs; 488 switch (n) { 489 case 3: 490 *px2 = getPixel(fSrc, bufferLoc[2]); 491 case 2: 492 *px1 = getPixel(fSrc, bufferLoc[1]); 493 case 1: 494 *px0 = getPixel(fSrc, bufferLoc[0]); 495 default: 496 break; 497 } 498 } 499 500 void VECTORCALL get4Pixels(Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) { 501 Sk4i XIs = SkNx_cast<int, float>(xs); 502 Sk4i YIs = SkNx_cast<int, float>(ys); 503 Sk4i bufferLoc = YIs * fWidth + XIs; 504 *px0 = getPixel(fSrc, bufferLoc[0]); 505 *px1 = getPixel(fSrc, bufferLoc[1]); 506 *px2 = getPixel(fSrc, bufferLoc[2]); 507 *px3 = getPixel(fSrc, bufferLoc[3]); 508 } 509 510 const uint32_t* row(int y) { return fSrc + y * fWidth[0]; } 511 512 private: 513 Sk4f getPixel(const uint32_t* src, int index) { 514 Sk4b bytePixel = Sk4b::Load((uint8_t *)(&src[index])); 515 Sk4f pixel = SkNx_cast<float, uint8_t>(bytePixel); 516 pixel = pixel * Sk4f{1.0f/255.0f}; 517 if (colorProfile == kSRGB_SkColorProfileType) { 518 pixel = sRGBFast::sRGBToLinear(pixel); 519 } 520 return pixel; 521 } 522 const uint32_t* const fSrc; 523 const Sk4i fWidth; 524 }; 525 526 // Explaination of the math: 527 // 1 - x x 528 // +--------+--------+ 529 // | | | 530 // 1 - y | px00 | px10 | 531 // | | | 532 // +--------+--------+ 533 // | | | 534 // y | px01 | px11 | 535 // | | | 536 // +--------+--------+ 537 // 538 // 539 // Given a pixelxy each is multiplied by a different factor derived from the fractional part of x 540 // and y: 541 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy 542 // * px10 -> x(1 - y) = x - xy 543 // * px01 -> (1 - x)y = y - xy 544 // * px11 -> xy 545 // So x * y is calculated first and then used to calculate all the other factors. 546 static Sk4f VECTORCALL bilerp4(Sk4f xs, Sk4f ys, Sk4f px00, Sk4f px10, 547 Sk4f px01, Sk4f px11) { 548 // Calculate fractional xs and ys. 549 Sk4f fxs = xs - xs.floor(); 550 Sk4f fys = ys - ys.floor(); 551 Sk4f fxys{fxs * fys}; 552 Sk4f sum = px11 * fxys; 553 sum = sum + px01 * (fys - fxys); 554 sum = sum + px10 * (fxs - fxys); 555 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys); 556 return sum; 557 } 558 559 template <typename SourceStrategy> 560 class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface { 561 public: 562 template <typename... Args> 563 Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args) 564 : fNext{next} 565 , fStrategy{std::forward<Args>(args)...} { } 566 567 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { 568 SkASSERT(0 < n && n < 4); 569 Sk4f px0, px1, px2; 570 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); 571 if (n >= 1) fNext->placePixel(px0); 572 if (n >= 2) fNext->placePixel(px1); 573 if (n >= 3) fNext->placePixel(px2); 574 } 575 576 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { 577 Sk4f px0, px1, px2, px3; 578 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); 579 fNext->place4Pixels(px0, px1, px2, px3); 580 } 581 582 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { 583 Sk4f px00, px10, px01, px11; 584 fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11); 585 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11); 586 fNext->placePixel(pixel); 587 } 588 589 void pointSpan(SkPoint start, SkScalar length, int count) override { 590 span_fallback(start, length, count, this); 591 } 592 593 private: 594 SkLinearBitmapPipeline::PixelPlacerInterface* const fNext; 595 SourceStrategy fStrategy; 596 }; 597 598 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler( 599 SkLinearBitmapPipeline::PixelPlacerInterface* next, 600 const SkPixmap& srcPixmap, 601 SkLinearBitmapPipeline::SampleStage* sampleStage) { 602 const SkImageInfo& imageInfo = srcPixmap.info(); 603 switch (imageInfo.colorType()) { 604 case kRGBA_8888_SkColorType: 605 case kBGRA_8888_SkColorType: 606 if (kN32_SkColorType == imageInfo.colorType()) { 607 if (imageInfo.profileType() == kSRGB_SkColorProfileType) { 608 sampleStage->Initialize<Sampler<Passthrough8888<kSRGB_SkColorProfileType>>>( 609 next, static_cast<int>(srcPixmap.rowBytes() / 4), 610 srcPixmap.addr32()); 611 } else { 612 sampleStage->Initialize<Sampler<Passthrough8888<kLinear_SkColorProfileType>>>( 613 next, static_cast<int>(srcPixmap.rowBytes() / 4), 614 srcPixmap.addr32()); 615 } 616 } else { 617 SkFAIL("Not implemented. No 8888 Swizzle"); 618 } 619 break; 620 default: 621 SkFAIL("Not implemented. Unsupported src"); 622 break; 623 } 624 return sampleStage->get(); 625 } 626 627 template <SkAlphaType alphaType> 628 class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface { 629 public: 630 void VECTORCALL placePixel(Sk4f pixel) override { 631 PlacePixel(fDst, pixel, 0); 632 fDst += 1; 633 } 634 635 void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override { 636 SkPM4f* dst = fDst; 637 PlacePixel(dst, p0, 0); 638 PlacePixel(dst, p1, 1); 639 PlacePixel(dst, p2, 2); 640 PlacePixel(dst, p3, 3); 641 fDst += 4; 642 } 643 644 void setDestination(SkPM4f* dst) override { 645 fDst = dst; 646 } 647 648 private: 649 static void VECTORCALL PlacePixel(SkPM4f* dst, Sk4f pixel, int index) { 650 Sk4f newPixel = pixel; 651 if (alphaType == kUnpremul_SkAlphaType) { 652 newPixel = Premultiply(pixel); 653 } 654 newPixel.store(dst + index); 655 } 656 static Sk4f VECTORCALL Premultiply(Sk4f pixel) { 657 float alpha = pixel[3]; 658 return pixel * Sk4f{alpha, alpha, alpha, 1.0f}; 659 } 660 661 SkPM4f* fDst; 662 }; 663 664 static SkLinearBitmapPipeline::PixelPlacerInterface* choose_pixel_placer( 665 SkAlphaType alphaType, 666 SkLinearBitmapPipeline::PixelStage* placerStage) { 667 if (alphaType == kUnpremul_SkAlphaType) { 668 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>(); 669 } else { 670 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType 671 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>(); 672 } 673 return placerStage->get(); 674 } 675 } // namespace 676 677 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {} 678 679 SkLinearBitmapPipeline::SkLinearBitmapPipeline( 680 const SkMatrix& inverse, 681 SkFilterQuality filterQuality, 682 SkShader::TileMode xTile, SkShader::TileMode yTile, 683 const SkPixmap& srcPixmap) { 684 SkSize size = SkSize::Make(srcPixmap.width(), srcPixmap.height()); 685 const SkImageInfo& srcImageInfo = srcPixmap.info(); 686 687 // As the stages are built, the chooser function may skip a stage. For example, with the 688 // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage. 689 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelStage); 690 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSampleStage); 691 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileXOrBothStage, 692 &fTileYStage); 693 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage); 694 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); 695 } 696 697 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { 698 SkASSERT(count > 0); 699 fPixelStage->setDestination(dst); 700 // Adjust points by 0.5, 0.5 to sample from the center of the pixels. 701 if (count == 1) { 702 fFirstStage->pointListFew(1, Sk4f{x + 0.5f}, Sk4f{y + 0.5f}); 703 } else { 704 // The count and length arguments start out in a precise relation in order to keep the 705 // math correct through the different stages. Count is the number of pixel to produce. 706 // Since the code samples at pixel centers, length is the distance from the center of the 707 // first pixel to the center of the last pixel. This implies that length is count-1. 708 fFirstStage->pointSpan(SkPoint{x + 0.5f, y + 0.5f}, count - 1, count); 709 } 710 } 711