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