blob: 169bb9f74b83586cb15396841468c896e70a1a0a [file] [log] [blame]
mtklein9a5c47f2016-07-22 11:05:04 -07001/*
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 "SkBlitter.h"
9#include "SkColor.h"
10#include "SkColorFilter.h"
11#include "SkPM4f.h"
12#include "SkPM4fPriv.h"
13#include "SkRasterPipeline.h"
14#include "SkShader.h"
15#include "SkSRGB.h"
16#include "SkXfermode.h"
17
18
19class SkRasterPipelineBlitter : public SkBlitter {
20public:
21 static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkTBlitterAllocator*);
22
23 SkRasterPipelineBlitter(SkPixmap dst,
24 SkRasterPipeline shader,
25 SkRasterPipeline colorFilter,
26 SkRasterPipeline xfermode,
27 SkPM4f paintColor)
28 : fDst(dst)
29 , fShader(shader)
30 , fColorFilter(colorFilter)
31 , fXfermode(xfermode)
32 , fPaintColor(paintColor)
33 {}
34
35 void blitH (int x, int y, int w) override;
36 void blitAntiH(int x, int y, const SkAlpha[], const int16_t[]) override;
37 void blitMask (const SkMask&, const SkIRect& clip) override;
38
39 // TODO: The default implementations of the other blits look fine,
40 // but some of them like blitV could probably benefit from custom
41 // blits using something like a SkRasterPipeline::runFew() method.
42
43private:
mtklein8e4373f2016-07-22 14:20:27 -070044 void append_load_d(SkRasterPipeline*, const void*) const;
45 void append_store (SkRasterPipeline*, void*) const;
46
mtklein9a5c47f2016-07-22 11:05:04 -070047 SkPixmap fDst;
48 SkRasterPipeline fShader, fColorFilter, fXfermode;
49 SkPM4f fPaintColor;
50
51 typedef SkBlitter INHERITED;
52};
53
54SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
55 const SkPaint& paint,
56 SkTBlitterAllocator* alloc) {
57 return SkRasterPipelineBlitter::Create(dst, paint, alloc);
58}
59
60
61// The default shader produces a constant color (from the SkPaint).
62static void SK_VECTORCALL constant_color(SkRasterPipeline::Stage* st, size_t x,
63 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
64 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
65 auto color = st->ctx<const SkPM4f*>();
66 r = color->r();
67 g = color->g();
68 b = color->b();
69 a = color->a();
70 st->next(x, r,g,b,a, dr,dg,db,da);
71}
72
73// The default transfer mode is srcover, s' = s + d*(1-sa).
74static void SK_VECTORCALL srcover(SkRasterPipeline::Stage* st, size_t x,
75 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
76 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
77 auto A = 1.0f - a;
78 r += dr*A;
79 g += dg*A;
80 b += db*A;
81 a += da*A;
82 st->next(x, r,g,b,a, dr,dg,db,da);
83}
84
85static Sk4f lerp(const Sk4f& from, const Sk4f& to, const Sk4f& cov) {
86 return from + (to-from)*cov;
87}
88
89// s' = d(1-c) + sc, for a constant c.
90static void SK_VECTORCALL lerp_constant_float(SkRasterPipeline::Stage* st, size_t x,
91 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
92 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
93 Sk4f c = *st->ctx<const float*>();
94
95 r = lerp(dr, r, c);
96 g = lerp(dg, g, c);
97 b = lerp(db, b, c);
98 a = lerp(da, a, c);
99 st->next(x, r,g,b,a, dr,dg,db,da);
100}
101
102// s' = d(1-c) + sc, 4 pixels at a time for 8-bit coverage.
103static void SK_VECTORCALL lerp_a8(SkRasterPipeline::Stage* st, size_t x,
104 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
105 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
106 auto ptr = st->ctx<const uint8_t*>() + x;
107 Sk4f c = SkNx_cast<float>(Sk4b::Load(ptr)) * (1/255.0f);
108
109 r = lerp(dr, r, c);
110 g = lerp(dg, g, c);
111 b = lerp(db, b, c);
112 a = lerp(da, a, c);
113 st->next(x, r,g,b,a, dr,dg,db,da);
114}
115
116// Tail variant of lerp_a8() handling 1 pixel at a time.
117static void SK_VECTORCALL lerp_a8_1(SkRasterPipeline::Stage* st, size_t x,
118 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
119 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
120 auto ptr = st->ctx<const uint8_t*>() + x;
121 Sk4f c = *ptr * (1/255.0f);
122
123 r = lerp(dr, r, c);
124 g = lerp(dg, g, c);
125 b = lerp(db, b, c);
126 a = lerp(da, a, c);
127 st->next(x, r,g,b,a, dr,dg,db,da);
128}
129
mtklein8e4373f2016-07-22 14:20:27 -0700130static void from_565(const Sk4h& _565, Sk4f* r, Sk4f* g, Sk4f* b) {
131 Sk4i _32_bit = SkNx_cast<int>(_565);
mtklein9a5c47f2016-07-22 11:05:04 -0700132
133 *r = SkNx_cast<float>(_32_bit & SK_R16_MASK_IN_PLACE) * (1.0f / SK_R16_MASK_IN_PLACE);
134 *g = SkNx_cast<float>(_32_bit & SK_G16_MASK_IN_PLACE) * (1.0f / SK_G16_MASK_IN_PLACE);
135 *b = SkNx_cast<float>(_32_bit & SK_B16_MASK_IN_PLACE) * (1.0f / SK_B16_MASK_IN_PLACE);
136}
137
mtklein8e4373f2016-07-22 14:20:27 -0700138static Sk4h to_565(const Sk4f& r, const Sk4f& g, const Sk4f& b) {
139 return SkNx_cast<uint16_t>( Sk4f_round(r * SK_R16_MASK) << SK_R16_SHIFT
140 | Sk4f_round(g * SK_G16_MASK) << SK_G16_SHIFT
141 | Sk4f_round(b * SK_B16_MASK) << SK_B16_SHIFT);
142}
143
mtklein9a5c47f2016-07-22 11:05:04 -0700144// s' = d(1-c) + sc, 4 pixels at a time for 565 coverage.
145static void SK_VECTORCALL lerp_lcd16(SkRasterPipeline::Stage* st, size_t x,
146 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
147 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
148 auto ptr = st->ctx<const uint16_t*>() + x;
149 Sk4f cr, cg, cb;
mtklein8e4373f2016-07-22 14:20:27 -0700150 from_565(Sk4h::Load(ptr), &cr, &cg, &cb);
mtklein9a5c47f2016-07-22 11:05:04 -0700151
152 r = lerp(dr, r, cr);
153 g = lerp(dg, g, cg);
154 b = lerp(db, b, cb);
155 a = 1.0f;
156 st->next(x, r,g,b,a, dr,dg,db,da);
157}
158
159// Tail variant of lerp_lcd16() handling 1 pixel at a time.
160static void SK_VECTORCALL lerp_lcd16_1(SkRasterPipeline::Stage* st, size_t x,
161 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
162 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
163 auto ptr = st->ctx<const uint16_t*>() + x;
164 Sk4f cr, cg, cb;
mtklein8e4373f2016-07-22 14:20:27 -0700165 from_565({*ptr,0,0,0}, &cr, &cg, &cb);
mtklein9a5c47f2016-07-22 11:05:04 -0700166
167 r = lerp(dr, r, cr);
168 g = lerp(dg, g, cg);
169 b = lerp(db, b, cb);
170 a = 1.0f;
171 st->next(x, r,g,b,a, dr,dg,db,da);
172}
173
mtklein8e4373f2016-07-22 14:20:27 -0700174// Load 4 565 dst pixels.
175static void SK_VECTORCALL load_d_565(SkRasterPipeline::Stage* st, size_t x,
176 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
177 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
178 auto ptr = st->ctx<const uint16_t*>() + x;
179
180 from_565(Sk4h::Load(ptr), &dr,&dg,&db);
181 da = 1.0f;
182 st->next(x, r,g,b,a, dr,dg,db,da);
183}
184
185// Load 1 565 dst pixel.
186static void SK_VECTORCALL load_d_565_1(SkRasterPipeline::Stage* st, size_t x,
187 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
188 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
189 auto ptr = st->ctx<const uint16_t*>() + x;
190
191 from_565({*ptr,0,0,0}, &dr,&dg,&db);
192 da = 1.0f;
193 st->next(x, r,g,b,a, dr,dg,db,da);
194}
195
196// Store 4 565 pixels.
197static void SK_VECTORCALL store_565(SkRasterPipeline::Stage* st, size_t x,
198 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
199 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
200 auto ptr = st->ctx<uint16_t*>() + x;
201 to_565(r,g,b).store(ptr);
202}
203
204// Store 1 565 pixel.
205static void SK_VECTORCALL store_565_1(SkRasterPipeline::Stage* st, size_t x,
206 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
207 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
208 auto ptr = st->ctx<uint16_t*>() + x;
209 *ptr = to_565(r,g,b)[0];
210}
211
mtklein9a5c47f2016-07-22 11:05:04 -0700212// Load 4 8-bit sRGB pixels from SkPMColor order to RGBA.
213static void SK_VECTORCALL load_d_srgb(SkRasterPipeline::Stage* st, size_t x,
214 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
215 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
216 auto ptr = st->ctx<const uint32_t*>() + x;
217
218 dr = { sk_linear_from_srgb[(ptr[0] >> SK_R32_SHIFT) & 0xff],
219 sk_linear_from_srgb[(ptr[1] >> SK_R32_SHIFT) & 0xff],
220 sk_linear_from_srgb[(ptr[2] >> SK_R32_SHIFT) & 0xff],
221 sk_linear_from_srgb[(ptr[3] >> SK_R32_SHIFT) & 0xff] };
222
223 dg = { sk_linear_from_srgb[(ptr[0] >> SK_G32_SHIFT) & 0xff],
224 sk_linear_from_srgb[(ptr[1] >> SK_G32_SHIFT) & 0xff],
225 sk_linear_from_srgb[(ptr[2] >> SK_G32_SHIFT) & 0xff],
226 sk_linear_from_srgb[(ptr[3] >> SK_G32_SHIFT) & 0xff] };
227
228 db = { sk_linear_from_srgb[(ptr[0] >> SK_B32_SHIFT) & 0xff],
229 sk_linear_from_srgb[(ptr[1] >> SK_B32_SHIFT) & 0xff],
230 sk_linear_from_srgb[(ptr[2] >> SK_B32_SHIFT) & 0xff],
231 sk_linear_from_srgb[(ptr[3] >> SK_B32_SHIFT) & 0xff] };
232
233 // TODO: this >> doesn't really need mask if we make it logical instead of arithmetic.
234 da = SkNx_cast<float>((Sk4i::Load(ptr) >> SK_A32_SHIFT) & 0xff) * (1/255.0f);
235
236 st->next(x, r,g,b,a, dr,dg,db,da);
237}
238
239// Tail variant of load_d_srgb() handling 1 pixel at a time.
240static void SK_VECTORCALL load_d_srgb_1(SkRasterPipeline::Stage* st, size_t x,
241 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
242 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
243 auto ptr = st->ctx<const uint32_t*>() + x;
244
245 dr = { sk_linear_from_srgb[(*ptr >> SK_R32_SHIFT) & 0xff], 0,0,0 };
246 dg = { sk_linear_from_srgb[(*ptr >> SK_G32_SHIFT) & 0xff], 0,0,0 };
247 db = { sk_linear_from_srgb[(*ptr >> SK_B32_SHIFT) & 0xff], 0,0,0 };
248 da = { (1/255.0f) * (*ptr >> SK_A32_SHIFT) , 0,0,0 };
249
250 st->next(x, r,g,b,a, dr,dg,db,da);
251}
252
253// Write out 4 pixels as 8-bit SkPMColor-order sRGB.
254static void SK_VECTORCALL store_srgb(SkRasterPipeline::Stage* st, size_t x,
255 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
256 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
257 auto dst = st->ctx<uint32_t*>() + x;
258 ( sk_linear_to_srgb(r) << SK_R32_SHIFT
259 | sk_linear_to_srgb(g) << SK_G32_SHIFT
260 | sk_linear_to_srgb(b) << SK_B32_SHIFT
261 | Sk4f_round(255.0f*a) << SK_A32_SHIFT).store(dst);
262}
263
264// Tail variant of store_srgb() handling 1 pixel at a time.
265static void SK_VECTORCALL store_srgb_1(SkRasterPipeline::Stage* st, size_t x,
266 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
267 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
268 auto dst = st->ctx<uint32_t*>() + x;
269 *dst = Sk4f_toS32(swizzle_rb_if_bgra({ r[0], g[0], b[0], a[0] }));
270}
271
mtklein8e4373f2016-07-22 14:20:27 -0700272static bool supported(const SkImageInfo& info) {
273 // TODO: f16, more?
274 switch (info.colorType()) {
275 case kN32_SkColorType: return info.gammaCloseToSRGB();
276 case kRGB_565_SkColorType: return true;
277 default: return false;
278 }
279}
mtklein9a5c47f2016-07-22 11:05:04 -0700280
281template <typename Effect>
282static bool append_effect_stages(const Effect* effect, SkRasterPipeline* pipeline) {
283 return !effect || effect->appendStages(pipeline);
284}
285
286
287SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
288 const SkPaint& paint,
289 SkTBlitterAllocator* alloc) {
mtklein8e4373f2016-07-22 14:20:27 -0700290 if (!supported(dst.info())) {
291 return nullptr;
mtklein9a5c47f2016-07-22 11:05:04 -0700292 }
293 if (paint.getShader()) {
294 return nullptr; // TODO: need to work out how shaders and their contexts work
295 }
296
297 SkRasterPipeline shader, colorFilter, xfermode;
298 if (!append_effect_stages(paint.getColorFilter(), &colorFilter) ||
299 !append_effect_stages(paint.getXfermode(), &xfermode )) {
300 return nullptr;
301 }
302
mtklein8e4373f2016-07-22 14:20:27 -0700303 uint32_t paintColor = paint.getColor();
304
305 SkColor4f color;
306 if (dst.info().colorSpace()) {
307 color = SkColor4f::FromColor(paintColor);
308 } else {
309 swizzle_rb(SkNx_cast<float>(Sk4b::Load(&paintColor)) * (1/255.0f)).store(&color);
310 }
311
mtklein9a5c47f2016-07-22 11:05:04 -0700312 auto blitter = alloc->createT<SkRasterPipelineBlitter>(
313 dst,
314 shader, colorFilter, xfermode,
mtklein8e4373f2016-07-22 14:20:27 -0700315 color.premul());
mtklein9a5c47f2016-07-22 11:05:04 -0700316
317 if (!paint.getShader()) {
318 blitter->fShader.append(constant_color, &blitter->fPaintColor);
319 }
320 if (!paint.getXfermode()) {
321 blitter->fXfermode.append(srcover);
322 }
323
324 return blitter;
325}
326
mtklein8e4373f2016-07-22 14:20:27 -0700327void SkRasterPipelineBlitter::append_load_d(SkRasterPipeline* p, const void* dst) const {
328 SkASSERT(supported(fDst.info()));
329
330 switch (fDst.info().colorType()) {
331 case kN32_SkColorType:
332 if (fDst.info().gammaCloseToSRGB()) {
333 p->append(load_d_srgb, load_d_srgb_1, dst);
334 }
335 break;
336 case kRGB_565_SkColorType:
337 p->append(load_d_565, load_d_565_1, dst);
338 break;
339 default: break;
340 }
341}
342
343void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p, void* dst) const {
344 SkASSERT(supported(fDst.info()));
345
346 switch (fDst.info().colorType()) {
347 case kN32_SkColorType:
348 if (fDst.info().gammaCloseToSRGB()) {
349 p->append(store_srgb, store_srgb_1, dst);
350 }
351 break;
352 case kRGB_565_SkColorType:
353 p->append(store_565, store_565_1, dst);
354 break;
355 default: break;
356 }
357}
358
mtklein9a5c47f2016-07-22 11:05:04 -0700359void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
360 auto dst = fDst.writable_addr(0,y);
361
362 SkRasterPipeline p;
363 p.extend(fShader);
364 p.extend(fColorFilter);
mtklein8e4373f2016-07-22 14:20:27 -0700365 this->append_load_d(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700366 p.extend(fXfermode);
mtklein8e4373f2016-07-22 14:20:27 -0700367 this->append_store(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700368
369 p.run(x, w);
370}
371
372void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
373 auto dst = fDst.writable_addr(0,y);
374 float coverage;
375
376 SkRasterPipeline p;
377 p.extend(fShader);
378 p.extend(fColorFilter);
mtklein8e4373f2016-07-22 14:20:27 -0700379 this->append_load_d(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700380 p.extend(fXfermode);
381 p.append(lerp_constant_float, &coverage);
mtklein8e4373f2016-07-22 14:20:27 -0700382 this->append_store(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700383
384 for (int16_t run = *runs; run > 0; run = *runs) {
385 coverage = *aa * (1/255.0f);
386 p.run(x, run);
387
388 x += run;
389 runs += run;
390 aa += run;
391 }
392}
393
394void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
395 if (mask.fFormat == SkMask::kBW_Format) {
396 // TODO: native BW masks?
397 return INHERITED::blitMask(mask, clip);
398 }
399
400 int x = clip.left();
401 for (int y = clip.top(); y < clip.bottom(); y++) {
402 auto dst = fDst.writable_addr(0,y);
403
404 SkRasterPipeline p;
405 p.extend(fShader);
406 p.extend(fColorFilter);
mtklein8e4373f2016-07-22 14:20:27 -0700407 this->append_load_d(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700408 p.extend(fXfermode);
409 switch (mask.fFormat) {
410 case SkMask::kA8_Format:
411 p.append(lerp_a8, lerp_a8_1, mask.getAddr8(x,y)-x);
412 break;
413 case SkMask::kLCD16_Format:
414 p.append(lerp_lcd16, lerp_lcd16_1, mask.getAddrLCD16(x,y)-x);
415 break;
416 default: break;
417 }
mtklein8e4373f2016-07-22 14:20:27 -0700418 this->append_store(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700419
420 p.run(x, clip.width());
421 }
422}