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 10 #include <algorithm> 11 #include <cmath> 12 #include <limits> 13 #include <tuple> 14 15 #include "SkArenaAlloc.h" 16 #include "SkLinearBitmapPipeline_core.h" 17 #include "SkLinearBitmapPipeline_matrix.h" 18 #include "SkLinearBitmapPipeline_tile.h" 19 #include "SkLinearBitmapPipeline_sample.h" 20 #include "SkNx.h" 21 #include "SkOpts.h" 22 #include "SkPM4f.h" 23 24 namespace { 25 26 //////////////////////////////////////////////////////////////////////////////////////////////////// 27 // Matrix Stage 28 // PointProcessor uses a strategy to help complete the work of the different stages. The strategy 29 // must implement the following methods: 30 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. 31 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixels 32 // to work over. 33 // span - encapsulation of span. 34 // next - a pointer to the next stage. 35 // maybeProcessSpan - returns false if it can not process the span and needs to fallback to 36 // point lists for processing. 37 template<typename Strategy, typename Next> 38 class MatrixStage final : public SkLinearBitmapPipeline::PointProcessorInterface { 39 public: 40 template <typename... Args> 41 MatrixStage(Next* next, Args&&... args) 42 : fNext{next} 43 , fStrategy{std::forward<Args>(args)...}{ } 44 45 MatrixStage(Next* next, MatrixStage* stage) 46 : fNext{next} 47 , fStrategy{stage->fStrategy} { } 48 49 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { 50 fStrategy.processPoints(&xs, &ys); 51 fNext->pointListFew(n, xs, ys); 52 } 53 54 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { 55 fStrategy.processPoints(&xs, &ys); 56 fNext->pointList4(xs, ys); 57 } 58 59 // The span you pass must not be empty. 60 void pointSpan(Span span) override { 61 SkASSERT(!span.isEmpty()); 62 if (!fStrategy.maybeProcessSpan(span, fNext)) { 63 span_fallback(span, this); 64 } 65 } 66 67 private: 68 Next* const fNext; 69 Strategy fStrategy; 70 }; 71 72 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 73 using TranslateMatrix = MatrixStage<TranslateMatrixStrategy, Next>; 74 75 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 76 using ScaleMatrix = MatrixStage<ScaleMatrixStrategy, Next>; 77 78 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 79 using AffineMatrix = MatrixStage<AffineMatrixStrategy, Next>; 80 81 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 82 using PerspectiveMatrix = MatrixStage<PerspectiveMatrixStrategy, Next>; 83 84 85 //////////////////////////////////////////////////////////////////////////////////////////////////// 86 // Tile Stage 87 88 template<typename XStrategy, typename YStrategy, typename Next> 89 class CombinedTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface { 90 public: 91 CombinedTileStage(Next* next, SkISize dimensions) 92 : fNext{next} 93 , fXStrategy{dimensions.width()} 94 , fYStrategy{dimensions.height()}{ } 95 96 CombinedTileStage(Next* next, CombinedTileStage* stage) 97 : fNext{next} 98 , fXStrategy{stage->fXStrategy} 99 , fYStrategy{stage->fYStrategy} { } 100 101 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { 102 fXStrategy.tileXPoints(&xs); 103 fYStrategy.tileYPoints(&ys); 104 fNext->pointListFew(n, xs, ys); 105 } 106 107 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { 108 fXStrategy.tileXPoints(&xs); 109 fYStrategy.tileYPoints(&ys); 110 fNext->pointList4(xs, ys); 111 } 112 113 // The span you pass must not be empty. 114 void pointSpan(Span span) override { 115 SkASSERT(!span.isEmpty()); 116 SkPoint start; SkScalar length; int count; 117 std::tie(start, length, count) = span; 118 119 if (span.count() == 1) { 120 // DANGER: 121 // The explicit casts from float to Sk4f are not usually necessary, but are here to 122 // work around an MSVC 2015u2 c++ code generation bug. This is tracked using skia bug 123 // 5566. 124 this->pointListFew(1, Sk4f{span.startX()}, Sk4f{span.startY()}); 125 return; 126 } 127 128 SkScalar x = X(start); 129 SkScalar y = fYStrategy.tileY(Y(start)); 130 Span yAdjustedSpan{{x, y}, length, count}; 131 132 if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) { 133 span_fallback(span, this); 134 } 135 } 136 137 private: 138 Next* const fNext; 139 XStrategy fXStrategy; 140 YStrategy fYStrategy; 141 }; 142 143 //////////////////////////////////////////////////////////////////////////////////////////////////// 144 // Specialized Samplers 145 146 // RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination 147 // are the same format and do not need in transformations in pixel space. Therefore, there is no 148 // need to convert them to HiFi pixel format. 149 class RGBA8888UnitRepeatSrc final : public SkLinearBitmapPipeline::SampleProcessorInterface, 150 public SkLinearBitmapPipeline::DestinationInterface { 151 public: 152 RGBA8888UnitRepeatSrc(const uint32_t* src, int32_t width) 153 : fSrc{src}, fWidth{width} { } 154 155 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { 156 SkASSERT(fDest + n <= fEnd); 157 // At this point xs and ys should be >= 0, so trunc is the same as floor. 158 Sk4i iXs = SkNx_cast<int>(xs); 159 Sk4i iYs = SkNx_cast<int>(ys); 160 161 if (n >= 1) *fDest++ = *this->pixelAddress(iXs[0], iYs[0]); 162 if (n >= 2) *fDest++ = *this->pixelAddress(iXs[1], iYs[1]); 163 if (n >= 3) *fDest++ = *this->pixelAddress(iXs[2], iYs[2]); 164 } 165 166 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { 167 SkASSERT(fDest + 4 <= fEnd); 168 Sk4i iXs = SkNx_cast<int>(xs); 169 Sk4i iYs = SkNx_cast<int>(ys); 170 *fDest++ = *this->pixelAddress(iXs[0], iYs[0]); 171 *fDest++ = *this->pixelAddress(iXs[1], iYs[1]); 172 *fDest++ = *this->pixelAddress(iXs[2], iYs[2]); 173 *fDest++ = *this->pixelAddress(iXs[3], iYs[3]); 174 } 175 176 void pointSpan(Span span) override { 177 SkASSERT(fDest + span.count() <= fEnd); 178 if (span.length() != 0.0f) { 179 int32_t x = SkScalarTruncToInt(span.startX()); 180 int32_t y = SkScalarTruncToInt(span.startY()); 181 const uint32_t* src = this->pixelAddress(x, y); 182 memmove(fDest, src, span.count() * sizeof(uint32_t)); 183 fDest += span.count(); 184 } 185 } 186 187 void repeatSpan(Span span, int32_t repeatCount) override { 188 SkASSERT(fDest + span.count() * repeatCount <= fEnd); 189 190 int32_t x = SkScalarTruncToInt(span.startX()); 191 int32_t y = SkScalarTruncToInt(span.startY()); 192 const uint32_t* src = this->pixelAddress(x, y); 193 uint32_t* dest = fDest; 194 while (repeatCount --> 0) { 195 memmove(dest, src, span.count() * sizeof(uint32_t)); 196 dest += span.count(); 197 } 198 fDest = dest; 199 } 200 201 void setDestination(void* dst, int count) override { 202 fDest = static_cast<uint32_t*>(dst); 203 fEnd = fDest + count; 204 } 205 206 private: 207 const uint32_t* pixelAddress(int32_t x, int32_t y) { 208 return &fSrc[fWidth * y + x]; 209 } 210 const uint32_t* const fSrc; 211 const int32_t fWidth; 212 uint32_t* fDest; 213 uint32_t* fEnd; 214 }; 215 216 // RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination 217 // are the same format and do not need in transformations in pixel space. Therefore, there is no 218 // need to convert them to HiFi pixel format. 219 class RGBA8888UnitRepeatSrcOver final : public SkLinearBitmapPipeline::SampleProcessorInterface, 220 public SkLinearBitmapPipeline::DestinationInterface { 221 public: 222 RGBA8888UnitRepeatSrcOver(const uint32_t* src, int32_t width) 223 : fSrc{src}, fWidth{width} { } 224 225 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { 226 SkASSERT(fDest + n <= fEnd); 227 // At this point xs and ys should be >= 0, so trunc is the same as floor. 228 Sk4i iXs = SkNx_cast<int>(xs); 229 Sk4i iYs = SkNx_cast<int>(ys); 230 231 if (n >= 1) blendPixelAt(iXs[0], iYs[0]); 232 if (n >= 2) blendPixelAt(iXs[1], iYs[1]); 233 if (n >= 3) blendPixelAt(iXs[2], iYs[2]); 234 } 235 236 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { 237 SkASSERT(fDest + 4 <= fEnd); 238 Sk4i iXs = SkNx_cast<int>(xs); 239 Sk4i iYs = SkNx_cast<int>(ys); 240 blendPixelAt(iXs[0], iYs[0]); 241 blendPixelAt(iXs[1], iYs[1]); 242 blendPixelAt(iXs[2], iYs[2]); 243 blendPixelAt(iXs[3], iYs[3]); 244 } 245 246 void pointSpan(Span span) override { 247 if (span.length() != 0.0f) { 248 this->repeatSpan(span, 1); 249 } 250 } 251 252 void repeatSpan(Span span, int32_t repeatCount) override { 253 SkASSERT(fDest + span.count() * repeatCount <= fEnd); 254 SkASSERT(span.count() > 0); 255 SkASSERT(repeatCount > 0); 256 257 int32_t x = (int32_t)span.startX(); 258 int32_t y = (int32_t)span.startY(); 259 const uint32_t* beginSpan = this->pixelAddress(x, y); 260 261 SkOpts::srcover_srgb_srgb(fDest, beginSpan, span.count() * repeatCount, span.count()); 262 263 fDest += span.count() * repeatCount; 264 265 SkASSERT(fDest <= fEnd); 266 } 267 268 void setDestination(void* dst, int count) override { 269 SkASSERT(count > 0); 270 fDest = static_cast<uint32_t*>(dst); 271 fEnd = fDest + count; 272 } 273 274 private: 275 const uint32_t* pixelAddress(int32_t x, int32_t y) { 276 return &fSrc[fWidth * y + x]; 277 } 278 279 void blendPixelAt(int32_t x, int32_t y) { 280 const uint32_t* src = this->pixelAddress(x, y); 281 SkOpts::srcover_srgb_srgb(fDest, src, 1, 1); 282 fDest += 1; 283 } 284 285 const uint32_t* const fSrc; 286 const int32_t fWidth; 287 uint32_t* fDest; 288 uint32_t* fEnd; 289 }; 290 291 using Blender = SkLinearBitmapPipeline::BlendProcessorInterface; 292 293 //////////////////////////////////////////////////////////////////////////////////////////////////// 294 // Pixel Blender Stage 295 template <SkAlphaType alphaType> 296 class SrcFPPixel final : public Blender { 297 public: 298 SrcFPPixel(float postAlpha) : fPostAlpha{postAlpha} { } 299 SrcFPPixel(const SrcFPPixel& Blender) : fPostAlpha(Blender.fPostAlpha) {} 300 void SK_VECTORCALL blendPixel(Sk4f pixel) override { 301 SkASSERT(fDst + 1 <= fEnd ); 302 this->srcPixel(fDst, pixel, 0); 303 fDst += 1; 304 } 305 306 void SK_VECTORCALL blend4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override { 307 SkASSERT(fDst + 4 <= fEnd); 308 SkPM4f* dst = fDst; 309 this->srcPixel(dst, p0, 0); 310 this->srcPixel(dst, p1, 1); 311 this->srcPixel(dst, p2, 2); 312 this->srcPixel(dst, p3, 3); 313 fDst += 4; 314 } 315 316 void setDestination(void* dst, int count) override { 317 fDst = static_cast<SkPM4f*>(dst); 318 fEnd = fDst + count; 319 } 320 321 private: 322 void SK_VECTORCALL srcPixel(SkPM4f* dst, Sk4f pixel, int index) { 323 check_pixel(pixel); 324 325 Sk4f newPixel = pixel; 326 if (alphaType == kUnpremul_SkAlphaType) { 327 newPixel = Premultiply(pixel); 328 } 329 newPixel = newPixel * fPostAlpha; 330 newPixel.store(dst + index); 331 } 332 static Sk4f SK_VECTORCALL Premultiply(Sk4f pixel) { 333 float alpha = pixel[3]; 334 return pixel * Sk4f{alpha, alpha, alpha, 1.0f}; 335 } 336 337 SkPM4f* fDst; 338 SkPM4f* fEnd; 339 float fPostAlpha; 340 }; 341 342 } // namespace 343 344 //////////////////////////////////////////////////////////////////////////////////////////////////// 345 // SkLinearBitmapPipeline 346 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {} 347 348 SkLinearBitmapPipeline::SkLinearBitmapPipeline( 349 const SkMatrix& inverse, 350 SkFilterQuality filterQuality, 351 SkShader::TileMode xTile, SkShader::TileMode yTile, 352 SkColor paintColor, 353 const SkPixmap& srcPixmap, 354 SkArenaAlloc* allocator) 355 { 356 SkISize dimensions = srcPixmap.info().dimensions(); 357 const SkImageInfo& srcImageInfo = srcPixmap.info(); 358 359 SkMatrix adjustedInverse = inverse; 360 if (filterQuality == kNone_SkFilterQuality) { 361 if (inverse.getScaleX() >= 0.0f) { 362 adjustedInverse.setTranslateX( 363 nextafterf(inverse.getTranslateX(), std::floor(inverse.getTranslateX()))); 364 } 365 if (inverse.getScaleY() >= 0.0f) { 366 adjustedInverse.setTranslateY( 367 nextafterf(inverse.getTranslateY(), std::floor(inverse.getTranslateY()))); 368 } 369 } 370 371 SkScalar dx = adjustedInverse.getScaleX(); 372 373 // If it is an index 8 color type, the sampler converts to unpremul for better fidelity. 374 SkAlphaType alphaType = srcImageInfo.alphaType(); 375 if (srcPixmap.colorType() == kIndex_8_SkColorType) { 376 alphaType = kUnpremul_SkAlphaType; 377 } 378 379 float postAlpha = SkColorGetA(paintColor) * (1.0f / 255.0f); 380 // As the stages are built, the chooser function may skip a stage. For example, with the 381 // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage. 382 auto blenderStage = this->chooseBlenderForShading(alphaType, postAlpha, allocator); 383 auto samplerStage = this->chooseSampler( 384 blenderStage, filterQuality, xTile, yTile, srcPixmap, paintColor, allocator); 385 auto tilerStage = this->chooseTiler( 386 samplerStage, dimensions, xTile, yTile, filterQuality, dx, allocator); 387 fFirstStage = this->chooseMatrix(tilerStage, adjustedInverse, allocator); 388 fLastStage = blenderStage; 389 } 390 391 SkLinearBitmapPipeline::SkLinearBitmapPipeline( 392 const SkLinearBitmapPipeline& pipeline, 393 const SkPixmap& srcPixmap, 394 SkBlendMode mode, 395 const SkImageInfo& dstInfo, 396 SkArenaAlloc* allocator) 397 { 398 SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver); 399 SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType() 400 && srcPixmap.info().colorType() == kRGBA_8888_SkColorType); 401 402 SampleProcessorInterface* sampleStage; 403 if (mode == SkBlendMode::kSrc) { 404 auto sampler = allocator->make<RGBA8888UnitRepeatSrc>( 405 srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4); 406 sampleStage = sampler; 407 fLastStage = sampler; 408 } else { 409 auto sampler = allocator->make<RGBA8888UnitRepeatSrcOver>( 410 srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4); 411 sampleStage = sampler; 412 fLastStage = sampler; 413 } 414 415 auto tilerStage = pipeline.fTileStageCloner(sampleStage, allocator); 416 auto matrixStage = pipeline.fMatrixStageCloner(tilerStage, allocator); 417 fFirstStage = matrixStage; 418 } 419 420 SkLinearBitmapPipeline* SkLinearBitmapPipeline::ClonePipelineForBlitting( 421 const SkLinearBitmapPipeline& pipeline, 422 SkMatrix::TypeMask matrixMask, 423 SkFilterQuality filterQuality, 424 const SkPixmap& srcPixmap, 425 float finalAlpha, 426 SkBlendMode blendMode, 427 const SkImageInfo& dstInfo, 428 SkArenaAlloc* allocator) 429 { 430 if (blendMode == SkBlendMode::kSrcOver && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) { 431 blendMode = SkBlendMode::kSrc; 432 } 433 434 if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return nullptr; } 435 if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return nullptr; } 436 if (finalAlpha != 1.0f) { return nullptr; } 437 if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType 438 || dstInfo.colorType() != kRGBA_8888_SkColorType) { return nullptr; } 439 440 if (!srcPixmap.info().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) { 441 return nullptr; 442 } 443 444 if (blendMode != SkBlendMode::kSrc && blendMode != SkBlendMode::kSrcOver) { 445 return nullptr; 446 } 447 448 return allocator->make<SkLinearBitmapPipeline>( 449 pipeline, srcPixmap, blendMode, dstInfo, allocator); 450 } 451 452 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { 453 SkASSERT(count > 0); 454 this->blitSpan(x, y, dst, count); 455 } 456 457 void SkLinearBitmapPipeline::blitSpan(int x, int y, void* dst, int count) { 458 SkASSERT(count > 0); 459 fLastStage->setDestination(dst, count); 460 461 // The count and length arguments start out in a precise relation in order to keep the 462 // math correct through the different stages. Count is the number of pixel to produce. 463 // Since the code samples at pixel centers, length is the distance from the center of the 464 // first pixel to the center of the last pixel. This implies that length is count-1. 465 fFirstStage->pointSpan(Span{{x + 0.5f, y + 0.5f}, count - 1.0f, count}); 466 } 467 468 SkLinearBitmapPipeline::PointProcessorInterface* 469 SkLinearBitmapPipeline::chooseMatrix( 470 PointProcessorInterface* next, 471 const SkMatrix& inverse, 472 SkArenaAlloc* allocator) 473 { 474 if (inverse.hasPerspective()) { 475 auto matrixStage = allocator->make<PerspectiveMatrix<>>( 476 next, 477 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, 478 SkVector{inverse.getScaleX(), inverse.getScaleY()}, 479 SkVector{inverse.getSkewX(), inverse.getSkewY()}, 480 SkVector{inverse.getPerspX(), inverse.getPerspY()}, 481 inverse.get(SkMatrix::kMPersp2)); 482 fMatrixStageCloner = 483 [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) { 484 return memory->make<PerspectiveMatrix<>>(cloneNext, matrixStage); 485 }; 486 return matrixStage; 487 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { 488 auto matrixStage = allocator->make<AffineMatrix<>>( 489 next, 490 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, 491 SkVector{inverse.getScaleX(), inverse.getScaleY()}, 492 SkVector{inverse.getSkewX(), inverse.getSkewY()}); 493 fMatrixStageCloner = 494 [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) { 495 return memory->make<AffineMatrix<>>(cloneNext, matrixStage); 496 }; 497 return matrixStage; 498 } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) { 499 auto matrixStage = allocator->make<ScaleMatrix<>>( 500 next, 501 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, 502 SkVector{inverse.getScaleX(), inverse.getScaleY()}); 503 fMatrixStageCloner = 504 [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) { 505 return memory->make<ScaleMatrix<>>(cloneNext, matrixStage); 506 }; 507 return matrixStage; 508 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) { 509 auto matrixStage = allocator->make<TranslateMatrix<>>( 510 next, 511 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); 512 fMatrixStageCloner = 513 [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) { 514 return memory->make<TranslateMatrix<>>(cloneNext, matrixStage); 515 }; 516 return matrixStage; 517 } else { 518 fMatrixStageCloner = [](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) { 519 return cloneNext; 520 }; 521 return next; 522 } 523 } 524 525 template <typename Tiler> 526 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::createTiler( 527 SampleProcessorInterface* next, 528 SkISize dimensions, 529 SkArenaAlloc* allocator) 530 { 531 auto tilerStage = allocator->make<Tiler>(next, dimensions); 532 fTileStageCloner = 533 [tilerStage](SampleProcessorInterface* cloneNext, 534 SkArenaAlloc* memory) -> PointProcessorInterface* { 535 return memory->make<Tiler>(cloneNext, tilerStage); 536 }; 537 return tilerStage; 538 } 539 540 template <typename XStrategy> 541 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTilerYMode( 542 SampleProcessorInterface* next, 543 SkShader::TileMode yMode, 544 SkISize dimensions, 545 SkArenaAlloc* allocator) 546 { 547 switch (yMode) { 548 case SkShader::kClamp_TileMode: { 549 using Tiler = CombinedTileStage<XStrategy, YClampStrategy, SampleProcessorInterface>; 550 return this->createTiler<Tiler>(next, dimensions, allocator); 551 } 552 case SkShader::kRepeat_TileMode: { 553 using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, SampleProcessorInterface>; 554 return this->createTiler<Tiler>(next, dimensions, allocator); 555 } 556 case SkShader::kMirror_TileMode: { 557 using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, SampleProcessorInterface>; 558 return this->createTiler<Tiler>(next, dimensions, allocator); 559 } 560 } 561 562 // Should never get here. 563 SkFAIL("Not all Y tile cases covered."); 564 return nullptr; 565 } 566 567 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTiler( 568 SampleProcessorInterface* next, 569 SkISize dimensions, 570 SkShader::TileMode xMode, 571 SkShader::TileMode yMode, 572 SkFilterQuality filterQuality, 573 SkScalar dx, 574 SkArenaAlloc* allocator) 575 { 576 switch (xMode) { 577 case SkShader::kClamp_TileMode: 578 return this->chooseTilerYMode<XClampStrategy>(next, yMode, dimensions, allocator); 579 case SkShader::kRepeat_TileMode: 580 if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) { 581 return this->chooseTilerYMode<XRepeatUnitScaleStrategy>( 582 next, yMode, dimensions, allocator); 583 } else { 584 return this->chooseTilerYMode<XRepeatStrategy>( 585 next, yMode, dimensions, allocator); 586 } 587 case SkShader::kMirror_TileMode: 588 return this->chooseTilerYMode<XMirrorStrategy>(next, yMode, dimensions, allocator); 589 } 590 591 // Should never get here. 592 SkFAIL("Not all X tile cases covered."); 593 return nullptr; 594 } 595 596 template <SkColorType colorType> 597 SkLinearBitmapPipeline::PixelAccessorInterface* 598 SkLinearBitmapPipeline::chooseSpecificAccessor( 599 const SkPixmap& srcPixmap, 600 SkArenaAlloc* allocator) 601 { 602 if (srcPixmap.info().gammaCloseToSRGB()) { 603 using Accessor = PixelAccessor<colorType, kSRGB_SkGammaType>; 604 return allocator->make<Accessor>(srcPixmap); 605 } else { 606 using Accessor = PixelAccessor<colorType, kLinear_SkGammaType>; 607 return allocator->make<Accessor>(srcPixmap); 608 } 609 } 610 611 SkLinearBitmapPipeline::PixelAccessorInterface* SkLinearBitmapPipeline::choosePixelAccessor( 612 const SkPixmap& srcPixmap, 613 const SkColor A8TintColor, 614 SkArenaAlloc* allocator) 615 { 616 const SkImageInfo& imageInfo = srcPixmap.info(); 617 618 switch (imageInfo.colorType()) { 619 case kAlpha_8_SkColorType: { 620 using Accessor = PixelAccessor<kAlpha_8_SkColorType, kLinear_SkGammaType>; 621 return allocator->make<Accessor>(srcPixmap, A8TintColor); 622 } 623 case kARGB_4444_SkColorType: 624 return this->chooseSpecificAccessor<kARGB_4444_SkColorType>(srcPixmap, allocator); 625 case kRGB_565_SkColorType: 626 return this->chooseSpecificAccessor<kRGB_565_SkColorType>(srcPixmap, allocator); 627 case kRGBA_8888_SkColorType: 628 return this->chooseSpecificAccessor<kRGBA_8888_SkColorType>(srcPixmap, allocator); 629 case kBGRA_8888_SkColorType: 630 return this->chooseSpecificAccessor<kBGRA_8888_SkColorType>(srcPixmap, allocator); 631 case kIndex_8_SkColorType: 632 return this->chooseSpecificAccessor<kIndex_8_SkColorType>(srcPixmap, allocator); 633 case kGray_8_SkColorType: 634 return this->chooseSpecificAccessor<kGray_8_SkColorType>(srcPixmap, allocator); 635 case kRGBA_F16_SkColorType: { 636 using Accessor = PixelAccessor<kRGBA_F16_SkColorType, kLinear_SkGammaType>; 637 return allocator->make<Accessor>(srcPixmap); 638 } 639 default: 640 // Should never get here. 641 SkFAIL("Pixel source not supported."); 642 return nullptr; 643 } 644 } 645 646 SkLinearBitmapPipeline::SampleProcessorInterface* SkLinearBitmapPipeline::chooseSampler( 647 Blender* next, 648 SkFilterQuality filterQuality, 649 SkShader::TileMode xTile, SkShader::TileMode yTile, 650 const SkPixmap& srcPixmap, 651 const SkColor A8TintColor, 652 SkArenaAlloc* allocator) 653 { 654 const SkImageInfo& imageInfo = srcPixmap.info(); 655 SkISize dimensions = imageInfo.dimensions(); 656 657 // Special case samplers with fully expanded templates 658 if (imageInfo.gammaCloseToSRGB()) { 659 if (filterQuality == kNone_SkFilterQuality) { 660 switch (imageInfo.colorType()) { 661 case kN32_SkColorType: { 662 using Sampler = 663 NearestNeighborSampler< 664 PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>; 665 return allocator->make<Sampler>(next, srcPixmap); 666 } 667 case kIndex_8_SkColorType: { 668 using Sampler = 669 NearestNeighborSampler< 670 PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>; 671 return allocator->make<Sampler>(next, srcPixmap); 672 } 673 default: 674 break; 675 } 676 } else { 677 switch (imageInfo.colorType()) { 678 case kN32_SkColorType: { 679 using Sampler = 680 BilerpSampler< 681 PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>; 682 return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap); 683 } 684 case kIndex_8_SkColorType: { 685 using Sampler = 686 BilerpSampler< 687 PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>; 688 return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap); 689 } 690 default: 691 break; 692 } 693 } 694 } 695 696 auto pixelAccessor = this->choosePixelAccessor(srcPixmap, A8TintColor, allocator); 697 // General cases. 698 if (filterQuality == kNone_SkFilterQuality) { 699 using Sampler = NearestNeighborSampler<PixelAccessorShim, Blender>; 700 return allocator->make<Sampler>(next, pixelAccessor); 701 } else { 702 using Sampler = BilerpSampler<PixelAccessorShim, Blender>; 703 return allocator->make<Sampler>(next, dimensions, xTile, yTile, pixelAccessor); 704 } 705 } 706 707 Blender* SkLinearBitmapPipeline::chooseBlenderForShading( 708 SkAlphaType alphaType, 709 float postAlpha, 710 SkArenaAlloc* allocator) 711 { 712 if (alphaType == kUnpremul_SkAlphaType) { 713 return allocator->make<SrcFPPixel<kUnpremul_SkAlphaType>>(postAlpha); 714 } else { 715 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType 716 return allocator->make<SrcFPPixel<kPremul_SkAlphaType>>(postAlpha); 717 } 718 } 719