Line data Source code
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 0 : class MatrixStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
39 : public:
40 : template <typename... Args>
41 0 : MatrixStage(Next* next, Args&&... args)
42 : : fNext{next}
43 0 : , fStrategy{std::forward<Args>(args)...}{ }
44 :
45 0 : MatrixStage(Next* next, MatrixStage* stage)
46 : : fNext{next}
47 0 : , fStrategy{stage->fStrategy} { }
48 :
49 0 : void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
50 0 : fStrategy.processPoints(&xs, &ys);
51 0 : fNext->pointListFew(n, xs, ys);
52 0 : }
53 :
54 0 : void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
55 0 : fStrategy.processPoints(&xs, &ys);
56 0 : fNext->pointList4(xs, ys);
57 0 : }
58 :
59 : // The span you pass must not be empty.
60 0 : void pointSpan(Span span) override {
61 0 : SkASSERT(!span.isEmpty());
62 0 : if (!fStrategy.maybeProcessSpan(span, fNext)) {
63 0 : span_fallback(span, this);
64 : }
65 0 : }
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 0 : class CombinedTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
90 : public:
91 0 : CombinedTileStage(Next* next, SkISize dimensions)
92 : : fNext{next}
93 : , fXStrategy{dimensions.width()}
94 0 : , fYStrategy{dimensions.height()}{ }
95 :
96 0 : CombinedTileStage(Next* next, CombinedTileStage* stage)
97 : : fNext{next}
98 : , fXStrategy{stage->fXStrategy}
99 0 : , fYStrategy{stage->fYStrategy} { }
100 :
101 0 : void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
102 0 : fXStrategy.tileXPoints(&xs);
103 0 : fYStrategy.tileYPoints(&ys);
104 0 : fNext->pointListFew(n, xs, ys);
105 0 : }
106 :
107 0 : void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
108 0 : fXStrategy.tileXPoints(&xs);
109 0 : fYStrategy.tileYPoints(&ys);
110 0 : fNext->pointList4(xs, ys);
111 0 : }
112 :
113 : // The span you pass must not be empty.
114 0 : void pointSpan(Span span) override {
115 0 : SkASSERT(!span.isEmpty());
116 : SkPoint start; SkScalar length; int count;
117 0 : std::tie(start, length, count) = span;
118 :
119 0 : 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 0 : this->pointListFew(1, Sk4f{span.startX()}, Sk4f{span.startY()});
125 0 : return;
126 : }
127 :
128 0 : SkScalar x = X(start);
129 0 : SkScalar y = fYStrategy.tileY(Y(start));
130 0 : Span yAdjustedSpan{{x, y}, length, count};
131 :
132 0 : if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) {
133 0 : 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 0 : class RGBA8888UnitRepeatSrc final : public SkLinearBitmapPipeline::SampleProcessorInterface,
150 : public SkLinearBitmapPipeline::DestinationInterface {
151 : public:
152 0 : RGBA8888UnitRepeatSrc(const uint32_t* src, int32_t width)
153 0 : : fSrc{src}, fWidth{width} { }
154 :
155 0 : void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
156 0 : SkASSERT(fDest + n <= fEnd);
157 : // At this point xs and ys should be >= 0, so trunc is the same as floor.
158 0 : Sk4i iXs = SkNx_cast<int>(xs);
159 0 : Sk4i iYs = SkNx_cast<int>(ys);
160 :
161 0 : if (n >= 1) *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
162 0 : if (n >= 2) *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
163 0 : if (n >= 3) *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
164 0 : }
165 :
166 0 : void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
167 0 : SkASSERT(fDest + 4 <= fEnd);
168 0 : Sk4i iXs = SkNx_cast<int>(xs);
169 0 : Sk4i iYs = SkNx_cast<int>(ys);
170 0 : *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
171 0 : *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
172 0 : *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
173 0 : *fDest++ = *this->pixelAddress(iXs[3], iYs[3]);
174 0 : }
175 :
176 0 : void pointSpan(Span span) override {
177 0 : SkASSERT(fDest + span.count() <= fEnd);
178 0 : if (span.length() != 0.0f) {
179 0 : int32_t x = SkScalarTruncToInt(span.startX());
180 0 : int32_t y = SkScalarTruncToInt(span.startY());
181 0 : const uint32_t* src = this->pixelAddress(x, y);
182 0 : memmove(fDest, src, span.count() * sizeof(uint32_t));
183 0 : fDest += span.count();
184 : }
185 0 : }
186 :
187 0 : void repeatSpan(Span span, int32_t repeatCount) override {
188 0 : SkASSERT(fDest + span.count() * repeatCount <= fEnd);
189 :
190 0 : int32_t x = SkScalarTruncToInt(span.startX());
191 0 : int32_t y = SkScalarTruncToInt(span.startY());
192 0 : const uint32_t* src = this->pixelAddress(x, y);
193 0 : uint32_t* dest = fDest;
194 0 : while (repeatCount --> 0) {
195 0 : memmove(dest, src, span.count() * sizeof(uint32_t));
196 0 : dest += span.count();
197 : }
198 0 : fDest = dest;
199 0 : }
200 :
201 0 : void setDestination(void* dst, int count) override {
202 0 : fDest = static_cast<uint32_t*>(dst);
203 0 : fEnd = fDest + count;
204 0 : }
205 :
206 : private:
207 0 : const uint32_t* pixelAddress(int32_t x, int32_t y) {
208 0 : 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 0 : class RGBA8888UnitRepeatSrcOver final : public SkLinearBitmapPipeline::SampleProcessorInterface,
220 : public SkLinearBitmapPipeline::DestinationInterface {
221 : public:
222 0 : RGBA8888UnitRepeatSrcOver(const uint32_t* src, int32_t width)
223 0 : : fSrc{src}, fWidth{width} { }
224 :
225 0 : void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
226 0 : SkASSERT(fDest + n <= fEnd);
227 : // At this point xs and ys should be >= 0, so trunc is the same as floor.
228 0 : Sk4i iXs = SkNx_cast<int>(xs);
229 0 : Sk4i iYs = SkNx_cast<int>(ys);
230 :
231 0 : if (n >= 1) blendPixelAt(iXs[0], iYs[0]);
232 0 : if (n >= 2) blendPixelAt(iXs[1], iYs[1]);
233 0 : if (n >= 3) blendPixelAt(iXs[2], iYs[2]);
234 0 : }
235 :
236 0 : void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
237 0 : SkASSERT(fDest + 4 <= fEnd);
238 0 : Sk4i iXs = SkNx_cast<int>(xs);
239 0 : Sk4i iYs = SkNx_cast<int>(ys);
240 0 : blendPixelAt(iXs[0], iYs[0]);
241 0 : blendPixelAt(iXs[1], iYs[1]);
242 0 : blendPixelAt(iXs[2], iYs[2]);
243 0 : blendPixelAt(iXs[3], iYs[3]);
244 0 : }
245 :
246 0 : void pointSpan(Span span) override {
247 0 : if (span.length() != 0.0f) {
248 0 : this->repeatSpan(span, 1);
249 : }
250 0 : }
251 :
252 0 : void repeatSpan(Span span, int32_t repeatCount) override {
253 0 : SkASSERT(fDest + span.count() * repeatCount <= fEnd);
254 0 : SkASSERT(span.count() > 0);
255 0 : SkASSERT(repeatCount > 0);
256 :
257 0 : int32_t x = (int32_t)span.startX();
258 0 : int32_t y = (int32_t)span.startY();
259 0 : const uint32_t* beginSpan = this->pixelAddress(x, y);
260 :
261 0 : SkOpts::srcover_srgb_srgb(fDest, beginSpan, span.count() * repeatCount, span.count());
262 :
263 0 : fDest += span.count() * repeatCount;
264 :
265 0 : SkASSERT(fDest <= fEnd);
266 0 : }
267 :
268 0 : void setDestination(void* dst, int count) override {
269 0 : SkASSERT(count > 0);
270 0 : fDest = static_cast<uint32_t*>(dst);
271 0 : fEnd = fDest + count;
272 0 : }
273 :
274 : private:
275 0 : const uint32_t* pixelAddress(int32_t x, int32_t y) {
276 0 : return &fSrc[fWidth * y + x];
277 : }
278 :
279 0 : void blendPixelAt(int32_t x, int32_t y) {
280 0 : const uint32_t* src = this->pixelAddress(x, y);
281 0 : SkOpts::srcover_srgb_srgb(fDest, src, 1, 1);
282 0 : fDest += 1;
283 0 : }
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 0 : class SrcFPPixel final : public Blender {
297 : public:
298 0 : SrcFPPixel(float postAlpha) : fPostAlpha{postAlpha} { }
299 : SrcFPPixel(const SrcFPPixel& Blender) : fPostAlpha(Blender.fPostAlpha) {}
300 0 : void SK_VECTORCALL blendPixel(Sk4f pixel) override {
301 0 : SkASSERT(fDst + 1 <= fEnd );
302 0 : this->srcPixel(fDst, pixel, 0);
303 0 : fDst += 1;
304 0 : }
305 :
306 0 : void SK_VECTORCALL blend4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
307 0 : SkASSERT(fDst + 4 <= fEnd);
308 0 : SkPM4f* dst = fDst;
309 0 : this->srcPixel(dst, p0, 0);
310 0 : this->srcPixel(dst, p1, 1);
311 0 : this->srcPixel(dst, p2, 2);
312 0 : this->srcPixel(dst, p3, 3);
313 0 : fDst += 4;
314 0 : }
315 :
316 0 : void setDestination(void* dst, int count) override {
317 0 : fDst = static_cast<SkPM4f*>(dst);
318 0 : fEnd = fDst + count;
319 0 : }
320 :
321 : private:
322 0 : void SK_VECTORCALL srcPixel(SkPM4f* dst, Sk4f pixel, int index) {
323 0 : check_pixel(pixel);
324 :
325 0 : Sk4f newPixel = pixel;
326 : if (alphaType == kUnpremul_SkAlphaType) {
327 0 : newPixel = Premultiply(pixel);
328 : }
329 0 : newPixel = newPixel * fPostAlpha;
330 0 : newPixel.store(dst + index);
331 0 : }
332 0 : static Sk4f SK_VECTORCALL Premultiply(Sk4f pixel) {
333 0 : float alpha = pixel[3];
334 0 : 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 0 : SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {}
347 :
348 0 : SkLinearBitmapPipeline::SkLinearBitmapPipeline(
349 : const SkMatrix& inverse,
350 : SkFilterQuality filterQuality,
351 : SkShader::TileMode xTile, SkShader::TileMode yTile,
352 : SkColor paintColor,
353 : const SkPixmap& srcPixmap,
354 0 : SkArenaAlloc* allocator)
355 : {
356 0 : SkISize dimensions = srcPixmap.info().dimensions();
357 0 : const SkImageInfo& srcImageInfo = srcPixmap.info();
358 :
359 0 : SkMatrix adjustedInverse = inverse;
360 0 : if (filterQuality == kNone_SkFilterQuality) {
361 0 : if (inverse.getScaleX() >= 0.0f) {
362 0 : adjustedInverse.setTranslateX(
363 0 : nextafterf(inverse.getTranslateX(), std::floor(inverse.getTranslateX())));
364 : }
365 0 : if (inverse.getScaleY() >= 0.0f) {
366 0 : adjustedInverse.setTranslateY(
367 0 : nextafterf(inverse.getTranslateY(), std::floor(inverse.getTranslateY())));
368 : }
369 : }
370 :
371 0 : SkScalar dx = adjustedInverse.getScaleX();
372 :
373 : // If it is an index 8 color type, the sampler converts to unpremul for better fidelity.
374 0 : SkAlphaType alphaType = srcImageInfo.alphaType();
375 0 : if (srcPixmap.colorType() == kIndex_8_SkColorType) {
376 0 : alphaType = kUnpremul_SkAlphaType;
377 : }
378 :
379 0 : 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 0 : auto blenderStage = this->chooseBlenderForShading(alphaType, postAlpha, allocator);
383 : auto samplerStage = this->chooseSampler(
384 0 : blenderStage, filterQuality, xTile, yTile, srcPixmap, paintColor, allocator);
385 : auto tilerStage = this->chooseTiler(
386 0 : samplerStage, dimensions, xTile, yTile, filterQuality, dx, allocator);
387 0 : fFirstStage = this->chooseMatrix(tilerStage, adjustedInverse, allocator);
388 0 : fLastStage = blenderStage;
389 0 : }
390 :
391 0 : SkLinearBitmapPipeline::SkLinearBitmapPipeline(
392 : const SkLinearBitmapPipeline& pipeline,
393 : const SkPixmap& srcPixmap,
394 : SkBlendMode mode,
395 : const SkImageInfo& dstInfo,
396 0 : SkArenaAlloc* allocator)
397 : {
398 0 : SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver);
399 0 : SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType()
400 : && srcPixmap.info().colorType() == kRGBA_8888_SkColorType);
401 :
402 : SampleProcessorInterface* sampleStage;
403 0 : if (mode == SkBlendMode::kSrc) {
404 : auto sampler = allocator->make<RGBA8888UnitRepeatSrc>(
405 0 : srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
406 0 : sampleStage = sampler;
407 0 : fLastStage = sampler;
408 : } else {
409 : auto sampler = allocator->make<RGBA8888UnitRepeatSrcOver>(
410 0 : srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
411 0 : sampleStage = sampler;
412 0 : fLastStage = sampler;
413 : }
414 :
415 0 : auto tilerStage = pipeline.fTileStageCloner(sampleStage, allocator);
416 0 : auto matrixStage = pipeline.fMatrixStageCloner(tilerStage, allocator);
417 0 : fFirstStage = matrixStage;
418 0 : }
419 :
420 0 : 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 0 : if (blendMode == SkBlendMode::kSrcOver && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) {
431 0 : blendMode = SkBlendMode::kSrc;
432 : }
433 :
434 0 : if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return nullptr; }
435 0 : if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return nullptr; }
436 0 : if (finalAlpha != 1.0f) { return nullptr; }
437 0 : if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType
438 0 : || dstInfo.colorType() != kRGBA_8888_SkColorType) { return nullptr; }
439 :
440 0 : if (!srcPixmap.info().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) {
441 0 : return nullptr;
442 : }
443 :
444 0 : if (blendMode != SkBlendMode::kSrc && blendMode != SkBlendMode::kSrcOver) {
445 0 : return nullptr;
446 : }
447 :
448 0 : return allocator->make<SkLinearBitmapPipeline>(
449 0 : pipeline, srcPixmap, blendMode, dstInfo, allocator);
450 : }
451 :
452 0 : void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
453 0 : SkASSERT(count > 0);
454 0 : this->blitSpan(x, y, dst, count);
455 0 : }
456 :
457 0 : void SkLinearBitmapPipeline::blitSpan(int x, int y, void* dst, int count) {
458 0 : SkASSERT(count > 0);
459 0 : 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 0 : fFirstStage->pointSpan(Span{{x + 0.5f, y + 0.5f}, count - 1.0f, count});
466 0 : }
467 :
468 : SkLinearBitmapPipeline::PointProcessorInterface*
469 0 : SkLinearBitmapPipeline::chooseMatrix(
470 : PointProcessorInterface* next,
471 : const SkMatrix& inverse,
472 : SkArenaAlloc* allocator)
473 : {
474 0 : if (inverse.hasPerspective()) {
475 : auto matrixStage = allocator->make<PerspectiveMatrix<>>(
476 : next,
477 0 : SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
478 0 : SkVector{inverse.getScaleX(), inverse.getScaleY()},
479 0 : SkVector{inverse.getSkewX(), inverse.getSkewY()},
480 0 : SkVector{inverse.getPerspX(), inverse.getPerspY()},
481 0 : inverse.get(SkMatrix::kMPersp2));
482 : fMatrixStageCloner =
483 0 : [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
484 0 : return memory->make<PerspectiveMatrix<>>(cloneNext, matrixStage);
485 0 : };
486 0 : return matrixStage;
487 0 : } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
488 : auto matrixStage = allocator->make<AffineMatrix<>>(
489 : next,
490 0 : SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
491 0 : SkVector{inverse.getScaleX(), inverse.getScaleY()},
492 0 : SkVector{inverse.getSkewX(), inverse.getSkewY()});
493 : fMatrixStageCloner =
494 0 : [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
495 0 : return memory->make<AffineMatrix<>>(cloneNext, matrixStage);
496 0 : };
497 0 : return matrixStage;
498 0 : } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
499 : auto matrixStage = allocator->make<ScaleMatrix<>>(
500 : next,
501 0 : SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
502 0 : SkVector{inverse.getScaleX(), inverse.getScaleY()});
503 : fMatrixStageCloner =
504 0 : [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
505 0 : return memory->make<ScaleMatrix<>>(cloneNext, matrixStage);
506 0 : };
507 0 : return matrixStage;
508 0 : } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) {
509 : auto matrixStage = allocator->make<TranslateMatrix<>>(
510 : next,
511 0 : SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
512 : fMatrixStageCloner =
513 0 : [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
514 0 : return memory->make<TranslateMatrix<>>(cloneNext, matrixStage);
515 0 : };
516 0 : return matrixStage;
517 : } else {
518 0 : fMatrixStageCloner = [](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
519 : return cloneNext;
520 0 : };
521 0 : return next;
522 : }
523 : }
524 :
525 : template <typename Tiler>
526 0 : SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::createTiler(
527 : SampleProcessorInterface* next,
528 : SkISize dimensions,
529 : SkArenaAlloc* allocator)
530 : {
531 0 : auto tilerStage = allocator->make<Tiler>(next, dimensions);
532 0 : fTileStageCloner =
533 : [tilerStage](SampleProcessorInterface* cloneNext,
534 0 : SkArenaAlloc* memory) -> PointProcessorInterface* {
535 0 : return memory->make<Tiler>(cloneNext, tilerStage);
536 : };
537 0 : return tilerStage;
538 : }
539 :
540 : template <typename XStrategy>
541 0 : SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTilerYMode(
542 : SampleProcessorInterface* next,
543 : SkShader::TileMode yMode,
544 : SkISize dimensions,
545 : SkArenaAlloc* allocator)
546 : {
547 0 : switch (yMode) {
548 : case SkShader::kClamp_TileMode: {
549 : using Tiler = CombinedTileStage<XStrategy, YClampStrategy, SampleProcessorInterface>;
550 0 : return this->createTiler<Tiler>(next, dimensions, allocator);
551 : }
552 : case SkShader::kRepeat_TileMode: {
553 : using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, SampleProcessorInterface>;
554 0 : return this->createTiler<Tiler>(next, dimensions, allocator);
555 : }
556 : case SkShader::kMirror_TileMode: {
557 : using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, SampleProcessorInterface>;
558 0 : return this->createTiler<Tiler>(next, dimensions, allocator);
559 : }
560 : }
561 :
562 : // Should never get here.
563 0 : SkFAIL("Not all Y tile cases covered.");
564 0 : return nullptr;
565 : }
566 :
567 0 : 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 0 : switch (xMode) {
577 : case SkShader::kClamp_TileMode:
578 0 : return this->chooseTilerYMode<XClampStrategy>(next, yMode, dimensions, allocator);
579 : case SkShader::kRepeat_TileMode:
580 0 : if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) {
581 : return this->chooseTilerYMode<XRepeatUnitScaleStrategy>(
582 0 : next, yMode, dimensions, allocator);
583 : } else {
584 : return this->chooseTilerYMode<XRepeatStrategy>(
585 0 : next, yMode, dimensions, allocator);
586 : }
587 : case SkShader::kMirror_TileMode:
588 0 : return this->chooseTilerYMode<XMirrorStrategy>(next, yMode, dimensions, allocator);
589 : }
590 :
591 : // Should never get here.
592 0 : SkFAIL("Not all X tile cases covered.");
593 0 : return nullptr;
594 : }
595 :
596 : template <SkColorType colorType>
597 : SkLinearBitmapPipeline::PixelAccessorInterface*
598 0 : SkLinearBitmapPipeline::chooseSpecificAccessor(
599 : const SkPixmap& srcPixmap,
600 : SkArenaAlloc* allocator)
601 : {
602 0 : if (srcPixmap.info().gammaCloseToSRGB()) {
603 : using Accessor = PixelAccessor<colorType, kSRGB_SkGammaType>;
604 0 : return allocator->make<Accessor>(srcPixmap);
605 : } else {
606 : using Accessor = PixelAccessor<colorType, kLinear_SkGammaType>;
607 0 : return allocator->make<Accessor>(srcPixmap);
608 : }
609 : }
610 :
611 0 : SkLinearBitmapPipeline::PixelAccessorInterface* SkLinearBitmapPipeline::choosePixelAccessor(
612 : const SkPixmap& srcPixmap,
613 : const SkColor A8TintColor,
614 : SkArenaAlloc* allocator)
615 : {
616 0 : const SkImageInfo& imageInfo = srcPixmap.info();
617 :
618 0 : switch (imageInfo.colorType()) {
619 : case kAlpha_8_SkColorType: {
620 : using Accessor = PixelAccessor<kAlpha_8_SkColorType, kLinear_SkGammaType>;
621 0 : return allocator->make<Accessor>(srcPixmap, A8TintColor);
622 : }
623 : case kARGB_4444_SkColorType:
624 0 : return this->chooseSpecificAccessor<kARGB_4444_SkColorType>(srcPixmap, allocator);
625 : case kRGB_565_SkColorType:
626 0 : return this->chooseSpecificAccessor<kRGB_565_SkColorType>(srcPixmap, allocator);
627 : case kRGBA_8888_SkColorType:
628 0 : return this->chooseSpecificAccessor<kRGBA_8888_SkColorType>(srcPixmap, allocator);
629 : case kBGRA_8888_SkColorType:
630 0 : return this->chooseSpecificAccessor<kBGRA_8888_SkColorType>(srcPixmap, allocator);
631 : case kIndex_8_SkColorType:
632 0 : return this->chooseSpecificAccessor<kIndex_8_SkColorType>(srcPixmap, allocator);
633 : case kGray_8_SkColorType:
634 0 : return this->chooseSpecificAccessor<kGray_8_SkColorType>(srcPixmap, allocator);
635 : case kRGBA_F16_SkColorType: {
636 : using Accessor = PixelAccessor<kRGBA_F16_SkColorType, kLinear_SkGammaType>;
637 0 : return allocator->make<Accessor>(srcPixmap);
638 : }
639 : default:
640 : // Should never get here.
641 0 : SkFAIL("Pixel source not supported.");
642 0 : return nullptr;
643 : }
644 : }
645 :
646 0 : 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 0 : const SkImageInfo& imageInfo = srcPixmap.info();
655 0 : SkISize dimensions = imageInfo.dimensions();
656 :
657 : // Special case samplers with fully expanded templates
658 0 : if (imageInfo.gammaCloseToSRGB()) {
659 0 : if (filterQuality == kNone_SkFilterQuality) {
660 0 : switch (imageInfo.colorType()) {
661 : case kN32_SkColorType: {
662 : using Sampler =
663 : NearestNeighborSampler<
664 : PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
665 0 : 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 0 : return allocator->make<Sampler>(next, srcPixmap);
672 : }
673 : default:
674 0 : break;
675 : }
676 : } else {
677 0 : switch (imageInfo.colorType()) {
678 : case kN32_SkColorType: {
679 : using Sampler =
680 : BilerpSampler<
681 : PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
682 0 : 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 0 : return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
689 : }
690 : default:
691 0 : break;
692 : }
693 : }
694 : }
695 :
696 0 : auto pixelAccessor = this->choosePixelAccessor(srcPixmap, A8TintColor, allocator);
697 : // General cases.
698 0 : if (filterQuality == kNone_SkFilterQuality) {
699 : using Sampler = NearestNeighborSampler<PixelAccessorShim, Blender>;
700 0 : return allocator->make<Sampler>(next, pixelAccessor);
701 : } else {
702 : using Sampler = BilerpSampler<PixelAccessorShim, Blender>;
703 0 : return allocator->make<Sampler>(next, dimensions, xTile, yTile, pixelAccessor);
704 : }
705 : }
706 :
707 0 : Blender* SkLinearBitmapPipeline::chooseBlenderForShading(
708 : SkAlphaType alphaType,
709 : float postAlpha,
710 : SkArenaAlloc* allocator)
711 : {
712 0 : if (alphaType == kUnpremul_SkAlphaType) {
713 0 : return allocator->make<SrcFPPixel<kUnpremul_SkAlphaType>>(postAlpha);
714 : } else {
715 : // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
716 0 : return allocator->make<SrcFPPixel<kPremul_SkAlphaType>>(postAlpha);
717 : }
718 : }
|