add a bulk shader path through SkRasterPipelineBlitter
[platform/upstream/libSkiaSharp.git] / src / core / SkRasterPipelineBlitter.cpp
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 "SkArenaAlloc.h"
9 #include "SkBlitter.h"
10 #include "SkBlendModePriv.h"
11 #include "SkColor.h"
12 #include "SkColorFilter.h"
13 #include "SkColorSpaceXformer.h"
14 #include "SkOpts.h"
15 #include "SkPM4f.h"
16 #include "SkPM4fPriv.h"
17 #include "SkRasterPipeline.h"
18 #include "SkShader.h"
19 #include "SkUtils.h"
20 #include "../jumper/SkJumper.h"
21
22 class SkRasterPipelineBlitter final : public SkBlitter {
23 public:
24     // This is our common entrypoint for creating the blitter once we've sorted out shaders.
25     static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkArenaAlloc*,
26                              const SkRasterPipeline& shaderPipeline, SkShader::Context* shaderCtx,
27                              bool is_opaque, bool is_constant, bool wants_dither);
28
29     SkRasterPipelineBlitter(SkPixmap dst,
30                             SkBlendMode blend,
31                             SkArenaAlloc* alloc,
32                             SkShader::Context* shaderCtx)
33         : fDst(dst)
34         , fBlend(blend)
35         , fAlloc(alloc)
36         , fShaderCtx(shaderCtx)
37         , fColorPipeline(alloc)
38     {}
39
40     void blitH    (int x, int y, int w)                            override;
41     void blitAntiH(int x, int y, const SkAlpha[], const int16_t[]) override;
42     void blitMask (const SkMask&, const SkIRect& clip)             override;
43
44     // TODO: The default implementations of the other blits look fine,
45     // but some of them like blitV could probably benefit from custom
46     // blits using something like a SkRasterPipeline::runFew() method.
47
48 private:
49     void append_load_d(SkRasterPipeline*) const;
50     void append_blend (SkRasterPipeline*) const;
51     void maybe_clamp  (SkRasterPipeline*) const;
52     void append_store (SkRasterPipeline*) const;
53
54     // If we have an SkShader::Context, use it to fill our shader buffer.
55     void maybe_shade(int x, int y, int w);
56
57     SkPixmap           fDst;
58     SkBlendMode        fBlend;
59     SkArenaAlloc*      fAlloc;
60     SkShader::Context* fShaderCtx;
61     SkRasterPipeline   fColorPipeline;
62
63     // We may be able to specialize blitH() into a memset.
64     bool     fCanMemsetInBlitH = false;
65     uint64_t fMemsetColor      = 0;     // Big enough for largest dst format, F16.
66
67     // Built lazily on first use.
68     std::function<void(size_t, size_t)> fBlitH,
69                                         fBlitAntiH,
70                                         fBlitMaskA8,
71                                         fBlitMaskLCD16;
72
73     // These values are pointed to by the blit pipelines above,
74     // which allows us to adjust them from call to call.
75     void*              fShaderOutput    = nullptr;
76     void*              fDstPtr          = nullptr;
77     const void*        fMaskPtr         = nullptr;
78     float              fCurrentCoverage = 0.0f;
79     int                fCurrentY        = 0;
80     SkJumper_DitherCtx fDitherCtx = { &fCurrentY, 0.0f };
81
82     std::vector<SkPM4f> fShaderBuffer;
83
84     typedef SkBlitter INHERITED;
85 };
86
87 SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
88                                          const SkPaint& paint,
89                                          const SkMatrix& ctm,
90                                          SkArenaAlloc* alloc) {
91     SkColorSpace* dstCS = dst.colorSpace();
92     auto paintColor = alloc->make<SkPM4f>(SkPM4f_from_SkColor(paint.getColor(), dstCS));
93     auto shader = paint.getShader();
94
95     SkRasterPipeline_<256> shaderPipeline;
96     if (!shader) {
97         // Having no shader makes things nice and easy... just use the paint color.
98         shaderPipeline.append(SkRasterPipeline::constant_color, paintColor);
99         bool is_opaque    = paintColor->a() == 1.0f,
100              is_constant  = true,
101              wants_dither = false;
102         return SkRasterPipelineBlitter::Create(dst, paint, alloc,
103                                                shaderPipeline, nullptr,
104                                                is_opaque, is_constant, wants_dither);
105     }
106
107     bool is_opaque    = shader->isOpaque() && paintColor->a() == 1.0f;
108     bool is_constant  = shader->isConstant();
109     bool wants_dither = shader->asAGradient(nullptr) >= SkShader::kLinear_GradientType;
110
111     // See if the shader can express itself by appending pipeline stages.
112     if (shader->appendStages(&shaderPipeline, dstCS, alloc, ctm, paint)) {
113         if (paintColor->a() != 1.0f) {
114             shaderPipeline.append(SkRasterPipeline::scale_1_float, &paintColor->fVec[SkPM4f::A]);
115         }
116         return SkRasterPipelineBlitter::Create(dst, paint, alloc,
117                                                shaderPipeline, nullptr,
118                                                is_opaque, is_constant, wants_dither);
119     }
120
121     // No, the shader wants us to create a context and call shadeSpan4f().
122     SkASSERT(!is_constant);  // All constant shaders should be able to appendStages().
123
124     if (dstCS) {
125         // We need to transform the shader into the dst color space, and extend its lifetime.
126         sk_sp<SkShader> in_dstCS = SkColorSpaceXformer::Make(sk_ref_sp(dstCS))->apply(shader);
127         shader = in_dstCS.get();
128         alloc->make<sk_sp<SkShader>>(std::move(in_dstCS));
129     }
130     SkShader::ContextRec rec(paint, ctm, nullptr, SkShader::ContextRec::kPM4f_DstType, dstCS);
131     SkShader::Context* shaderCtx = shader->makeContext(rec, alloc);
132     if (!shaderCtx) {
133         // When a shader fails to create a context, it has vetoed drawing entirely.
134         return alloc->make<SkNullBlitter>();
135     }
136     return SkRasterPipelineBlitter::Create(dst, paint, alloc,
137                                            shaderPipeline, shaderCtx,
138                                            is_opaque, is_constant, wants_dither);
139 }
140
141 SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
142                                          const SkPaint& paint,
143                                          const SkRasterPipeline& shaderPipeline,
144                                          bool is_opaque,
145                                          bool wants_dither,
146                                          SkArenaAlloc* alloc) {
147     bool is_constant = false;  // If this were the case, it'd be better to just set a paint color.
148     return SkRasterPipelineBlitter::Create(dst, paint, alloc,
149                                            shaderPipeline, nullptr,
150                                            is_opaque, is_constant, wants_dither);
151 }
152
153 SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
154                                            const SkPaint& paint,
155                                            SkArenaAlloc* alloc,
156                                            const SkRasterPipeline& shaderPipeline,
157                                            SkShader::Context* shaderCtx,
158                                            bool is_opaque,
159                                            bool is_constant,
160                                            bool wants_dither) {
161     auto blitter = alloc->make<SkRasterPipelineBlitter>(dst,
162                                                         paint.getBlendMode(),
163                                                         alloc,
164                                                         shaderCtx);
165
166     // Our job in this factory is to fill out the blitter's color pipeline.
167     // This is the common front of the full blit pipelines, each constructed lazily on first use.
168     // The full blit pipelines handle reading and writing the dst, blending, coverage, dithering.
169     auto colorPipeline = &blitter->fColorPipeline;
170
171     // Let's get the shader in first.
172     if (shaderCtx) {
173         colorPipeline->append(SkRasterPipeline::load_f32, &blitter->fShaderOutput);
174     } else {
175         // If the shader's not constant, it'll need seeding with x,y.
176         if (!is_constant) {
177             colorPipeline->append(SkRasterPipeline::seed_shader, &blitter->fCurrentY);
178         }
179         colorPipeline->extend(shaderPipeline);
180     }
181
182     // If there's a color filter it comes next.
183     if (auto colorFilter = paint.getColorFilter()) {
184         colorFilter->appendStages(colorPipeline, dst.colorSpace(), alloc, is_opaque);
185         is_opaque = is_opaque && (colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag);
186     }
187
188     // We'll dither if the shader wants to, or if we're drawing 565 and the paint wants to.
189     // Not all formats make sense to dither (think, F16).  We set their dither rate to zero.
190     // We need to decide if we're going to dither now to keep is_constant accurate.
191     if (wants_dither ||
192             (paint.isDither() && dst.info().colorType() == kRGB_565_SkColorType)) {
193         switch (dst.info().colorType()) {
194             default:                     blitter->fDitherCtx.rate =     0.0f; break;
195             case   kRGB_565_SkColorType: blitter->fDitherCtx.rate =  1/63.0f; break;
196             case kRGBA_8888_SkColorType:
197             case kBGRA_8888_SkColorType: blitter->fDitherCtx.rate = 1/255.0f; break;
198         }
199     }
200     is_constant = is_constant && (blitter->fDitherCtx.rate == 0.0f);
201
202     // We're logically done here.  The code between here and return blitter is all optimization.
203
204     // A pipeline that's still constant here can collapse back into a constant color.
205     if (is_constant) {
206         auto constantColor = alloc->make<SkPM4f>();
207         colorPipeline->append(SkRasterPipeline::store_f32, &constantColor);
208         colorPipeline->run(0,1);
209         colorPipeline->reset();
210         colorPipeline->append(SkRasterPipeline::constant_color, constantColor);
211
212         is_opaque = constantColor->a() == 1.0f;
213     }
214
215     // We can strength-reduce SrcOver into Src when opaque.
216     if (is_opaque && blitter->fBlend == SkBlendMode::kSrcOver) {
217         blitter->fBlend = SkBlendMode::kSrc;
218     }
219
220     // When we're drawing a constant color in Src mode, we can sometimes just memset.
221     // (The previous two optimizations help find more opportunities for this one.)
222     if (is_constant && blitter->fBlend == SkBlendMode::kSrc) {
223         // Run our color pipeline all the way through to produce what we'd memset when we can.
224         // Not all blits can memset, so we need to keep colorPipeline too.
225         SkRasterPipeline_<256> p;
226         p.extend(*colorPipeline);
227         blitter->fDstPtr = &blitter->fMemsetColor;
228         blitter->append_store(&p);
229         p.run(0,1);
230
231         blitter->fCanMemsetInBlitH = true;
232     }
233
234     return blitter;
235 }
236
237 void SkRasterPipelineBlitter::append_load_d(SkRasterPipeline* p) const {
238     p->append(SkRasterPipeline::move_src_dst);
239     switch (fDst.info().colorType()) {
240         case kAlpha_8_SkColorType:   p->append(SkRasterPipeline::load_a8,   &fDstPtr); break;
241         case kRGB_565_SkColorType:   p->append(SkRasterPipeline::load_565,  &fDstPtr); break;
242         case kBGRA_8888_SkColorType:
243         case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::load_8888, &fDstPtr); break;
244         case kRGBA_F16_SkColorType:  p->append(SkRasterPipeline::load_f16,  &fDstPtr); break;
245         default: break;
246     }
247     if (fDst.info().colorType() == kBGRA_8888_SkColorType) {
248         p->append(SkRasterPipeline::swap_rb);
249     }
250     if (fDst.info().gammaCloseToSRGB()) {
251         p->append_from_srgb(fDst.info().alphaType());
252     }
253     p->append(SkRasterPipeline::swap);
254 }
255
256 void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p) const {
257     if (fDst.info().gammaCloseToSRGB()) {
258         p->append(SkRasterPipeline::to_srgb);
259     }
260     if (fDitherCtx.rate > 0.0f) {
261         // We dither after any sRGB transfer function to make sure our 1/255.0f is sensible
262         // over the whole range.  If we did it before, 1/255.0f is too big a rate near zero.
263         p->append(SkRasterPipeline::dither, &fDitherCtx);
264     }
265
266     if (fDst.info().colorType() == kBGRA_8888_SkColorType) {
267         p->append(SkRasterPipeline::swap_rb);
268     }
269     switch (fDst.info().colorType()) {
270         case kAlpha_8_SkColorType:   p->append(SkRasterPipeline::store_a8,   &fDstPtr); break;
271         case kRGB_565_SkColorType:   p->append(SkRasterPipeline::store_565,  &fDstPtr); break;
272         case kBGRA_8888_SkColorType:
273         case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::store_8888, &fDstPtr); break;
274         case kRGBA_F16_SkColorType:  p->append(SkRasterPipeline::store_f16,  &fDstPtr); break;
275         default: break;
276     }
277 }
278
279 void SkRasterPipelineBlitter::append_blend(SkRasterPipeline* p) const {
280     SkBlendMode_AppendStages(fBlend, p);
281 }
282
283 void SkRasterPipelineBlitter::maybe_clamp(SkRasterPipeline* p) const {
284     if (SkBlendMode_CanOverflow(fBlend)) {
285         p->append(SkRasterPipeline::clamp_a);
286     }
287 }
288
289 void SkRasterPipelineBlitter::maybe_shade(int x, int y, int w) {
290     if (fShaderCtx) {
291         if (w > SkToInt(fShaderBuffer.size())) {
292             fShaderBuffer.resize(w);
293         }
294         fShaderCtx->shadeSpan4f(x,y, fShaderBuffer.data(), w);
295         // We'll be reading from fShaderOutput + x.
296         fShaderOutput = fShaderBuffer.data() - x;
297     }
298 }
299
300 void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
301     fDstPtr = fDst.writable_addr(0,y);
302     fCurrentY = y;
303
304     if (fCanMemsetInBlitH) {
305         switch (fDst.shiftPerPixel()) {
306             case 0:    memset  ((uint8_t *)fDstPtr + x, fMemsetColor, w); return;
307             case 1: sk_memset16((uint16_t*)fDstPtr + x, fMemsetColor, w); return;
308             case 2: sk_memset32((uint32_t*)fDstPtr + x, fMemsetColor, w); return;
309             case 3: sk_memset64((uint64_t*)fDstPtr + x, fMemsetColor, w); return;
310             default: break;
311         }
312     }
313
314     if (!fBlitH) {
315         SkRasterPipeline p(fAlloc);
316         p.extend(fColorPipeline);
317         if (fBlend != SkBlendMode::kSrc) {
318             this->append_load_d(&p);
319             this->append_blend(&p);
320             this->maybe_clamp(&p);
321         }
322         this->append_store(&p);
323         fBlitH = p.compile();
324     }
325     this->maybe_shade(x,y,w);
326     fBlitH(x,w);
327 }
328
329 void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
330     if (!fBlitAntiH) {
331         SkRasterPipeline p(fAlloc);
332         p.extend(fColorPipeline);
333         if (fBlend == SkBlendMode::kSrcOver) {
334             p.append(SkRasterPipeline::scale_1_float, &fCurrentCoverage);
335             this->append_load_d(&p);
336             this->append_blend(&p);
337         } else {
338             this->append_load_d(&p);
339             this->append_blend(&p);
340             p.append(SkRasterPipeline::lerp_1_float, &fCurrentCoverage);
341         }
342         this->maybe_clamp(&p);
343         this->append_store(&p);
344         fBlitAntiH = p.compile();
345     }
346
347     fDstPtr = fDst.writable_addr(0,y);
348     fCurrentY = y;
349     for (int16_t run = *runs; run > 0; run = *runs) {
350         switch (*aa) {
351             case 0x00:                       break;
352             case 0xff: this->blitH(x,y,run); break;
353             default:
354                 this->maybe_shade(x,y,run);
355                 fCurrentCoverage = *aa * (1/255.0f);
356                 fBlitAntiH(x,run);
357         }
358         x    += run;
359         runs += run;
360         aa   += run;
361     }
362 }
363
364 void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
365     if (mask.fFormat == SkMask::kBW_Format) {
366         // TODO: native BW masks?
367         return INHERITED::blitMask(mask, clip);
368     }
369
370     if (mask.fFormat == SkMask::kA8_Format && !fBlitMaskA8) {
371         SkRasterPipeline p(fAlloc);
372         p.extend(fColorPipeline);
373         if (fBlend == SkBlendMode::kSrcOver) {
374             p.append(SkRasterPipeline::scale_u8, &fMaskPtr);
375             this->append_load_d(&p);
376             this->append_blend(&p);
377         } else {
378             this->append_load_d(&p);
379             this->append_blend(&p);
380             p.append(SkRasterPipeline::lerp_u8, &fMaskPtr);
381         }
382         this->maybe_clamp(&p);
383         this->append_store(&p);
384         fBlitMaskA8 = p.compile();
385     }
386
387     if (mask.fFormat == SkMask::kLCD16_Format && !fBlitMaskLCD16) {
388         SkRasterPipeline p(fAlloc);
389         p.extend(fColorPipeline);
390         this->append_load_d(&p);
391         this->append_blend(&p);
392         p.append(SkRasterPipeline::lerp_565, &fMaskPtr);
393         this->maybe_clamp(&p);
394         this->append_store(&p);
395         fBlitMaskLCD16 = p.compile();
396     }
397
398     int x = clip.left();
399     for (int y = clip.top(); y < clip.bottom(); y++) {
400         fDstPtr = fDst.writable_addr(0,y);
401         fCurrentY = y;
402
403         this->maybe_shade(x,y,clip.width());
404         switch (mask.fFormat) {
405             case SkMask::kA8_Format:
406                 fMaskPtr = mask.getAddr8(x,y)-x;
407                 fBlitMaskA8(x,clip.width());
408                 break;
409             case SkMask::kLCD16_Format:
410                 fMaskPtr = mask.getAddrLCD16(x,y)-x;
411                 fBlitMaskLCD16(x,clip.width());
412                 break;
413             default:
414                 // TODO
415                 break;
416         }
417     }
418 }