Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/core/SkRasterPipelineBlitter.cpp

Issue 2146413002: Add SkRasterPipeline blitter. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: misleading comment Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "SkBlitter.h"
9 #include "SkColor.h"
10 #include "SkColorFilter.h"
11 #include "SkPM4f.h"
12 #include "SkRasterPipeline.h"
13 #include "SkShader.h"
14 #include "SkSRGB.h"
15 #include "SkXfermode.h"
16
17
18 struct SkRasterPipelineBlitter : public SkBlitter {
reed1 2016/07/20 13:09:59 class?
mtklein 2016/07/20 13:29:03 Done.
19 SkRasterPipelineBlitter(SkPixmap dst,
20 SkRasterPipeline shader,
21 SkRasterPipeline colorFilter,
22 SkRasterPipeline xfermode,
23 SkPM4f paintColor)
24 : fDst(dst)
25 , fShader(shader)
26 , fColorFilter(colorFilter)
27 , fXfermode(xfermode)
28 , fPaintColor(paintColor)
29 {}
30
31 void blitH (int x, int y, int w) override;
32 void blitAntiH(int x, int y, const SkAlpha[], const int16_t[]) override;
33 void blitMask (const SkMask&, const SkIRect& clip) override;
34
35 // TODO: The default implementations of the other blits look fine,
36 // but some of them like blitV could probably benefit from custom
37 // blits using something like a SkRasterPipeline::runFew() method.
38
39 SkPixmap fDst;
40 SkRasterPipeline fShader, fColorFilter, fXfermode;
41 SkPM4f fPaintColor;
42
43 typedef SkBlitter INHERITED;
44 };
45
46
47
48 // The default shader produces a constant color (from the SkPaint).
49 static void SK_VECTORCALL constant_color(SkRasterPipeline::Stage* st, size_t x,
50 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
51 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
52 auto color = st->ctx<const SkPM4f*>();
53 r = color->r();
54 g = color->g();
55 b = color->b();
56 a = color->a();
57 st->next(x, r,g,b,a, dr,dg,db,da);
58 }
59
60 // The default transfer mode is srcover, s' = s + d*(1-sa).
61 static void SK_VECTORCALL srcover(SkRasterPipeline::Stage* st, size_t x,
62 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
63 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
64 auto A = 1.0f - a;
65 r += dr*A;
66 g += dg*A;
67 b += db*A;
68 a += da*A;
69 st->next(x, r,g,b,a, dr,dg,db,da);
70 }
71
72 // s' = d(1-c) + sc, for a constant c.
73 static void SK_VECTORCALL lerp_constant_float(SkRasterPipeline::Stage* st, size_ t x,
74 Sk4f r, Sk4f g, Sk4f b, Sk4f a ,
75 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da ) {
76 Sk4f c = *st->ctx<const float*>();
77
78 Sk4f C = 1.0f - c;
79 r = r*c + dr*C;
80 g = g*c + dg*C;
81 b = b*c + db*C;
82 a = a*c + da*C;
83 st->next(x, r,g,b,a, dr,dg,db,da);
84 }
85
86 // s' = d(1-c) + sc, 4 pixels at a time for 8-bit coverage.
87 static void SK_VECTORCALL lerp_a8(SkRasterPipeline::Stage* st, size_t x,
88 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
89 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
90 auto ptr = st->ctx<const uint8_t*>() + x;
91 Sk4f c = SkNx_cast<float>(Sk4b::Load(ptr)) * (1/255.0f);
92
93 Sk4f C = 1.0f - c;
94 r = r*c + dr*C;
95 g = g*c + dg*C;
96 b = b*c + db*C;
97 a = a*c + da*C;
98 st->next(x, r,g,b,a, dr,dg,db,da);
99 }
100
101 // Tail variant of lerp_a8() handling 1 pixel at a time.
102 static void SK_VECTORCALL lerp_a8_1(SkRasterPipeline::Stage* st, size_t x,
103 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
104 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
105 auto ptr = st->ctx<const uint8_t*>() + x;
106 Sk4f c = *ptr * (1/255.0f);
107
108 Sk4f C = 1.0f - c;
109 r = r*c + dr*C;
110 g = g*c + dg*C;
111 b = b*c + db*C;
112 a = a*c + da*C;
113 st->next(x, r,g,b,a, dr,dg,db,da);
114 }
115
116 static void upscale_lcd16(const Sk4h& lcd16, Sk4f* r, Sk4f* g, Sk4f* b) {
117 Sk4i _32_bit = SkNx_cast<int>(lcd16);
118
119 *r = SkNx_cast<float>(_32_bit & SK_R16_MASK_IN_PLACE) * (1.0f / SK_R16_MASK_ IN_PLACE);
120 *g = SkNx_cast<float>(_32_bit & SK_G16_MASK_IN_PLACE) * (1.0f / SK_G16_MASK_ IN_PLACE);
121 *b = SkNx_cast<float>(_32_bit & SK_B16_MASK_IN_PLACE) * (1.0f / SK_B16_MASK_ IN_PLACE);
122 }
123
124 // s' = d(1-c) + sc, 4 pixels at a time for 565 coverage.
125 static void SK_VECTORCALL lerp_lcd16(SkRasterPipeline::Stage* st, size_t x,
126 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
127 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
128 auto ptr = st->ctx<const uint16_t*>() + x;
129 Sk4f cr, cg, cb;
130 upscale_lcd16(Sk4h::Load(ptr), &cr, &cg, &cb);
131
132 r = r*cr + dr*(1.0f - cr);
133 g = g*cg + dg*(1.0f - cg);
134 b = b*cb + db*(1.0f - cb);
135 a = 1.0f;
136 st->next(x, r,g,b,a, dr,dg,db,da);
137 }
138
139 // Tail variant of lerp_lcd16() handling 1 pixel at a time.
140 static void SK_VECTORCALL lerp_lcd16_1(SkRasterPipeline::Stage* st, size_t x,
141 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
142 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
143 auto ptr = st->ctx<const uint16_t*>() + x;
144 Sk4f cr, cg, cb;
145 upscale_lcd16({*ptr,0,0,0}, &cr, &cg, &cb);
146
147 r = r*cr + dr*(1.0f - cr);
148 g = g*cg + dg*(1.0f - cg);
149 b = b*cb + db*(1.0f - cb);
150 a = 1.0f;
151 st->next(x, r,g,b,a, dr,dg,db,da);
152 }
153
154 // Load 4 8-bit sRGB pixels from SkPMColor order to RGBA.
155 static void SK_VECTORCALL load_d_srgb(SkRasterPipeline::Stage* st, size_t x,
156 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
157 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
158 auto ptr = st->ctx<const uint32_t*>() + x;
159
160 dr = { sk_linear_from_srgb[(ptr[0] >> SK_R32_SHIFT) & 0xff],
161 sk_linear_from_srgb[(ptr[1] >> SK_R32_SHIFT) & 0xff],
162 sk_linear_from_srgb[(ptr[2] >> SK_R32_SHIFT) & 0xff],
163 sk_linear_from_srgb[(ptr[3] >> SK_R32_SHIFT) & 0xff] };
164
165 dg = { sk_linear_from_srgb[(ptr[0] >> SK_G32_SHIFT) & 0xff],
166 sk_linear_from_srgb[(ptr[1] >> SK_G32_SHIFT) & 0xff],
167 sk_linear_from_srgb[(ptr[2] >> SK_G32_SHIFT) & 0xff],
168 sk_linear_from_srgb[(ptr[3] >> SK_G32_SHIFT) & 0xff] };
169
170 db = { sk_linear_from_srgb[(ptr[0] >> SK_B32_SHIFT) & 0xff],
171 sk_linear_from_srgb[(ptr[1] >> SK_B32_SHIFT) & 0xff],
172 sk_linear_from_srgb[(ptr[2] >> SK_B32_SHIFT) & 0xff],
173 sk_linear_from_srgb[(ptr[3] >> SK_B32_SHIFT) & 0xff] };
174
175 // TODO: this >> doesn't really need mask if we make it logical instead of a rithmetic.
176 da = SkNx_cast<float>((Sk4i::Load(ptr) >> SK_A32_SHIFT) & 0xff) * (1/255.0f) ;
177
178 st->next(x, r,g,b,a, dr,dg,db,da);
179 }
180
181 // Tail variant of load_d_srgb() handling 1 pixel at a time.
182 static void SK_VECTORCALL load_d_srgb_1(SkRasterPipeline::Stage* st, size_t x,
183 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
184 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
185 auto ptr = st->ctx<const uint32_t*>() + x;
186
187 dr = { sk_linear_from_srgb[(*ptr >> SK_R32_SHIFT) & 0xff], 0,0,0 };
188 dg = { sk_linear_from_srgb[(*ptr >> SK_G32_SHIFT) & 0xff], 0,0,0 };
189 db = { sk_linear_from_srgb[(*ptr >> SK_B32_SHIFT) & 0xff], 0,0,0 };
190 da = { (1/255.0f) * (*ptr >> SK_A32_SHIFT) , 0,0,0 };
191
192 st->next(x, r,g,b,a, dr,dg,db,da);
193 }
194
195 static Sk4f clamp_0_255(const Sk4f& x) {
196 // This Max() argument order clamps NaN to 0.
197 return Sk4f::Min(Sk4f::Max(x, 0.0f), 255.0f);
198 }
199
200 // Write out 4 pixels as 8-bit SkPMColor-order sRGB.
201 static void SK_VECTORCALL store_srgb(SkRasterPipeline::Stage* st, size_t x,
202 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
203 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
204 r = clamp_0_255(sk_linear_to_srgb(r));
205 g = clamp_0_255(sk_linear_to_srgb(g));
206 b = clamp_0_255(sk_linear_to_srgb(b));
207 a = clamp_0_255( 255.0f * a );
208
209 auto dst = st->ctx<uint32_t*>() + x;
210 ( Sk4f_round(r) << SK_R32_SHIFT
211 | Sk4f_round(g) << SK_G32_SHIFT
212 | Sk4f_round(b) << SK_B32_SHIFT
213 | Sk4f_round(a) << SK_A32_SHIFT).store(dst);
214 }
215
216 // Tail variant of store_srgb() handling 1 pixel at a time.
217 static void SK_VECTORCALL store_srgb_1(SkRasterPipeline::Stage* st, size_t x,
218 Sk4f r, Sk4f g, Sk4f b, Sk4f a,
219 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
220 auto rgba = sk_linear_to_srgb({r[0], g[0], b[0], 0}),
221 pm = clamp_0_255({rgba[SK_R_INDEX], rgba[SK_G_INDEX], rgba[SK_B_INDEX ], 255.0f*a[0]});
222
223 auto dst = st->ctx<uint32_t*>() + x;
224 SkNx_cast<uint8_t>(Sk4f_round(pm)).store(dst);
225 }
226
227
228 template <typename Effect>
229 static bool append_effect_stages(const Effect* effect, SkRasterPipeline* pipelin e) {
230 return !effect || effect->appendStages(pipeline);
231 }
232
233 std::unique_ptr<SkBlitter> SkCreateRasterPipelineBlitter(const SkPixmap& dst,
234 const SkPaint& paint) {
235 if (!dst.info().gammaCloseToSRGB()) {
236 return nullptr; // TODO: f16, etc.
237 }
238 if (paint.getShader()) {
239 return nullptr; // TODO: need to work out how shaders and their context s work
240 }
241
242 SkRasterPipeline shader, colorFilter, xfermode;
243 if (!append_effect_stages(paint.getColorFilter(), &colorFilter) ||
244 !append_effect_stages(paint.getXfermode(), &xfermode )) {
245 return nullptr;
246 }
247
248 // TODO: SkPM4f paintColor = SkColor4f::FromColor(paint.getColor()).premul() ;
249 // once FromColor() is correct sRGB -> linear.
250 SkPM4f paintColor = SkColor4f{
251 sk_linear_from_srgb[SkColorGetR(paint.getColor())],
252 sk_linear_from_srgb[SkColorGetG(paint.getColor())],
253 sk_linear_from_srgb[SkColorGetB(paint.getColor())],
254 (1/255.0f) * SkColorGetA(paint.getColor()) ,
255 }.premul();
256
257 std::unique_ptr<SkRasterPipelineBlitter> blitter(new SkRasterPipelineBlitter {
258 dst,
259 shader, colorFilter, xfermode,
260 paintColor,
261 });
262
263 if (!paint.getShader()) {
reed1 2016/07/20 13:09:59 didn't we already check on line 238?
mtklein 2016/07/20 13:29:03 Yep. This check will stay long-term, the one on 2
reed1 2016/07/20 13:32:39 That's what I figured. sgtm
264 blitter->fShader.append(constant_color, &blitter->fPaintColor);
265 }
266 if (!paint.getXfermode()) {
267 blitter->fXfermode.append(srcover);
268 }
269
270 return std::move(blitter);
271 }
272
273 void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
274 auto dst = fDst.writable_addr(0,y);
275
276 SkRasterPipeline p;
277 p.extend(fShader);
278 p.extend(fColorFilter);
279 p.append(load_d_srgb, load_d_srgb_1, dst);
280 p.extend(fXfermode);
281 p.append(store_srgb, store_srgb_1, dst);
282
283 p.run(x, w);
284 }
285
286 void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
287 auto dst = fDst.writable_addr(0,y);
288 float coverage;
289
290 SkRasterPipeline p;
291 p.extend(fShader);
292 p.extend(fColorFilter);
293 p.append(load_d_srgb, load_d_srgb_1, dst);
294 p.extend(fXfermode);
295 p.append(lerp_constant_float, &coverage);
296 p.append(store_srgb, store_srgb_1, dst);
297
298 for (int16_t run = *runs; run > 0; run = *runs) {
299 coverage = *aa * (1/255.0f);
300 p.run(x, run);
301
302 x += run;
303 runs += run;
304 aa += run;
305 }
306 }
307
308 void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
309 if (mask.fFormat == SkMask::kBW_Format) {
310 // TODO: native BW masks?
311 return INHERITED::blitMask(mask, clip);
312 }
313
314 for (int y = clip.top(); y < clip.bottom(); y++) {
315 auto dst = fDst.writable_addr(0,y);
316
317 SkRasterPipeline p;
318 p.extend(fShader);
319 p.extend(fColorFilter);
320 p.append(load_d_srgb, load_d_srgb_1, dst);
321 p.extend(fXfermode);
322 switch (mask.fFormat) {
323 case SkMask::kA8_Format:
324 p.append(lerp_a8, lerp_a8_1, mask.getAddr8(0,y));
325 break;
326 case SkMask::kLCD16_Format:
327 p.append(lerp_lcd16, lerp_lcd16_1, mask.getAddrLCD16(0,y));
328 break;
329 default: break;
330 }
331 p.append(store_srgb, store_srgb_1, dst);
332
333 p.run(clip.left(), clip.width());
334 }
335 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698