OLD | NEW |
(Empty) | |
| 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 struct X { |
| 11 explicit X(SkScalar val) : fVal{val} { } |
| 12 explicit X(SkPoint pt) : fVal{pt.fX} { } |
| 13 explicit X(SkSize s) : fVal{s.fWidth} { } |
| 14 explicit X(SkISize s) : fVal(s.fWidth) { } |
| 15 operator float () const {return fVal;} |
| 16 private: |
| 17 float fVal; |
| 18 }; |
| 19 |
| 20 struct Y { |
| 21 explicit Y(SkScalar val) : fVal{val} { } |
| 22 explicit Y(SkPoint pt) : fVal{pt.fY} { } |
| 23 explicit Y(SkSize s) : fVal{s.fHeight} { } |
| 24 explicit Y(SkISize s) : fVal(s.fHeight) { } |
| 25 |
| 26 operator float () const {return fVal;} |
| 27 private: |
| 28 float fVal; |
| 29 }; |
| 30 |
| 31 template<typename Strategy, typename Next> |
| 32 class PointProcessor : public PointProcessorInterface { |
| 33 public: |
| 34 template <typename... Args> |
| 35 PointProcessor(Next* next, Args&&... args) |
| 36 : fNext{next} |
| 37 , fStrategy{std::forward<Args>(args)...}{ } |
| 38 |
| 39 void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override { |
| 40 Sk4f newXs = xs; |
| 41 Sk4f newYs = ys; |
| 42 fStrategy.processPoints(&newXs, &newYs); |
| 43 fNext->pointListFew(n, newXs, newYs); |
| 44 } |
| 45 |
| 46 void pointList4(Sk4fArg xs, Sk4fArg ys) override { |
| 47 Sk4f newXs = xs; |
| 48 Sk4f newYs = ys; |
| 49 fStrategy.processPoints(&newXs, &newYs); |
| 50 fNext->pointList4(newXs, newYs); |
| 51 } |
| 52 |
| 53 private: |
| 54 Next* const fNext; |
| 55 Strategy fStrategy; |
| 56 }; |
| 57 |
| 58 class SkippedStage final : public PointProcessorInterface { |
| 59 void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override { |
| 60 SkFAIL("Abort tiler."); |
| 61 } |
| 62 void pointList4(Sk4fArg Xs, Sk4fArg Ys) override { |
| 63 SkFAIL("Abort point processor."); |
| 64 } |
| 65 }; |
| 66 |
| 67 class TranslateMatrixStrategy { |
| 68 public: |
| 69 TranslateMatrixStrategy(SkVector offset) |
| 70 : fXOffset{X(offset)} |
| 71 , fYOffset{Y(offset)} { } |
| 72 void processPoints(Sk4f* xs, Sk4f* ys) { |
| 73 *xs = *xs + fXOffset; |
| 74 *ys = *ys + fYOffset; |
| 75 } |
| 76 |
| 77 private: |
| 78 const Sk4f fXOffset, fYOffset; |
| 79 }; |
| 80 template <typename Next = PointProcessorInterface> |
| 81 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; |
| 82 |
| 83 class ScaleMatrixStrategy { |
| 84 public: |
| 85 ScaleMatrixStrategy(SkVector offset, SkVector scale) |
| 86 : fXOffset{X(offset)}, fYOffset{Y(offset)} |
| 87 , fXScale{X(scale)}, fYScale{Y(scale)} { } |
| 88 void processPoints(Sk4f* xs, Sk4f* ys) { |
| 89 *xs = *xs * fXScale + fXOffset; |
| 90 *ys = *ys * fYScale + fYOffset; |
| 91 } |
| 92 |
| 93 private: |
| 94 const Sk4f fXOffset, fYOffset; |
| 95 const Sk4f fXScale, fYScale; |
| 96 }; |
| 97 template <typename Next = PointProcessorInterface> |
| 98 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; |
| 99 |
| 100 class AffineMatrixStrategy { |
| 101 public: |
| 102 AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew) |
| 103 : fXOffset{X(offset)}, fYOffset{Y(offset)} |
| 104 , fXScale{X(scale)}, fYScale{Y(scale)} |
| 105 , fXSkew{X(skew)}, fYSkew{Y(skew)} { } |
| 106 void processPoints(Sk4f* xs, Sk4f* ys) { |
| 107 Sk4f newXs = fXScale * *xs + fXSkew * *ys + fXOffset; |
| 108 Sk4f newYs = fYSkew * *xs + fYScale * *ys + fYOffset; |
| 109 |
| 110 *xs = newXs; |
| 111 *ys = newYs; |
| 112 } |
| 113 |
| 114 private: |
| 115 const Sk4f fXOffset, fYOffset; |
| 116 const Sk4f fXScale, fYScale; |
| 117 const Sk4f fXSkew, fYSkew; |
| 118 }; |
| 119 template <typename Next = PointProcessorInterface> |
| 120 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; |
| 121 |
| 122 static PointProcessorInterface* choose_matrix( |
| 123 PointProcessorInterface* next, |
| 124 const SkMatrix& inverse, |
| 125 SkLinearBitmapPipeline::MatrixStage* matrixProc) { |
| 126 if (inverse.hasPerspective()) { |
| 127 SkFAIL("Not implemented."); |
| 128 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { |
| 129 matrixProc->Initialize<AffineMatrix<>>( |
| 130 next, |
| 131 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, |
| 132 SkVector{inverse.getScaleX(), inverse.getScaleY()}, |
| 133 SkVector{inverse.getSkewX(), inverse.getSkewY()}); |
| 134 } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) { |
| 135 matrixProc->Initialize<ScaleMatrix<>>( |
| 136 next, |
| 137 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, |
| 138 SkVector{inverse.getScaleX(), inverse.getScaleY()}); |
| 139 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0
f) { |
| 140 matrixProc->Initialize<TranslateMatrix<>>( |
| 141 next, |
| 142 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); |
| 143 } else { |
| 144 matrixProc->Initialize<SkippedStage>(); |
| 145 return next; |
| 146 } |
| 147 return matrixProc->get(); |
| 148 } |
| 149 |
| 150 class ClampStrategy { |
| 151 public: |
| 152 ClampStrategy(X max) |
| 153 : fXMin{0.0f} |
| 154 , fXMax{max - 1.0f} { } |
| 155 ClampStrategy(Y max) |
| 156 : fYMin{0.0f} |
| 157 , fYMax{max - 1.0f} { } |
| 158 ClampStrategy(SkSize max) |
| 159 : fXMin{0.0f} |
| 160 , fYMin{0.0f} |
| 161 , fXMax{X(max) - 1.0f} |
| 162 , fYMax{Y(max) - 1.0f} { } |
| 163 |
| 164 void processPoints(Sk4f* xs, Sk4f* ys) { |
| 165 *xs = Sk4f::Min(Sk4f::Max(*xs, fXMin), fXMax); |
| 166 *ys = Sk4f::Min(Sk4f::Max(*ys, fYMin), fYMax); |
| 167 } |
| 168 |
| 169 private: |
| 170 const Sk4f fXMin{SK_FloatNegativeInfinity}; |
| 171 const Sk4f fYMin{SK_FloatNegativeInfinity}; |
| 172 const Sk4f fXMax{SK_FloatInfinity}; |
| 173 const Sk4f fYMax{SK_FloatInfinity}; |
| 174 }; |
| 175 template <typename Next = PointProcessorInterface> |
| 176 using Clamp = PointProcessor<ClampStrategy, Next>; |
| 177 |
| 178 class RepeatStrategy { |
| 179 public: |
| 180 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { } |
| 181 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { } |
| 182 RepeatStrategy(SkSize max) |
| 183 : fXMax{X(max)} |
| 184 , fXInvMax{1.0f / X(max)} |
| 185 , fYMax{Y(max)} |
| 186 , fYInvMax{1.0f / Y(max)} { } |
| 187 |
| 188 void processPoints(Sk4f* xs, Sk4f* ys) { |
| 189 Sk4f divX = (*xs * fXInvMax).floor(); |
| 190 Sk4f divY = (*ys * fYInvMax).floor(); |
| 191 Sk4f baseX = (divX * fXMax); |
| 192 Sk4f baseY = (divY * fYMax); |
| 193 *xs = *xs - baseX; |
| 194 *ys = *ys - baseY; |
| 195 } |
| 196 |
| 197 private: |
| 198 const Sk4f fXMax{0.0f}; |
| 199 const Sk4f fXInvMax{0.0f}; |
| 200 const Sk4f fYMax{0.0f}; |
| 201 const Sk4f fYInvMax{0.0f}; |
| 202 }; |
| 203 |
| 204 template <typename Next = PointProcessorInterface> |
| 205 using Repeat = PointProcessor<RepeatStrategy, Next>; |
| 206 |
| 207 static PointProcessorInterface* choose_tiler( |
| 208 PointProcessorInterface* next, |
| 209 SkSize dimensions, |
| 210 SkShader::TileMode xMode, |
| 211 SkShader::TileMode yMode, |
| 212 SkLinearBitmapPipeline::TileStage* tileProcXOrBoth, |
| 213 SkLinearBitmapPipeline::TileStage* tileProcY) { |
| 214 if (xMode == yMode) { |
| 215 switch (xMode) { |
| 216 case SkShader::kClamp_TileMode: |
| 217 tileProcXOrBoth->Initialize<Clamp<>>(next, dimensions); |
| 218 break; |
| 219 case SkShader::kRepeat_TileMode: |
| 220 tileProcXOrBoth->Initialize<Repeat<>>(next, dimensions); |
| 221 break; |
| 222 case SkShader::kMirror_TileMode: |
| 223 SkFAIL("Not implemented."); |
| 224 break; |
| 225 } |
| 226 tileProcY->Initialize<SkippedStage>(); |
| 227 } else { |
| 228 switch (yMode) { |
| 229 case SkShader::kClamp_TileMode: |
| 230 tileProcY->Initialize<Clamp<>>(next, Y(dimensions)); |
| 231 break; |
| 232 case SkShader::kRepeat_TileMode: |
| 233 tileProcY->Initialize<Repeat<>>(next, Y(dimensions)); |
| 234 break; |
| 235 case SkShader::kMirror_TileMode: |
| 236 SkFAIL("Not implemented."); |
| 237 break; |
| 238 } |
| 239 switch (xMode) { |
| 240 case SkShader::kClamp_TileMode: |
| 241 tileProcXOrBoth->Initialize<Clamp<>>(tileProcY->get(), X(dimensi
ons)); |
| 242 break; |
| 243 case SkShader::kRepeat_TileMode: |
| 244 tileProcXOrBoth->Initialize<Repeat<>>(tileProcY->get(), X(dimens
ions)); |
| 245 break; |
| 246 case SkShader::kMirror_TileMode: |
| 247 SkFAIL("Not implemented."); |
| 248 break; |
| 249 } |
| 250 } |
| 251 return tileProcXOrBoth->get(); |
| 252 } |
| 253 |
| 254 class sRGBFast { |
| 255 public: |
| 256 static Sk4f sRGBToLinear(Sk4fArg pixel) { |
| 257 Sk4f l = pixel * pixel; |
| 258 return Sk4f{l[0], l[1], l[2], pixel[3]}; |
| 259 } |
| 260 }; |
| 261 |
| 262 template <SkColorProfileType colorProfile> |
| 263 class Passthrough8888 { |
| 264 public: |
| 265 Passthrough8888(int width, const uint32_t* src) |
| 266 : fSrc{src}, fWidth{width}{ } |
| 267 |
| 268 void getFewPixels(int n, Sk4fArg xs, Sk4fArg ys, Sk4f* px0, Sk4f* px1, Sk4f*
px2) { |
| 269 Sk4i XIs = SkNx_cast<int, float>(xs); |
| 270 Sk4i YIs = SkNx_cast<int, float>(ys); |
| 271 Sk4i bufferLoc = YIs * fWidth + XIs; |
| 272 switch (n) { |
| 273 case 3: |
| 274 *px2 = getPixel(fSrc, bufferLoc[2]); |
| 275 case 2: |
| 276 *px1 = getPixel(fSrc, bufferLoc[1]); |
| 277 case 1: |
| 278 *px0 = getPixel(fSrc, bufferLoc[0]); |
| 279 default: |
| 280 break; |
| 281 } |
| 282 } |
| 283 |
| 284 void get4Pixels(Sk4fArg xs, Sk4fArg ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4
f* px3) { |
| 285 Sk4i XIs = SkNx_cast<int, float>(xs); |
| 286 Sk4i YIs = SkNx_cast<int, float>(ys); |
| 287 Sk4i bufferLoc = YIs * fWidth + XIs; |
| 288 *px0 = getPixel(fSrc, bufferLoc[0]); |
| 289 *px1 = getPixel(fSrc, bufferLoc[1]); |
| 290 *px2 = getPixel(fSrc, bufferLoc[2]); |
| 291 *px3 = getPixel(fSrc, bufferLoc[3]); |
| 292 } |
| 293 |
| 294 const uint32_t* row(int y) { return fSrc + y * fWidth[0]; } |
| 295 |
| 296 private: |
| 297 Sk4f getPixel(const uint32_t* src, int index) { |
| 298 Sk4b bytePixel = Sk4b::Load((uint8_t *)(&src[index])); |
| 299 Sk4f pixel = SkNx_cast<float, uint8_t>(bytePixel); |
| 300 pixel = pixel * Sk4f{1.0f/255.0f}; |
| 301 if (colorProfile == kSRGB_SkColorProfileType) { |
| 302 pixel = sRGBFast::sRGBToLinear(pixel); |
| 303 } |
| 304 return pixel; |
| 305 } |
| 306 const uint32_t* const fSrc; |
| 307 const Sk4i fWidth; |
| 308 }; |
| 309 |
| 310 template <typename SourceStrategy> |
| 311 class Sampler final : public PointProcessorInterface { |
| 312 public: |
| 313 template <typename... Args> |
| 314 Sampler(PixelPlacerInterface* next, Args&&... args) |
| 315 : fNext{next} |
| 316 , fStrategy{std::forward<Args>(args)...} { } |
| 317 |
| 318 void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override { |
| 319 SkASSERT(0 < n && n < 4); |
| 320 Sk4f px0, px1, px2; |
| 321 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); |
| 322 if (n >= 1) fNext->placePixel(px0); |
| 323 if (n >= 2) fNext->placePixel(px1); |
| 324 if (n >= 3) fNext->placePixel(px2); |
| 325 } |
| 326 |
| 327 void pointList4(Sk4fArg xs, Sk4fArg ys) override { |
| 328 Sk4f px0, px1, px2, px3; |
| 329 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); |
| 330 fNext->place4Pixels(px0, px1, px2, px3); |
| 331 } |
| 332 |
| 333 private: |
| 334 PixelPlacerInterface* const fNext; |
| 335 SourceStrategy fStrategy; |
| 336 }; |
| 337 |
| 338 static PointProcessorInterface* choose_pixel_sampler( |
| 339 PixelPlacerInterface* next, |
| 340 const SkImageInfo& imageInfo, |
| 341 const void* imageData, |
| 342 SkLinearBitmapPipeline::SampleStage* sampleStage) { |
| 343 switch (imageInfo.colorType()) { |
| 344 case kRGBA_8888_SkColorType: |
| 345 case kBGRA_8888_SkColorType: |
| 346 if (kN32_SkColorType == imageInfo.colorType()) { |
| 347 if (imageInfo.profileType() == kSRGB_SkColorProfileType) { |
| 348 sampleStage->Initialize<Sampler<Passthrough8888<kSRGB_SkColo
rProfileType>>>( |
| 349 next, imageInfo.width(), |
| 350 (uint32_t*)imageData); |
| 351 } else { |
| 352 sampleStage->Initialize<Sampler<Passthrough8888<kLinear_SkCo
lorProfileType>>>( |
| 353 next, imageInfo.width(), |
| 354 (uint32_t*)imageData); |
| 355 } |
| 356 } else { |
| 357 SkFAIL("Not implemented. No 8888 Swizzle"); |
| 358 } |
| 359 break; |
| 360 default: |
| 361 SkFAIL("Not implemented. Unsupported src"); |
| 362 break; |
| 363 } |
| 364 return sampleStage->get(); |
| 365 } |
| 366 |
| 367 template <SkAlphaType alphaType> |
| 368 class PlaceFPPixel final : public PixelPlacerInterface { |
| 369 public: |
| 370 void placePixel(Sk4fArg pixel) override { |
| 371 PlacePixel(fDst, pixel, 0); |
| 372 fDst += 1; |
| 373 } |
| 374 |
| 375 void place4Pixels(Sk4fArg p0, Sk4fArg p1, Sk4fArg p2, Sk4fArg p3) override { |
| 376 SkPM4f* dst = fDst; |
| 377 PlacePixel(dst, p0, 0); |
| 378 PlacePixel(dst, p1, 1); |
| 379 PlacePixel(dst, p2, 2); |
| 380 PlacePixel(dst, p3, 3); |
| 381 fDst += 4; |
| 382 } |
| 383 |
| 384 void setDestination(SkPM4f* dst) override { |
| 385 fDst = dst; |
| 386 } |
| 387 |
| 388 private: |
| 389 static void PlacePixel(SkPM4f* dst, Sk4fArg pixel, int index) { |
| 390 Sk4f newPixel = pixel; |
| 391 if (alphaType == kUnpremul_SkAlphaType) { |
| 392 newPixel = Premultiply(pixel); |
| 393 } |
| 394 newPixel.store(dst + index); |
| 395 } |
| 396 static Sk4f Premultiply(Sk4fArg pixel) { |
| 397 float alpha = pixel[3]; |
| 398 return pixel * Sk4f{alpha, alpha, alpha, 1.0f}; |
| 399 } |
| 400 |
| 401 SkPM4f* fDst; |
| 402 }; |
| 403 |
| 404 static PixelPlacerInterface* choose_pixel_placer( |
| 405 SkAlphaType alphaType, |
| 406 SkLinearBitmapPipeline::PixelStage* placerStage) { |
| 407 if (alphaType == kUnpremul_SkAlphaType) { |
| 408 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>(); |
| 409 } else { |
| 410 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType |
| 411 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>(); |
| 412 } |
| 413 return placerStage->get(); |
| 414 } |
| 415 |
| 416 SkLinearBitmapPipeline::SkLinearBitmapPipeline( |
| 417 const SkMatrix& inverse, |
| 418 SkShader::TileMode xTile, SkShader::TileMode yTile, |
| 419 const SkImageInfo& srcImageInfo, |
| 420 const void* srcImageData) { |
| 421 SkSize size; |
| 422 size = srcImageInfo.dimensions(); |
| 423 |
| 424 // As the stages are built, the chooser function may skip a stage. For examp
le, with the |
| 425 // identity matrix, the matrix stage is skipped, and the tilerStage is the f
irst stage. |
| 426 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelS
tage); |
| 427 auto samplerStage = choose_pixel_sampler(placementStage, srcImageInfo, |
| 428 srcImageData, &fSampleStage); |
| 429 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX
OrBothStage, |
| 430 &fTileYStage); |
| 431 fFirstStage = choose_matrix(tilerStage, inverse, &fMatrixStage); |
| 432 } |
| 433 |
| 434 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { |
| 435 fPixelStage->setDestination(dst); |
| 436 |
| 437 Sk4f Xs = Sk4f(x) + Sk4f{0.5f, 1.5f, 2.5f, 3.5f}; |
| 438 Sk4f Ys(y); |
| 439 Sk4f fours{4.0f}; |
| 440 |
| 441 while (count >= 4) { |
| 442 fFirstStage->pointList4(Xs, Ys); |
| 443 Xs = Xs + fours; |
| 444 count -= 4; |
| 445 } |
| 446 if (count > 0) { |
| 447 fFirstStage->pointListFew(count, Xs, Ys); |
| 448 } |
| 449 } |
OLD | NEW |