Line data Source code
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 312 : class SkRasterPipelineBlitter : public SkBlitter {
22 : public:
23 : static SkBlitter* Create(const SkPixmap&, const SkPaint&, const SkMatrix& ctm,
24 : SkArenaAlloc*);
25 :
26 312 : SkRasterPipelineBlitter(SkPixmap dst, SkBlendMode blend, SkPM4f paintColor)
27 312 : : fDst(dst)
28 : , fBlend(blend)
29 312 : , fPaintColor(paintColor)
30 312 : {}
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 :
71 312 : SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
72 : const SkPaint& paint,
73 : const SkMatrix& ctm,
74 : SkArenaAlloc* alloc) {
75 312 : return SkRasterPipelineBlitter::Create(dst, paint, ctm, alloc);
76 : }
77 :
78 316 : static bool supported(const SkImageInfo& info) {
79 316 : switch (info.colorType()) {
80 8 : case kAlpha_8_SkColorType: return true;
81 0 : case kRGB_565_SkColorType: return true;
82 308 : case kN32_SkColorType: return info.gammaCloseToSRGB();
83 0 : case kRGBA_F16_SkColorType: return true;
84 0 : default: return false;
85 : }
86 : }
87 :
88 312 : 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 624 : paint.getBlendMode(),
95 936 : SkPM4f_from_SkColor(paint.getColor(), dst.colorSpace()));
96 :
97 :
98 312 : SkBlendMode* blend = &blitter->fBlend;
99 312 : SkPM4f* paintColor = &blitter->fPaintColor;
100 312 : SkRasterPipeline* pipeline = &blitter->fShader;
101 :
102 312 : SkShader* shader = paint.getShader();
103 312 : SkColorFilter* colorFilter = paint.getColorFilter();
104 :
105 : // TODO: all temporary
106 312 : if (!supported(dst.info()) || !SkBlendMode_AppendStages(*blend)) {
107 308 : return nullptr;
108 : }
109 :
110 4 : bool is_opaque = paintColor->a() == 1.0f,
111 4 : is_constant = true;
112 4 : if (shader) {
113 2 : pipeline->append(SkRasterPipeline::seed_shader, &blitter->fCurrentY);
114 2 : if (!shader->appendStages(pipeline, dst.colorSpace(), alloc, ctm, paint)) {
115 2 : return nullptr;
116 : }
117 0 : if (!is_opaque) {
118 : pipeline->append(SkRasterPipeline::scale_1_float,
119 0 : &paintColor->fVec[SkPM4f::A]);
120 : }
121 :
122 0 : is_opaque = is_opaque && shader->isOpaque();
123 0 : is_constant = shader->isConstant();
124 : } else {
125 2 : pipeline->append(SkRasterPipeline::constant_color, paintColor);
126 : }
127 :
128 2 : if (colorFilter) {
129 0 : if (!colorFilter->appendStages(pipeline, dst.colorSpace(), alloc, is_opaque)) {
130 0 : return nullptr;
131 : }
132 0 : is_opaque = is_opaque && (colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag);
133 : }
134 :
135 2 : if (is_constant) {
136 2 : pipeline->append(SkRasterPipeline::store_f32, &paintColor);
137 2 : pipeline->run(0,1);
138 :
139 2 : *pipeline = SkRasterPipeline();
140 2 : pipeline->append(SkRasterPipeline::constant_color, paintColor);
141 :
142 2 : is_opaque = paintColor->a() == 1.0f;
143 : }
144 :
145 2 : if (is_opaque && *blend == SkBlendMode::kSrcOver) {
146 2 : *blend = SkBlendMode::kSrc;
147 : }
148 :
149 2 : if (is_constant && *blend == SkBlendMode::kSrc) {
150 4 : SkRasterPipeline p;
151 2 : p.extend(*pipeline);
152 2 : blitter->fDstPtr = &blitter->fMemsetColor;
153 2 : blitter->append_store(&p);
154 2 : p.run(0,1);
155 :
156 2 : blitter->fCanMemsetInBlitH = true;
157 : }
158 :
159 2 : return blitter;
160 : }
161 :
162 1 : void SkRasterPipelineBlitter::append_load_d(SkRasterPipeline* p) const {
163 1 : SkASSERT(supported(fDst.info()));
164 :
165 1 : p->append(SkRasterPipeline::move_src_dst);
166 1 : switch (fDst.info().colorType()) {
167 1 : case kAlpha_8_SkColorType: p->append(SkRasterPipeline::load_a8, &fDstPtr); break;
168 0 : case kRGB_565_SkColorType: p->append(SkRasterPipeline::load_565, &fDstPtr); break;
169 : case kBGRA_8888_SkColorType:
170 0 : case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::load_8888, &fDstPtr); break;
171 0 : case kRGBA_F16_SkColorType: p->append(SkRasterPipeline::load_f16, &fDstPtr); break;
172 0 : default: break;
173 : }
174 1 : if (fDst.info().colorType() == kBGRA_8888_SkColorType) {
175 0 : p->append(SkRasterPipeline::swap_rb);
176 : }
177 1 : if (fDst.info().gammaCloseToSRGB()) {
178 0 : p->append_from_srgb(fDst.info().alphaType());
179 : }
180 1 : p->append(SkRasterPipeline::swap);
181 1 : }
182 :
183 3 : void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p) const {
184 3 : if (fDst.info().gammaCloseToSRGB()) {
185 0 : p->append(SkRasterPipeline::to_srgb);
186 : }
187 3 : if (fDst.info().colorType() == kBGRA_8888_SkColorType) {
188 0 : p->append(SkRasterPipeline::swap_rb);
189 : }
190 :
191 3 : SkASSERT(supported(fDst.info()));
192 3 : switch (fDst.info().colorType()) {
193 3 : case kAlpha_8_SkColorType: p->append(SkRasterPipeline::store_a8, &fDstPtr); break;
194 0 : case kRGB_565_SkColorType: p->append(SkRasterPipeline::store_565, &fDstPtr); break;
195 : case kBGRA_8888_SkColorType:
196 0 : case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::store_8888, &fDstPtr); break;
197 0 : case kRGBA_F16_SkColorType: p->append(SkRasterPipeline::store_f16, &fDstPtr); break;
198 0 : default: break;
199 : }
200 3 : }
201 :
202 1 : void SkRasterPipelineBlitter::append_blend(SkRasterPipeline* p) const {
203 1 : SkAssertResult(SkBlendMode_AppendStages(fBlend, p));
204 1 : }
205 :
206 1 : void SkRasterPipelineBlitter::maybe_clamp(SkRasterPipeline* p) const {
207 1 : if (SkBlendMode_CanOverflow(fBlend)) {
208 0 : p->append(SkRasterPipeline::clamp_a);
209 : }
210 1 : }
211 :
212 29 : void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
213 29 : fDstPtr = fDst.writable_addr(0,y);
214 29 : fCurrentY = y;
215 :
216 29 : if (fCanMemsetInBlitH) {
217 29 : switch (fDst.shiftPerPixel()) {
218 29 : case 0: memset ((uint8_t *)fDstPtr + x, fMemsetColor, w); return;
219 0 : case 1: sk_memset16((uint16_t*)fDstPtr + x, fMemsetColor, w); return;
220 0 : case 2: sk_memset32((uint32_t*)fDstPtr + x, fMemsetColor, w); return;
221 0 : case 3: sk_memset64((uint64_t*)fDstPtr + x, fMemsetColor, w); return;
222 0 : default: break;
223 : }
224 : }
225 :
226 0 : auto& p = fBlitH;
227 0 : if (p.empty()) {
228 0 : p.extend(fShader);
229 0 : if (fBlend != SkBlendMode::kSrc) {
230 0 : this->append_load_d(&p);
231 0 : this->append_blend(&p);
232 0 : this->maybe_clamp(&p);
233 : }
234 0 : this->append_store(&p);
235 : }
236 0 : p.run(x,w);
237 : }
238 :
239 0 : void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
240 0 : auto& p = fBlitAntiH;
241 0 : if (p.empty()) {
242 0 : p.extend(fShader);
243 0 : if (fBlend == SkBlendMode::kSrcOver) {
244 0 : p.append(SkRasterPipeline::scale_1_float, &fCurrentCoverage);
245 0 : this->append_load_d(&p);
246 0 : this->append_blend(&p);
247 : } else {
248 0 : this->append_load_d(&p);
249 0 : this->append_blend(&p);
250 0 : p.append(SkRasterPipeline::lerp_1_float, &fCurrentCoverage);
251 : }
252 0 : this->maybe_clamp(&p);
253 0 : this->append_store(&p);
254 : }
255 :
256 0 : fDstPtr = fDst.writable_addr(0,y);
257 0 : fCurrentY = y;
258 0 : for (int16_t run = *runs; run > 0; run = *runs) {
259 0 : switch (*aa) {
260 0 : case 0x00: break;
261 0 : case 0xff: this->blitH(x,y,run); break;
262 : default:
263 0 : fCurrentCoverage = *aa * (1/255.0f);
264 0 : p.run(x,run);
265 : }
266 0 : x += run;
267 0 : runs += run;
268 0 : aa += run;
269 : }
270 0 : }
271 :
272 1 : void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
273 1 : if (mask.fFormat == SkMask::kBW_Format) {
274 : // TODO: native BW masks?
275 0 : return INHERITED::blitMask(mask, clip);
276 : }
277 :
278 1 : if (mask.fFormat == SkMask::kA8_Format && fBlitMaskA8.empty()) {
279 1 : auto& p = fBlitMaskA8;
280 1 : p.extend(fShader);
281 1 : if (fBlend == SkBlendMode::kSrcOver) {
282 0 : p.append(SkRasterPipeline::scale_u8, &fMaskPtr);
283 0 : this->append_load_d(&p);
284 0 : this->append_blend(&p);
285 : } else {
286 1 : this->append_load_d(&p);
287 1 : this->append_blend(&p);
288 1 : p.append(SkRasterPipeline::lerp_u8, &fMaskPtr);
289 : }
290 1 : this->maybe_clamp(&p);
291 1 : this->append_store(&p);
292 : }
293 :
294 1 : if (mask.fFormat == SkMask::kLCD16_Format && fBlitMaskLCD16.empty()) {
295 0 : auto& p = fBlitMaskLCD16;
296 0 : p.extend(fShader);
297 0 : this->append_load_d(&p);
298 0 : this->append_blend(&p);
299 0 : p.append(SkRasterPipeline::lerp_565, &fMaskPtr);
300 0 : this->maybe_clamp(&p);
301 0 : this->append_store(&p);
302 : }
303 :
304 1 : int x = clip.left();
305 28 : for (int y = clip.top(); y < clip.bottom(); y++) {
306 27 : fDstPtr = fDst.writable_addr(0,y);
307 27 : fCurrentY = y;
308 :
309 27 : switch (mask.fFormat) {
310 : case SkMask::kA8_Format:
311 27 : fMaskPtr = mask.getAddr8(x,y)-x;
312 27 : fBlitMaskA8.run(x,clip.width());
313 27 : break;
314 : case SkMask::kLCD16_Format:
315 0 : fMaskPtr = mask.getAddrLCD16(x,y)-x;
316 0 : fBlitMaskLCD16.run(x,clip.width());
317 0 : break;
318 : default:
319 : // TODO
320 0 : break;
321 : }
322 : }
323 : }
|