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