blob: 401eb41b79ddacba10d4fc52385df898b4e236bc [file] [log] [blame]
herbfeec8782016-02-17 10:00:07 -08001/*
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
herbed545042016-02-18 13:55:02 -080010#include <algorithm>
11#include <cmath>
12#include <limits>
herb94665712016-02-29 07:53:22 -080013#include <tuple>
herb871a0482016-05-03 08:11:52 -070014
herb490d30f2016-03-04 10:39:14 -080015#include "SkLinearBitmapPipeline_core.h"
16#include "SkLinearBitmapPipeline_matrix.h"
17#include "SkLinearBitmapPipeline_tile.h"
herb6eff52a2016-03-23 09:00:33 -070018#include "SkLinearBitmapPipeline_sample.h"
herb871a0482016-05-03 08:11:52 -070019#include "SkNx.h"
20#include "SkOpts.h"
21#include "SkPM4f.h"
herba856e252016-02-22 14:48:21 -080022
herb9e0efe52016-04-08 13:25:28 -070023////////////////////////////////////////////////////////////////////////////////////////////////////
24// SkLinearBitmapPipeline::Stage
25template<typename Base, size_t kSize, typename Next>
26SkLinearBitmapPipeline::Stage<Base, kSize, Next>::~Stage() {
27 if (fIsInitialized) {
28 this->get()->~Base();
29 }
30}
31
32template<typename Base, size_t kSize, typename Next>
33template<typename Variant, typename... Args>
34void SkLinearBitmapPipeline::Stage<Base, kSize, Next>::initStage(Next* next, Args&& ... args) {
35 SkASSERTF(sizeof(Variant) <= sizeof(fSpace),
36 "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace));
37
38 new (&fSpace) Variant(next, std::forward<Args>(args)...);
39 fStageCloner = [this](Next* nextClone, void* addr) {
40 new (addr) Variant(nextClone, (const Variant&)*this->get());
41 };
42 fIsInitialized = true;
43};
44
45template<typename Base, size_t kSize, typename Next>
46template<typename Variant, typename... Args>
47void SkLinearBitmapPipeline::Stage<Base, kSize, Next>::initSink(Args&& ... args) {
48 SkASSERTF(sizeof(Variant) <= sizeof(fSpace),
49 "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace));
50 new (&fSpace) Variant(std::forward<Args>(args)...);
51 fIsInitialized = true;
52};
53
54template<typename Base, size_t kSize, typename Next>
55template <typename To, typename From>
56To* SkLinearBitmapPipeline::Stage<Base, kSize, Next>::getInterface() {
57 From* down = static_cast<From*>(this->get());
58 return static_cast<To*>(down);
59}
60
61template<typename Base, size_t kSize, typename Next>
62Base* SkLinearBitmapPipeline::Stage<Base, kSize, Next>::cloneStageTo(
63 Next* next, Stage* cloneToStage) const
64{
65 if (!fIsInitialized) return nullptr;
66 fStageCloner(next, &cloneToStage->fSpace);
67 return cloneToStage->get();
68}
69
herba856e252016-02-22 14:48:21 -080070namespace {
herb6eff52a2016-03-23 09:00:33 -070071
72////////////////////////////////////////////////////////////////////////////////////////////////////
73// Matrix Stage
herb933ad432016-02-22 13:13:28 -080074// PointProcessor uses a strategy to help complete the work of the different stages. The strategy
75// must implement the following methods:
76// * processPoints(xs, ys) - must mutate the xs and ys for the stage.
herb94665712016-02-29 07:53:22 -080077// * maybeProcessSpan(span, next) - This represents a horizontal series of pixels
herb933ad432016-02-22 13:13:28 -080078// to work over.
herb94665712016-02-29 07:53:22 -080079// span - encapsulation of span.
herb933ad432016-02-22 13:13:28 -080080// next - a pointer to the next stage.
81// maybeProcessSpan - returns false if it can not process the span and needs to fallback to
82// point lists for processing.
herbfeec8782016-02-17 10:00:07 -080083template<typename Strategy, typename Next>
herb6eff52a2016-03-23 09:00:33 -070084class MatrixStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
herbfeec8782016-02-17 10:00:07 -080085public:
86 template <typename... Args>
herb6eff52a2016-03-23 09:00:33 -070087 MatrixStage(Next* next, Args&&... args)
herbfeec8782016-02-17 10:00:07 -080088 : fNext{next}
89 , fStrategy{std::forward<Args>(args)...}{ }
90
herb9e0efe52016-04-08 13:25:28 -070091 MatrixStage(Next* next, const MatrixStage& stage)
92 : fNext{next}
93 , fStrategy{stage.fStrategy} { }
94
mtkleine5fb9c82016-07-07 08:12:09 -070095 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
mtklein88893472016-02-22 16:56:00 -080096 fStrategy.processPoints(&xs, &ys);
97 fNext->pointListFew(n, xs, ys);
herbfeec8782016-02-17 10:00:07 -080098 }
99
mtkleine5fb9c82016-07-07 08:12:09 -0700100 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
mtklein88893472016-02-22 16:56:00 -0800101 fStrategy.processPoints(&xs, &ys);
102 fNext->pointList4(xs, ys);
herbfeec8782016-02-17 10:00:07 -0800103 }
104
herb94665712016-02-29 07:53:22 -0800105 // The span you pass must not be empty.
106 void pointSpan(Span span) override {
107 SkASSERT(!span.isEmpty());
108 if (!fStrategy.maybeProcessSpan(span, fNext)) {
109 span_fallback(span, this);
herb933ad432016-02-22 13:13:28 -0800110 }
herb3eb48952016-02-19 14:39:47 -0800111 }
112
herbfeec8782016-02-17 10:00:07 -0800113private:
114 Next* const fNext;
115 Strategy fStrategy;
116};
117
herba856e252016-02-22 14:48:21 -0800118template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
herb6eff52a2016-03-23 09:00:33 -0700119using TranslateMatrix = MatrixStage<TranslateMatrixStrategy, Next>;
herbfeec8782016-02-17 10:00:07 -0800120
herba856e252016-02-22 14:48:21 -0800121template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
herb6eff52a2016-03-23 09:00:33 -0700122using ScaleMatrix = MatrixStage<ScaleMatrixStrategy, Next>;
herbfeec8782016-02-17 10:00:07 -0800123
herba856e252016-02-22 14:48:21 -0800124template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
herb6eff52a2016-03-23 09:00:33 -0700125using AffineMatrix = MatrixStage<AffineMatrixStrategy, Next>;
126
127template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
128using PerspectiveMatrix = MatrixStage<PerspectiveMatrixStrategy, Next>;
129
herbfeec8782016-02-17 10:00:07 -0800130
herba856e252016-02-22 14:48:21 -0800131static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix(
132 SkLinearBitmapPipeline::PointProcessorInterface* next,
herbfeec8782016-02-17 10:00:07 -0800133 const SkMatrix& inverse,
134 SkLinearBitmapPipeline::MatrixStage* matrixProc) {
135 if (inverse.hasPerspective()) {
herb9e0efe52016-04-08 13:25:28 -0700136 matrixProc->initStage<PerspectiveMatrix<>>(
herb6eff52a2016-03-23 09:00:33 -0700137 next,
138 SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
139 SkVector{inverse.getScaleX(), inverse.getScaleY()},
140 SkVector{inverse.getSkewX(), inverse.getSkewY()},
141 SkVector{inverse.getPerspX(), inverse.getPerspY()},
142 inverse.get(SkMatrix::kMPersp2));
herbfeec8782016-02-17 10:00:07 -0800143 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
herb9e0efe52016-04-08 13:25:28 -0700144 matrixProc->initStage<AffineMatrix<>>(
herbfeec8782016-02-17 10:00:07 -0800145 next,
146 SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
147 SkVector{inverse.getScaleX(), inverse.getScaleY()},
148 SkVector{inverse.getSkewX(), inverse.getSkewY()});
149 } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
herb9e0efe52016-04-08 13:25:28 -0700150 matrixProc->initStage<ScaleMatrix<>>(
herbfeec8782016-02-17 10:00:07 -0800151 next,
152 SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
153 SkVector{inverse.getScaleX(), inverse.getScaleY()});
154 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) {
herb9e0efe52016-04-08 13:25:28 -0700155 matrixProc->initStage<TranslateMatrix<>>(
herbfeec8782016-02-17 10:00:07 -0800156 next,
157 SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
158 } else {
herbfeec8782016-02-17 10:00:07 -0800159 return next;
160 }
161 return matrixProc->get();
162}
163
herb490d30f2016-03-04 10:39:14 -0800164////////////////////////////////////////////////////////////////////////////////////////////////////
herb6eff52a2016-03-23 09:00:33 -0700165// Tile Stage
166
167template<typename XStrategy, typename YStrategy, typename Next>
herb86a6c6d2016-07-22 14:06:27 -0700168class CombinedTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
herbc5eddd72016-02-17 19:50:05 -0800169public:
herb86a6c6d2016-07-22 14:06:27 -0700170 CombinedTileStage(Next* next, SkISize dimensions)
herb6eff52a2016-03-23 09:00:33 -0700171 : fNext{next}
172 , fXStrategy{dimensions.width()}
173 , fYStrategy{dimensions.height()}{ }
herbc5eddd72016-02-17 19:50:05 -0800174
herb86a6c6d2016-07-22 14:06:27 -0700175 CombinedTileStage(Next* next, const CombinedTileStage& stage)
herb9e0efe52016-04-08 13:25:28 -0700176 : fNext{next}
177 , fXStrategy{stage.fXStrategy}
178 , fYStrategy{stage.fYStrategy} { }
179
mtkleine5fb9c82016-07-07 08:12:09 -0700180 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
herb6eff52a2016-03-23 09:00:33 -0700181 fXStrategy.tileXPoints(&xs);
182 fYStrategy.tileYPoints(&ys);
183 fNext->pointListFew(n, xs, ys);
herbc5eddd72016-02-17 19:50:05 -0800184 }
185
mtkleine5fb9c82016-07-07 08:12:09 -0700186 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
herb6eff52a2016-03-23 09:00:33 -0700187 fXStrategy.tileXPoints(&xs);
188 fYStrategy.tileYPoints(&ys);
189 fNext->pointList4(xs, ys);
herbc5eddd72016-02-17 19:50:05 -0800190 }
191
herb6eff52a2016-03-23 09:00:33 -0700192 // The span you pass must not be empty.
herb94665712016-02-29 07:53:22 -0800193 void pointSpan(Span span) override {
194 SkASSERT(!span.isEmpty());
herb755539f2016-02-29 12:58:35 -0800195 SkPoint start; SkScalar length; int count;
196 std::tie(start, length, count) = span;
herb86a6c6d2016-07-22 14:06:27 -0700197
198 if (span.count() == 1) {
199 // DANGER:
200 // The explicit casts from float to Sk4f are not usually necessary, but are here to
201 // work around an MSVC 2015u2 c++ code generation bug. This is tracked using skia bug
202 // 5566.
203 this->pointListFew(1, Sk4f{span.startX()}, Sk4f{span.startY()});
204 return;
205 }
206
herb6eff52a2016-03-23 09:00:33 -0700207 SkScalar x = X(start);
208 SkScalar y = fYStrategy.tileY(Y(start));
209 Span yAdjustedSpan{{x, y}, length, count};
herb86a6c6d2016-07-22 14:06:27 -0700210
herb6eff52a2016-03-23 09:00:33 -0700211 if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) {
212 span_fallback(span, this);
213 }
herb3eb48952016-02-19 14:39:47 -0800214 }
215
herbc5eddd72016-02-17 19:50:05 -0800216private:
217 Next* const fNext;
herb6eff52a2016-03-23 09:00:33 -0700218 XStrategy fXStrategy;
219 YStrategy fYStrategy;
herbc5eddd72016-02-17 19:50:05 -0800220};
221
herb86a6c6d2016-07-22 14:06:27 -0700222template <typename XStrategy, typename Next>
herb6eff52a2016-03-23 09:00:33 -0700223void choose_tiler_ymode(
224 SkShader::TileMode yMode, SkFilterQuality filterQuality, SkISize dimensions,
herb86a6c6d2016-07-22 14:06:27 -0700225 Next* next,
herb6eff52a2016-03-23 09:00:33 -0700226 SkLinearBitmapPipeline::TileStage* tileStage) {
227 switch (yMode) {
herb86a6c6d2016-07-22 14:06:27 -0700228 case SkShader::kClamp_TileMode: {
229 using Tiler = CombinedTileStage<XStrategy, YClampStrategy, Next>;
230 tileStage->initStage<Tiler>(next, dimensions);
herb6eff52a2016-03-23 09:00:33 -0700231 break;
herb86a6c6d2016-07-22 14:06:27 -0700232 }
233 case SkShader::kRepeat_TileMode: {
234 using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, Next>;
235 tileStage->initStage<Tiler>(next, dimensions);
herb6eff52a2016-03-23 09:00:33 -0700236 break;
herb86a6c6d2016-07-22 14:06:27 -0700237 }
238 case SkShader::kMirror_TileMode: {
239 using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, Next>;
240 tileStage->initStage<Tiler>(next, dimensions);
herb6eff52a2016-03-23 09:00:33 -0700241 break;
herb86a6c6d2016-07-22 14:06:27 -0700242 }
herb6eff52a2016-03-23 09:00:33 -0700243 }
244};
245
246static SkLinearBitmapPipeline::PointProcessorInterface* choose_tiler(
herb308d9882016-03-29 14:48:44 -0700247 SkLinearBitmapPipeline::SampleProcessorInterface* next,
herb6eff52a2016-03-23 09:00:33 -0700248 SkISize dimensions,
249 SkShader::TileMode xMode,
250 SkShader::TileMode yMode,
251 SkFilterQuality filterQuality,
herb303c9792016-04-07 07:56:12 -0700252 SkScalar dx,
253 SkLinearBitmapPipeline::TileStage* tileStage)
254{
herb6eff52a2016-03-23 09:00:33 -0700255 switch (xMode) {
256 case SkShader::kClamp_TileMode:
257 choose_tiler_ymode<XClampStrategy>(yMode, filterQuality, dimensions, next, tileStage);
258 break;
259 case SkShader::kRepeat_TileMode:
herb303c9792016-04-07 07:56:12 -0700260 if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) {
261 choose_tiler_ymode<XRepeatUnitScaleStrategy>(
262 yMode, kNone_SkFilterQuality, dimensions, next, tileStage);
263 } else {
264 choose_tiler_ymode<XRepeatStrategy>(
265 yMode, filterQuality, dimensions, next, tileStage);
266 }
herb6eff52a2016-03-23 09:00:33 -0700267 break;
268 case SkShader::kMirror_TileMode:
269 choose_tiler_ymode<XMirrorStrategy>(yMode, filterQuality, dimensions, next, tileStage);
270 break;
herb7dd5db42016-03-01 13:54:08 -0800271 }
272
herb6eff52a2016-03-23 09:00:33 -0700273 return tileStage->get();
274}
275
herb6eff52a2016-03-23 09:00:33 -0700276////////////////////////////////////////////////////////////////////////////////////////////////////
herbd5f2e2e2016-04-14 11:16:44 -0700277// Specialized Samplers
278
herb6a5d7132016-04-08 06:49:59 -0700279// RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination
280// are the same format and do not need in transformations in pixel space. Therefore, there is no
281// need to convert them to HiFi pixel format.
herb871a0482016-05-03 08:11:52 -0700282class RGBA8888UnitRepeatSrc final : public SkLinearBitmapPipeline::SampleProcessorInterface,
283 public SkLinearBitmapPipeline::DestinationInterface {
herb6a5d7132016-04-08 06:49:59 -0700284public:
herb871a0482016-05-03 08:11:52 -0700285 RGBA8888UnitRepeatSrc(const uint32_t* src, int32_t width)
herb6a5d7132016-04-08 06:49:59 -0700286 : fSrc{src}, fWidth{width} { }
287
mtkleine5fb9c82016-07-07 08:12:09 -0700288 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
herb6a5d7132016-04-08 06:49:59 -0700289 SkASSERT(fDest + n <= fEnd);
290 // At this point xs and ys should be >= 0, so trunc is the same as floor.
291 Sk4i iXs = SkNx_cast<int>(xs);
292 Sk4i iYs = SkNx_cast<int>(ys);
293
294 if (n >= 1) *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
295 if (n >= 2) *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
296 if (n >= 3) *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
297 }
298
mtkleine5fb9c82016-07-07 08:12:09 -0700299 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
herb6a5d7132016-04-08 06:49:59 -0700300 SkASSERT(fDest + 4 <= fEnd);
301 Sk4i iXs = SkNx_cast<int>(xs);
302 Sk4i iYs = SkNx_cast<int>(ys);
303 *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
304 *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
305 *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
306 *fDest++ = *this->pixelAddress(iXs[3], iYs[3]);
307 }
308
309 void pointSpan(Span span) override {
310 SkASSERT(fDest + span.count() <= fEnd);
herb5d4943c2016-04-26 08:15:27 -0700311 if (span.length() != 0.0f) {
312 int32_t x = SkScalarTruncToInt(span.startX());
313 int32_t y = SkScalarTruncToInt(span.startY());
314 const uint32_t* src = this->pixelAddress(x, y);
315 memmove(fDest, src, span.count() * sizeof(uint32_t));
316 fDest += span.count();
317 }
herb6a5d7132016-04-08 06:49:59 -0700318 }
319
320 void repeatSpan(Span span, int32_t repeatCount) override {
321 SkASSERT(fDest + span.count() * repeatCount <= fEnd);
322
herb5d4943c2016-04-26 08:15:27 -0700323 int32_t x = SkScalarTruncToInt(span.startX());
324 int32_t y = SkScalarTruncToInt(span.startY());
herb6a5d7132016-04-08 06:49:59 -0700325 const uint32_t* src = this->pixelAddress(x, y);
326 uint32_t* dest = fDest;
327 while (repeatCount --> 0) {
328 memmove(dest, src, span.count() * sizeof(uint32_t));
329 dest += span.count();
330 }
331 fDest = dest;
332 }
333
herb6a5d7132016-04-08 06:49:59 -0700334 void setDestination(void* dst, int count) override {
335 fDest = static_cast<uint32_t*>(dst);
336 fEnd = fDest + count;
337 }
338
339private:
340 const uint32_t* pixelAddress(int32_t x, int32_t y) {
341 return &fSrc[fWidth * y + x];
342 }
343 const uint32_t* const fSrc;
344 const int32_t fWidth;
345 uint32_t* fDest;
346 uint32_t* fEnd;
347};
348
herb871a0482016-05-03 08:11:52 -0700349// RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination
350// are the same format and do not need in transformations in pixel space. Therefore, there is no
351// need to convert them to HiFi pixel format.
352class RGBA8888UnitRepeatSrcOver final : public SkLinearBitmapPipeline::SampleProcessorInterface,
353 public SkLinearBitmapPipeline::DestinationInterface {
354public:
355 RGBA8888UnitRepeatSrcOver(const uint32_t* src, int32_t width)
356 : fSrc{src}, fWidth{width} { }
357
mtkleine5fb9c82016-07-07 08:12:09 -0700358 void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
herb871a0482016-05-03 08:11:52 -0700359 SkASSERT(fDest + n <= fEnd);
360 // At this point xs and ys should be >= 0, so trunc is the same as floor.
361 Sk4i iXs = SkNx_cast<int>(xs);
362 Sk4i iYs = SkNx_cast<int>(ys);
363
364 if (n >= 1) blendPixelAt(iXs[0], iYs[0]);
365 if (n >= 2) blendPixelAt(iXs[1], iYs[1]);
366 if (n >= 3) blendPixelAt(iXs[2], iYs[2]);
367 }
368
mtkleine5fb9c82016-07-07 08:12:09 -0700369 void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
herb871a0482016-05-03 08:11:52 -0700370 SkASSERT(fDest + 4 <= fEnd);
371 Sk4i iXs = SkNx_cast<int>(xs);
372 Sk4i iYs = SkNx_cast<int>(ys);
373 blendPixelAt(iXs[0], iYs[0]);
374 blendPixelAt(iXs[1], iYs[1]);
375 blendPixelAt(iXs[2], iYs[2]);
376 blendPixelAt(iXs[3], iYs[3]);
377 }
378
379 void pointSpan(Span span) override {
380 if (span.length() != 0.0f) {
381 this->repeatSpan(span, 1);
382 }
383 }
384
385 void repeatSpan(Span span, int32_t repeatCount) override {
386 SkASSERT(fDest + span.count() * repeatCount <= fEnd);
387 SkASSERT(span.count() > 0);
388 SkASSERT(repeatCount > 0);
389
390 int32_t x = (int32_t)span.startX();
391 int32_t y = (int32_t)span.startY();
392 const uint32_t* beginSpan = this->pixelAddress(x, y);
393
394 SkOpts::srcover_srgb_srgb(fDest, beginSpan, span.count() * repeatCount, span.count());
395
396 fDest += span.count() * repeatCount;
397
398 SkASSERT(fDest <= fEnd);
399 }
400
herb871a0482016-05-03 08:11:52 -0700401 void setDestination(void* dst, int count) override {
402 SkASSERT(count > 0);
403 fDest = static_cast<uint32_t*>(dst);
404 fEnd = fDest + count;
405 }
406
407private:
408 const uint32_t* pixelAddress(int32_t x, int32_t y) {
409 return &fSrc[fWidth * y + x];
410 }
411
412 void blendPixelAt(int32_t x, int32_t y) {
413 const uint32_t* src = this->pixelAddress(x, y);
414 SkOpts::srcover_srgb_srgb(fDest, src, 1, 1);
415 fDest += 1;
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400416 }
herb871a0482016-05-03 08:11:52 -0700417
418 const uint32_t* const fSrc;
419 const int32_t fWidth;
420 uint32_t* fDest;
421 uint32_t* fEnd;
422};
423
herb9e0efe52016-04-08 13:25:28 -0700424using Blender = SkLinearBitmapPipeline::BlendProcessorInterface;
herb6eff52a2016-03-23 09:00:33 -0700425
herb00dd4532016-07-11 10:33:37 -0700426template <SkColorType colorType>
427static SkLinearBitmapPipeline::PixelAccessorInterface* choose_specific_accessor(
428 const SkPixmap& srcPixmap, SkLinearBitmapPipeline::Accessor* accessor)
herb670f01f2016-05-13 10:04:46 -0700429{
reeddabe5d32016-06-21 10:28:14 -0700430 if (srcPixmap.info().gammaCloseToSRGB()) {
herb00dd4532016-07-11 10:33:37 -0700431 using PA = PixelAccessor<colorType, kSRGB_SkGammaType>;
432 accessor->init<PA>(srcPixmap);
433 return accessor->get();
herb670f01f2016-05-13 10:04:46 -0700434 } else {
herb00dd4532016-07-11 10:33:37 -0700435 using PA = PixelAccessor<colorType, kLinear_SkGammaType>;
436 accessor->init<PA>(srcPixmap);
437 return accessor->get();
herb670f01f2016-05-13 10:04:46 -0700438 }
439}
440
herb86a6c6d2016-07-22 14:06:27 -0700441static SkLinearBitmapPipeline::PixelAccessorInterface* choose_pixel_accessor(
herbed545042016-02-18 13:55:02 -0800442 const SkPixmap& srcPixmap,
herb670f01f2016-05-13 10:04:46 -0700443 const SkColor A8TintColor,
herb00dd4532016-07-11 10:33:37 -0700444 SkLinearBitmapPipeline::Accessor* accessor)
herb670f01f2016-05-13 10:04:46 -0700445{
herbed545042016-02-18 13:55:02 -0800446 const SkImageInfo& imageInfo = srcPixmap.info();
herb00dd4532016-07-11 10:33:37 -0700447
448 SkLinearBitmapPipeline::PixelAccessorInterface* pixelAccessor = nullptr;
herbfeec8782016-02-17 10:00:07 -0800449 switch (imageInfo.colorType()) {
herb670f01f2016-05-13 10:04:46 -0700450 case kAlpha_8_SkColorType: {
herb00dd4532016-07-11 10:33:37 -0700451 using PA = PixelAccessor<kAlpha_8_SkColorType, kLinear_SkGammaType>;
452 accessor->init<PA>(srcPixmap, A8TintColor);
453 pixelAccessor = accessor->get();
herbfd5a2602016-03-01 07:01:23 -0800454 }
455 break;
herb670f01f2016-05-13 10:04:46 -0700456 case kARGB_4444_SkColorType:
herb00dd4532016-07-11 10:33:37 -0700457 pixelAccessor = choose_specific_accessor<kARGB_4444_SkColorType>(srcPixmap, accessor);
herb670f01f2016-05-13 10:04:46 -0700458 break;
459 case kRGB_565_SkColorType:
herb00dd4532016-07-11 10:33:37 -0700460 pixelAccessor = choose_specific_accessor<kRGB_565_SkColorType>(srcPixmap, accessor);
herb670f01f2016-05-13 10:04:46 -0700461 break;
462 case kRGBA_8888_SkColorType:
herb00dd4532016-07-11 10:33:37 -0700463 pixelAccessor = choose_specific_accessor<kRGBA_8888_SkColorType>(srcPixmap, accessor);
herb670f01f2016-05-13 10:04:46 -0700464 break;
herbfd5a2602016-03-01 07:01:23 -0800465 case kBGRA_8888_SkColorType:
herb00dd4532016-07-11 10:33:37 -0700466 pixelAccessor = choose_specific_accessor<kBGRA_8888_SkColorType>(srcPixmap, accessor);
herbfeec8782016-02-17 10:00:07 -0800467 break;
herb222f8ff2016-03-23 15:14:23 -0700468 case kIndex_8_SkColorType:
herb00dd4532016-07-11 10:33:37 -0700469 pixelAccessor = choose_specific_accessor<kIndex_8_SkColorType>(srcPixmap, accessor);
herb670f01f2016-05-13 10:04:46 -0700470 break;
471 case kGray_8_SkColorType:
herb00dd4532016-07-11 10:33:37 -0700472 pixelAccessor = choose_specific_accessor<kGray_8_SkColorType>(srcPixmap, accessor);
herb222f8ff2016-03-23 15:14:23 -0700473 break;
herb15332a82016-05-12 11:37:00 -0700474 case kRGBA_F16_SkColorType: {
herb00dd4532016-07-11 10:33:37 -0700475 using PA = PixelAccessor<kRGBA_F16_SkColorType, kLinear_SkGammaType>;
476 accessor->init<PA>(srcPixmap);
477 pixelAccessor = accessor->get();
herb15332a82016-05-12 11:37:00 -0700478 }
herbd5f2e2e2016-04-14 11:16:44 -0700479 break;
herbfeec8782016-02-17 10:00:07 -0800480 default:
481 SkFAIL("Not implemented. Unsupported src");
482 break;
483 }
herb00dd4532016-07-11 10:33:37 -0700484
herb86a6c6d2016-07-22 14:06:27 -0700485 return pixelAccessor;
herbfeec8782016-02-17 10:00:07 -0800486}
487
herb308d9882016-03-29 14:48:44 -0700488SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler(
herb9e0efe52016-04-08 13:25:28 -0700489 Blender* next,
herb6eff52a2016-03-23 09:00:33 -0700490 SkFilterQuality filterQuality,
herb86a6c6d2016-07-22 14:06:27 -0700491 SkShader::TileMode xTile, SkShader::TileMode yTile,
herb6eff52a2016-03-23 09:00:33 -0700492 const SkPixmap& srcPixmap,
herb670f01f2016-05-13 10:04:46 -0700493 const SkColor A8TintColor,
herb00dd4532016-07-11 10:33:37 -0700494 SkLinearBitmapPipeline::SampleStage* sampleStage,
495 SkLinearBitmapPipeline::Accessor* accessor) {
496 const SkImageInfo& imageInfo = srcPixmap.info();
herb86a6c6d2016-07-22 14:06:27 -0700497 SkISize dimensions = imageInfo.dimensions();
herb00dd4532016-07-11 10:33:37 -0700498
499 // Special case samplers with fully expanded templates
500 if (imageInfo.gammaCloseToSRGB()) {
501 if (filterQuality == kNone_SkFilterQuality) {
502 switch (imageInfo.colorType()) {
503 case kN32_SkColorType: {
504 using S =
505 NearestNeighborSampler<
506 PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
507 sampleStage->initStage<S>(next, srcPixmap);
508 return sampleStage->get();
509 }
510 case kIndex_8_SkColorType: {
511 using S =
512 NearestNeighborSampler<
513 PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
514 sampleStage->initStage<S>(next, srcPixmap);
515 return sampleStage->get();
516 }
517 default:
518 break;
519 }
520 } else {
521 switch (imageInfo.colorType()) {
522 case kN32_SkColorType: {
523 using S =
524 BilerpSampler<
525 PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
herb86a6c6d2016-07-22 14:06:27 -0700526 sampleStage->initStage<S>(next, dimensions, xTile, yTile, srcPixmap);
herb00dd4532016-07-11 10:33:37 -0700527 return sampleStage->get();
528 }
529 case kIndex_8_SkColorType: {
530 using S =
531 BilerpSampler<
532 PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
herb86a6c6d2016-07-22 14:06:27 -0700533 sampleStage->initStage<S>(next, dimensions, xTile, yTile, srcPixmap);
herb00dd4532016-07-11 10:33:37 -0700534 return sampleStage->get();
535 }
536 default:
537 break;
538 }
539 }
540 }
541
herb86a6c6d2016-07-22 14:06:27 -0700542 auto pixelAccessor = choose_pixel_accessor(srcPixmap, A8TintColor, accessor);
herb00dd4532016-07-11 10:33:37 -0700543 // General cases.
herb6eff52a2016-03-23 09:00:33 -0700544 if (filterQuality == kNone_SkFilterQuality) {
herb86a6c6d2016-07-22 14:06:27 -0700545 using S = NearestNeighborSampler<PixelAccessorShim, Blender>;
546 sampleStage->initStage<S>(next, pixelAccessor);
herb6eff52a2016-03-23 09:00:33 -0700547 } else {
herb86a6c6d2016-07-22 14:06:27 -0700548 using S = BilerpSampler<PixelAccessorShim, Blender>;
549 sampleStage->initStage<S>(next, dimensions, xTile, yTile, pixelAccessor);
herb6eff52a2016-03-23 09:00:33 -0700550 }
herb86a6c6d2016-07-22 14:06:27 -0700551 return sampleStage->get();
herb6eff52a2016-03-23 09:00:33 -0700552}
553
herb490d30f2016-03-04 10:39:14 -0800554////////////////////////////////////////////////////////////////////////////////////////////////////
herb9e0efe52016-04-08 13:25:28 -0700555// Pixel Blender Stage
herbfeec8782016-02-17 10:00:07 -0800556template <SkAlphaType alphaType>
herb9e0efe52016-04-08 13:25:28 -0700557class SrcFPPixel final : public SkLinearBitmapPipeline::BlendProcessorInterface {
herbfeec8782016-02-17 10:00:07 -0800558public:
herb9e0efe52016-04-08 13:25:28 -0700559 SrcFPPixel(float postAlpha) : fPostAlpha{postAlpha} { }
560 SrcFPPixel(const SrcFPPixel& Blender) : fPostAlpha(Blender.fPostAlpha) {}
mtkleine5fb9c82016-07-07 08:12:09 -0700561 void SK_VECTORCALL blendPixel(Sk4f pixel) override {
herb303c9792016-04-07 07:56:12 -0700562 SkASSERT(fDst + 1 <= fEnd );
herb86a6c6d2016-07-22 14:06:27 -0700563 this->srcPixel(fDst, pixel, 0);
herbfeec8782016-02-17 10:00:07 -0800564 fDst += 1;
565 }
566
mtkleine5fb9c82016-07-07 08:12:09 -0700567 void SK_VECTORCALL blend4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
herb303c9792016-04-07 07:56:12 -0700568 SkASSERT(fDst + 4 <= fEnd);
herbfeec8782016-02-17 10:00:07 -0800569 SkPM4f* dst = fDst;
herb86a6c6d2016-07-22 14:06:27 -0700570 this->srcPixel(dst, p0, 0);
571 this->srcPixel(dst, p1, 1);
572 this->srcPixel(dst, p2, 2);
573 this->srcPixel(dst, p3, 3);
herbfeec8782016-02-17 10:00:07 -0800574 fDst += 4;
575 }
576
herb303c9792016-04-07 07:56:12 -0700577 void setDestination(void* dst, int count) override {
578 fDst = static_cast<SkPM4f*>(dst);
579 fEnd = fDst + count;
herbfeec8782016-02-17 10:00:07 -0800580 }
581
582private:
herb86a6c6d2016-07-22 14:06:27 -0700583 void SK_VECTORCALL srcPixel(SkPM4f* dst, Sk4f pixel, int index) {
584 check_pixel(pixel);
585
herbfeec8782016-02-17 10:00:07 -0800586 Sk4f newPixel = pixel;
587 if (alphaType == kUnpremul_SkAlphaType) {
588 newPixel = Premultiply(pixel);
589 }
herb6eff52a2016-03-23 09:00:33 -0700590 newPixel = newPixel * fPostAlpha;
herbfeec8782016-02-17 10:00:07 -0800591 newPixel.store(dst + index);
592 }
mtkleine5fb9c82016-07-07 08:12:09 -0700593 static Sk4f SK_VECTORCALL Premultiply(Sk4f pixel) {
herbfeec8782016-02-17 10:00:07 -0800594 float alpha = pixel[3];
595 return pixel * Sk4f{alpha, alpha, alpha, 1.0f};
596 }
597
598 SkPM4f* fDst;
herb303c9792016-04-07 07:56:12 -0700599 SkPM4f* fEnd;
herb6eff52a2016-03-23 09:00:33 -0700600 Sk4f fPostAlpha;
herbfeec8782016-02-17 10:00:07 -0800601};
602
herbd5f2e2e2016-04-14 11:16:44 -0700603static SkLinearBitmapPipeline::BlendProcessorInterface* choose_blender_for_shading(
herbfeec8782016-02-17 10:00:07 -0800604 SkAlphaType alphaType,
herb6eff52a2016-03-23 09:00:33 -0700605 float postAlpha,
herb9e0efe52016-04-08 13:25:28 -0700606 SkLinearBitmapPipeline::BlenderStage* blenderStage) {
herbfeec8782016-02-17 10:00:07 -0800607 if (alphaType == kUnpremul_SkAlphaType) {
herb9e0efe52016-04-08 13:25:28 -0700608 blenderStage->initSink<SrcFPPixel<kUnpremul_SkAlphaType>>(postAlpha);
herbfeec8782016-02-17 10:00:07 -0800609 } else {
610 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
herb9e0efe52016-04-08 13:25:28 -0700611 blenderStage->initSink<SrcFPPixel<kPremul_SkAlphaType>>(postAlpha);
herbfeec8782016-02-17 10:00:07 -0800612 }
herb9e0efe52016-04-08 13:25:28 -0700613 return blenderStage->get();
herbfeec8782016-02-17 10:00:07 -0800614}
herbd5f2e2e2016-04-14 11:16:44 -0700615
herba856e252016-02-22 14:48:21 -0800616} // namespace
617
herb490d30f2016-03-04 10:39:14 -0800618////////////////////////////////////////////////////////////////////////////////////////////////////
herb9e0efe52016-04-08 13:25:28 -0700619// SkLinearBitmapPipeline
herba856e252016-02-22 14:48:21 -0800620SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {}
herbfeec8782016-02-17 10:00:07 -0800621
622SkLinearBitmapPipeline::SkLinearBitmapPipeline(
623 const SkMatrix& inverse,
herbc5eddd72016-02-17 19:50:05 -0800624 SkFilterQuality filterQuality,
herbfeec8782016-02-17 10:00:07 -0800625 SkShader::TileMode xTile, SkShader::TileMode yTile,
herb670f01f2016-05-13 10:04:46 -0700626 SkColor paintColor,
herb303c9792016-04-07 07:56:12 -0700627 const SkPixmap& srcPixmap)
628{
herb6eff52a2016-03-23 09:00:33 -0700629 SkISize dimensions = srcPixmap.info().dimensions();
herbed545042016-02-18 13:55:02 -0800630 const SkImageInfo& srcImageInfo = srcPixmap.info();
herbfeec8782016-02-17 10:00:07 -0800631
herb6eff52a2016-03-23 09:00:33 -0700632 SkMatrix adjustedInverse = inverse;
633 if (filterQuality == kNone_SkFilterQuality) {
634 if (inverse.getScaleX() >= 0.0f) {
635 adjustedInverse.setTranslateX(
636 nextafterf(inverse.getTranslateX(), std::floor(inverse.getTranslateX())));
637 }
638 if (inverse.getScaleY() >= 0.0f) {
639 adjustedInverse.setTranslateY(
640 nextafterf(inverse.getTranslateY(), std::floor(inverse.getTranslateY())));
641 }
642 }
643
herb303c9792016-04-07 07:56:12 -0700644 SkScalar dx = adjustedInverse.getScaleX();
645
herb222f8ff2016-03-23 15:14:23 -0700646 // If it is an index 8 color type, the sampler converts to unpremul for better fidelity.
647 SkAlphaType alphaType = srcImageInfo.alphaType();
648 if (srcPixmap.colorType() == kIndex_8_SkColorType) {
649 alphaType = kUnpremul_SkAlphaType;
650 }
651
herb670f01f2016-05-13 10:04:46 -0700652 float postAlpha = SkColorGetA(paintColor) * (1.0f / 255.0f);
herbfeec8782016-02-17 10:00:07 -0800653 // As the stages are built, the chooser function may skip a stage. For example, with the
654 // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
herbd5f2e2e2016-04-14 11:16:44 -0700655 auto blenderStage = choose_blender_for_shading(alphaType, postAlpha, &fBlenderStage);
herb670f01f2016-05-13 10:04:46 -0700656 auto samplerStage = choose_pixel_sampler(
herb86a6c6d2016-07-22 14:06:27 -0700657 blenderStage, filterQuality, xTile, yTile,
658 srcPixmap, paintColor, &fSampleStage, &fAccessor);
herb9e0efe52016-04-08 13:25:28 -0700659 auto tilerStage = choose_tiler(samplerStage, dimensions, xTile, yTile,
660 filterQuality, dx, &fTileStage);
661 fFirstStage = choose_matrix(tilerStage, adjustedInverse, &fMatrixStage);
662 fLastStage = blenderStage;
herbfeec8782016-02-17 10:00:07 -0800663}
664
herb69076fe2016-04-12 14:07:59 -0700665bool SkLinearBitmapPipeline::ClonePipelineForBlitting(
herb57a69dc2016-05-19 14:19:23 -0700666 SkEmbeddableLinearPipeline* pipelineStorage,
herb69076fe2016-04-12 14:07:59 -0700667 const SkLinearBitmapPipeline& pipeline,
668 SkMatrix::TypeMask matrixMask,
669 SkShader::TileMode xTileMode,
670 SkShader::TileMode yTileMode,
671 SkFilterQuality filterQuality,
672 const SkPixmap& srcPixmap,
673 float finalAlpha,
674 SkXfermode::Mode xferMode,
675 const SkImageInfo& dstInfo)
676{
herb871a0482016-05-03 08:11:52 -0700677 if (xferMode == SkXfermode::kSrcOver_Mode
678 && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) {
679 xferMode = SkXfermode::kSrc_Mode;
680 }
681
herb69076fe2016-04-12 14:07:59 -0700682 if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return false; }
683 if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return false; }
684 if (finalAlpha != 1.0f) { return false; }
685 if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType
686 || dstInfo.colorType() != kRGBA_8888_SkColorType) { return false; }
687
reeddabe5d32016-06-21 10:28:14 -0700688 if (!srcPixmap.info().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) {
689 return false;
690 }
herb69076fe2016-04-12 14:07:59 -0700691
herb871a0482016-05-03 08:11:52 -0700692 if (xferMode != SkXfermode::kSrc_Mode && xferMode != SkXfermode::kSrcOver_Mode) {
herb69076fe2016-04-12 14:07:59 -0700693 return false;
694 }
695
herb57a69dc2016-05-19 14:19:23 -0700696 pipelineStorage->init(pipeline, srcPixmap, xferMode, dstInfo);
herb69076fe2016-04-12 14:07:59 -0700697
698 return true;
699}
700
701SkLinearBitmapPipeline::SkLinearBitmapPipeline(
702 const SkLinearBitmapPipeline& pipeline,
703 const SkPixmap& srcPixmap,
704 SkXfermode::Mode mode,
705 const SkImageInfo& dstInfo)
706{
herb871a0482016-05-03 08:11:52 -0700707 SkASSERT(mode == SkXfermode::kSrc_Mode || mode == SkXfermode::kSrcOver_Mode);
herb69076fe2016-04-12 14:07:59 -0700708 SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType()
709 && srcPixmap.info().colorType() == kRGBA_8888_SkColorType);
710
herb871a0482016-05-03 08:11:52 -0700711 if (mode == SkXfermode::kSrc_Mode) {
712 fSampleStage.initSink<RGBA8888UnitRepeatSrc>(
713 srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
714 fLastStage = fSampleStage.getInterface<DestinationInterface, RGBA8888UnitRepeatSrc>();
715 } else {
716 fSampleStage.initSink<RGBA8888UnitRepeatSrcOver>(
717 srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
718 fLastStage = fSampleStage.getInterface<DestinationInterface, RGBA8888UnitRepeatSrcOver>();
719 }
720
herb69076fe2016-04-12 14:07:59 -0700721 auto sampleStage = fSampleStage.get();
722 auto tilerStage = pipeline.fTileStage.cloneStageTo(sampleStage, &fTileStage);
723 tilerStage = (tilerStage != nullptr) ? tilerStage : sampleStage;
724 auto matrixStage = pipeline.fMatrixStage.cloneStageTo(tilerStage, &fMatrixStage);
725 matrixStage = (matrixStage != nullptr) ? matrixStage : tilerStage;
726 fFirstStage = matrixStage;
herb69076fe2016-04-12 14:07:59 -0700727}
728
herbfeec8782016-02-17 10:00:07 -0800729void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
herb3eb48952016-02-19 14:39:47 -0800730 SkASSERT(count > 0);
herb69076fe2016-04-12 14:07:59 -0700731 this->blitSpan(x, y, dst, count);
732}
733
734void SkLinearBitmapPipeline::blitSpan(int x, int y, void* dst, int count) {
735 SkASSERT(count > 0);
herb6a5d7132016-04-08 06:49:59 -0700736 fLastStage->setDestination(dst, count);
737
herb94665712016-02-29 07:53:22 -0800738 // The count and length arguments start out in a precise relation in order to keep the
739 // math correct through the different stages. Count is the number of pixel to produce.
740 // Since the code samples at pixel centers, length is the distance from the center of the
741 // first pixel to the center of the last pixel. This implies that length is count-1.
herb6eff52a2016-03-23 09:00:33 -0700742 fFirstStage->pointSpan(Span{{x + 0.5f, y + 0.5f}, count - 1.0f, count});
herbfeec8782016-02-17 10:00:07 -0800743}