• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 
21 class SkRasterPipelineBlitter : public SkBlitter {
22 public:
23     static SkBlitter* Create(const SkPixmap&, const SkPaint&, const SkMatrix& ctm,
24                              SkArenaAlloc*);
25 
SkRasterPipelineBlitter(SkPixmap dst,SkBlendMode blend,SkPM4f paintColor)26     SkRasterPipelineBlitter(SkPixmap dst, SkBlendMode blend, SkPM4f paintColor)
27         : fDst(dst)
28         , fBlend(blend)
29         , fPaintColor(paintColor)
30     {}
31 
32     void blitH    (int x, int y, int w)                            override;
33     void blitAntiH(int x, int y, const SkAlpha[], const int16_t[]) override;
34     void blitMask (const SkMask&, const SkIRect& clip)             override;
35 
36     // TODO: The default implementations of the other blits look fine,
37     // but some of them like blitV could probably benefit from custom
38     // blits using something like a SkRasterPipeline::runFew() method.
39 
40 private:
41     void append_load_d(SkRasterPipeline*) const;
42     void append_blend (SkRasterPipeline*) const;
43     void maybe_clamp  (SkRasterPipeline*) const;
44     void append_store (SkRasterPipeline*) const;
45 
46     SkPixmap         fDst;
47     SkBlendMode      fBlend;
48     SkPM4f           fPaintColor;
49     SkRasterPipeline fShader;
50 
51     // We may be able to specialize blitH() into a memset.
52     bool     fCanMemsetInBlitH = false;
53     uint64_t fMemsetColor      = 0;     // Big enough for largest dst format, F16.
54 
55     // Built lazily on first use.
56     SkRasterPipeline fBlitH,
57                      fBlitAntiH,
58                      fBlitMaskA8,
59                      fBlitMaskLCD16;
60 
61     // These values are pointed to by the blit pipelines above,
62     // which allows us to adjust them from call to call.
63     void*       fDstPtr          = nullptr;
64     const void* fMaskPtr         = nullptr;
65     float       fCurrentCoverage = 0.0f;
66     int         fCurrentY        = 0;
67 
68     typedef SkBlitter INHERITED;
69 };
70 
SkCreateRasterPipelineBlitter(const SkPixmap & dst,const SkPaint & paint,const SkMatrix & ctm,SkArenaAlloc * alloc)71 SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
72                                          const SkPaint& paint,
73                                          const SkMatrix& ctm,
74                                          SkArenaAlloc* alloc) {
75     return SkRasterPipelineBlitter::Create(dst, paint, ctm, alloc);
76 }
77 
supported(const SkImageInfo & info)78 static bool supported(const SkImageInfo& info) {
79     switch (info.colorType()) {
80         case kAlpha_8_SkColorType:  return true;
81         case kRGB_565_SkColorType:  return true;
82         case kN32_SkColorType:      return info.gammaCloseToSRGB();
83         case kRGBA_F16_SkColorType: return true;
84         default:                    return false;
85     }
86 }
87 
Create(const SkPixmap & dst,const SkPaint & paint,const SkMatrix & ctm,SkArenaAlloc * alloc)88 SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
89                                            const SkPaint& paint,
90                                            const SkMatrix& ctm,
91                                            SkArenaAlloc* alloc) {
92     auto blitter = alloc->make<SkRasterPipelineBlitter>(
93             dst,
94             paint.getBlendMode(),
95             SkPM4f_from_SkColor(paint.getColor(), dst.colorSpace()));
96 
97 
98     SkBlendMode*      blend       = &blitter->fBlend;
99     SkPM4f*           paintColor  = &blitter->fPaintColor;
100     SkRasterPipeline* pipeline    = &blitter->fShader;
101 
102     SkShader*      shader      = paint.getShader();
103     SkColorFilter* colorFilter = paint.getColorFilter();
104 
105     // TODO: all temporary
106     if (!supported(dst.info()) || !SkBlendMode_AppendStages(*blend)) {
107         return nullptr;
108     }
109 
110     bool is_opaque   = paintColor->a() == 1.0f,
111          is_constant = true;
112     if (shader) {
113         pipeline->append(SkRasterPipeline::seed_shader, &blitter->fCurrentY);
114         if (!shader->appendStages(pipeline, dst.colorSpace(), alloc, ctm, paint)) {
115             return nullptr;
116         }
117         if (!is_opaque) {
118             pipeline->append(SkRasterPipeline::scale_1_float,
119                              &paintColor->fVec[SkPM4f::A]);
120         }
121 
122         is_opaque   = is_opaque && shader->isOpaque();
123         is_constant = shader->isConstant();
124     } else {
125         pipeline->append(SkRasterPipeline::constant_color, paintColor);
126     }
127 
128     if (colorFilter) {
129         if (!colorFilter->appendStages(pipeline, dst.colorSpace(), alloc, is_opaque)) {
130             return nullptr;
131         }
132         is_opaque = is_opaque && (colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag);
133     }
134 
135     if (is_constant) {
136         pipeline->append(SkRasterPipeline::store_f32, &paintColor);
137         pipeline->run(0,1);
138 
139         *pipeline = SkRasterPipeline();
140         pipeline->append(SkRasterPipeline::constant_color, paintColor);
141 
142         is_opaque = paintColor->a() == 1.0f;
143     }
144 
145     if (is_opaque && *blend == SkBlendMode::kSrcOver) {
146         *blend = SkBlendMode::kSrc;
147     }
148 
149     if (is_constant && *blend == SkBlendMode::kSrc) {
150         SkRasterPipeline p;
151         p.extend(*pipeline);
152         blitter->fDstPtr = &blitter->fMemsetColor;
153         blitter->append_store(&p);
154         p.run(0,1);
155 
156         blitter->fCanMemsetInBlitH = true;
157     }
158 
159     return blitter;
160 }
161 
append_load_d(SkRasterPipeline * p) const162 void SkRasterPipelineBlitter::append_load_d(SkRasterPipeline* p) const {
163     SkASSERT(supported(fDst.info()));
164 
165     p->append(SkRasterPipeline::move_src_dst);
166     switch (fDst.info().colorType()) {
167         case kAlpha_8_SkColorType:   p->append(SkRasterPipeline::load_a8,   &fDstPtr); break;
168         case kRGB_565_SkColorType:   p->append(SkRasterPipeline::load_565,  &fDstPtr); break;
169         case kBGRA_8888_SkColorType:
170         case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::load_8888, &fDstPtr); break;
171         case kRGBA_F16_SkColorType:  p->append(SkRasterPipeline::load_f16,  &fDstPtr); break;
172         default: break;
173     }
174     if (fDst.info().colorType() == kBGRA_8888_SkColorType) {
175         p->append(SkRasterPipeline::swap_rb);
176     }
177     if (fDst.info().gammaCloseToSRGB()) {
178         p->append_from_srgb(fDst.info().alphaType());
179     }
180     p->append(SkRasterPipeline::swap);
181 }
182 
append_store(SkRasterPipeline * p) const183 void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p) const {
184     if (fDst.info().gammaCloseToSRGB()) {
185         p->append(SkRasterPipeline::to_srgb);
186     }
187     if (fDst.info().colorType() == kBGRA_8888_SkColorType) {
188         p->append(SkRasterPipeline::swap_rb);
189     }
190 
191     SkASSERT(supported(fDst.info()));
192     switch (fDst.info().colorType()) {
193         case kAlpha_8_SkColorType:   p->append(SkRasterPipeline::store_a8,   &fDstPtr); break;
194         case kRGB_565_SkColorType:   p->append(SkRasterPipeline::store_565,  &fDstPtr); break;
195         case kBGRA_8888_SkColorType:
196         case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::store_8888, &fDstPtr); break;
197         case kRGBA_F16_SkColorType:  p->append(SkRasterPipeline::store_f16,  &fDstPtr); break;
198         default: break;
199     }
200 }
201 
append_blend(SkRasterPipeline * p) const202 void SkRasterPipelineBlitter::append_blend(SkRasterPipeline* p) const {
203     SkAssertResult(SkBlendMode_AppendStages(fBlend, p));
204 }
205 
maybe_clamp(SkRasterPipeline * p) const206 void SkRasterPipelineBlitter::maybe_clamp(SkRasterPipeline* p) const {
207     if (SkBlendMode_CanOverflow(fBlend)) {
208         p->append(SkRasterPipeline::clamp_a);
209     }
210 }
211 
blitH(int x,int y,int w)212 void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
213     fDstPtr = fDst.writable_addr(0,y);
214     fCurrentY = y;
215 
216     if (fCanMemsetInBlitH) {
217         switch (fDst.shiftPerPixel()) {
218             case 0:    memset  ((uint8_t *)fDstPtr + x, fMemsetColor, w); return;
219             case 1: sk_memset16((uint16_t*)fDstPtr + x, fMemsetColor, w); return;
220             case 2: sk_memset32((uint32_t*)fDstPtr + x, fMemsetColor, w); return;
221             case 3: sk_memset64((uint64_t*)fDstPtr + x, fMemsetColor, w); return;
222             default: break;
223         }
224     }
225 
226     auto& p = fBlitH;
227     if (p.empty()) {
228         p.extend(fShader);
229         if (fBlend != SkBlendMode::kSrc) {
230             this->append_load_d(&p);
231             this->append_blend(&p);
232             this->maybe_clamp(&p);
233         }
234         this->append_store(&p);
235     }
236     p.run(x,w);
237 }
238 
blitAntiH(int x,int y,const SkAlpha aa[],const int16_t runs[])239 void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
240     auto& p = fBlitAntiH;
241     if (p.empty()) {
242         p.extend(fShader);
243         if (fBlend == SkBlendMode::kSrcOver) {
244             p.append(SkRasterPipeline::scale_1_float, &fCurrentCoverage);
245             this->append_load_d(&p);
246             this->append_blend(&p);
247         } else {
248             this->append_load_d(&p);
249             this->append_blend(&p);
250             p.append(SkRasterPipeline::lerp_1_float, &fCurrentCoverage);
251         }
252         this->maybe_clamp(&p);
253         this->append_store(&p);
254     }
255 
256     fDstPtr = fDst.writable_addr(0,y);
257     fCurrentY = y;
258     for (int16_t run = *runs; run > 0; run = *runs) {
259         switch (*aa) {
260             case 0x00:                       break;
261             case 0xff: this->blitH(x,y,run); break;
262             default:
263                 fCurrentCoverage = *aa * (1/255.0f);
264                 p.run(x,run);
265         }
266         x    += run;
267         runs += run;
268         aa   += run;
269     }
270 }
271 
blitMask(const SkMask & mask,const SkIRect & clip)272 void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
273     if (mask.fFormat == SkMask::kBW_Format) {
274         // TODO: native BW masks?
275         return INHERITED::blitMask(mask, clip);
276     }
277 
278     if (mask.fFormat == SkMask::kA8_Format && fBlitMaskA8.empty()) {
279         auto& p = fBlitMaskA8;
280         p.extend(fShader);
281         if (fBlend == SkBlendMode::kSrcOver) {
282             p.append(SkRasterPipeline::scale_u8, &fMaskPtr);
283             this->append_load_d(&p);
284             this->append_blend(&p);
285         } else {
286             this->append_load_d(&p);
287             this->append_blend(&p);
288             p.append(SkRasterPipeline::lerp_u8, &fMaskPtr);
289         }
290         this->maybe_clamp(&p);
291         this->append_store(&p);
292     }
293 
294     if (mask.fFormat == SkMask::kLCD16_Format && fBlitMaskLCD16.empty()) {
295         auto& p = fBlitMaskLCD16;
296         p.extend(fShader);
297         this->append_load_d(&p);
298         this->append_blend(&p);
299         p.append(SkRasterPipeline::lerp_565, &fMaskPtr);
300         this->maybe_clamp(&p);
301         this->append_store(&p);
302     }
303 
304     int x = clip.left();
305     for (int y = clip.top(); y < clip.bottom(); y++) {
306         fDstPtr = fDst.writable_addr(0,y);
307         fCurrentY = y;
308 
309         switch (mask.fFormat) {
310             case SkMask::kA8_Format:
311                 fMaskPtr = mask.getAddr8(x,y)-x;
312                 fBlitMaskA8.run(x,clip.width());
313                 break;
314             case SkMask::kLCD16_Format:
315                 fMaskPtr = mask.getAddrLCD16(x,y)-x;
316                 fBlitMaskLCD16.run(x,clip.width());
317                 break;
318             default:
319                 // TODO
320                 break;
321         }
322     }
323 }
324