91d60bee3aac10f2e65b712cd72be4990cdbce66
[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 "SkBlitter.h"
9 #include "SkColor.h"
10 #include "SkColorFilter.h"
11 #include "SkOpts.h"
12 #include "SkPM4f.h"
13 #include "SkRasterPipeline.h"
14 #include "SkShader.h"
15 #include "SkXfermode.h"
16
17
18 class SkRasterPipelineBlitter : public SkBlitter {
19 public:
20     static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkTBlitterAllocator*);
21
22     SkRasterPipelineBlitter(SkPixmap dst,
23                             SkRasterPipeline shader,
24                             SkRasterPipeline colorFilter,
25                             SkRasterPipeline xfermode,
26                             SkPM4f paintColor)
27         : fDst(dst)
28         , fShader(shader)
29         , fColorFilter(colorFilter)
30         , fXfermode(xfermode)
31         , fPaintColor(paintColor)
32     {}
33
34     void blitH    (int x, int y, int w)                            override;
35     void blitAntiH(int x, int y, const SkAlpha[], const int16_t[]) override;
36     void blitMask (const SkMask&, const SkIRect& clip)             override;
37
38     // TODO: The default implementations of the other blits look fine,
39     // but some of them like blitV could probably benefit from custom
40     // blits using something like a SkRasterPipeline::runFew() method.
41
42 private:
43     void append_load_d(SkRasterPipeline*, const void*) const;
44     void append_store (SkRasterPipeline*,       void*) const;
45
46     SkPixmap         fDst;
47     SkRasterPipeline fShader, fColorFilter, fXfermode;
48     SkPM4f           fPaintColor;
49
50     typedef SkBlitter INHERITED;
51 };
52
53 SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
54                                          const SkPaint& paint,
55                                          SkTBlitterAllocator* alloc) {
56     return SkRasterPipelineBlitter::Create(dst, paint, alloc);
57 }
58
59 static bool supported(const SkImageInfo& info) {
60     switch (info.colorType()) {
61         case kN32_SkColorType:      return info.gammaCloseToSRGB();
62         case kRGBA_F16_SkColorType: return true;
63         case kRGB_565_SkColorType:  return true;
64         default:                    return false;
65     }
66 }
67
68 template <typename Effect>
69 static bool append_effect_stages(const Effect* effect, SkRasterPipeline* pipeline) {
70     return !effect || effect->appendStages(pipeline);
71 }
72
73
74 SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
75                                            const SkPaint& paint,
76                                            SkTBlitterAllocator* alloc) {
77     if (!supported(dst.info())) {
78         return nullptr;
79     }
80     if (paint.getShader()) {
81         return nullptr;  // TODO: need to work out how shaders and their contexts work
82     }
83
84     SkRasterPipeline shader, colorFilter, xfermode;
85     if (!append_effect_stages(paint.getColorFilter(),                 &colorFilter) ||
86         !append_effect_stages(SkXfermode::Peek(paint.getBlendMode()), &xfermode   )) {
87         return nullptr;
88     }
89
90     uint32_t paintColor = paint.getColor();
91
92     SkColor4f color;
93     if (SkImageInfoIsGammaCorrect(dst.info())) {
94         color = SkColor4f::FromColor(paintColor);
95     } else {
96         swizzle_rb(SkNx_cast<float>(Sk4b::Load(&paintColor)) * (1/255.0f)).store(&color);
97     }
98
99     auto blitter = alloc->createT<SkRasterPipelineBlitter>(
100             dst,
101             shader, colorFilter, xfermode,
102             color.premul());
103
104     if (!paint.getShader()) {
105         blitter->fShader.append(SkRasterPipeline::constant_color, &blitter->fPaintColor);
106     }
107     if (paint.isSrcOver()) {
108         blitter->fXfermode.append(SkRasterPipeline::srcover);
109     }
110
111     return blitter;
112 }
113
114 void SkRasterPipelineBlitter::append_load_d(SkRasterPipeline* p, const void* dst) const {
115     SkASSERT(supported(fDst.info()));
116
117     switch (fDst.info().colorType()) {
118         case kN32_SkColorType:
119             if (fDst.info().gammaCloseToSRGB()) {
120                 p->append(SkRasterPipeline::load_d_srgb, dst);
121             }
122             break;
123         case kRGBA_F16_SkColorType:
124             p->append(SkRasterPipeline::load_d_f16, dst);
125             break;
126         case kRGB_565_SkColorType:
127             p->append(SkRasterPipeline::load_d_565, dst);
128             break;
129         default: break;
130     }
131 }
132
133 void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p, void* dst) const {
134     SkASSERT(supported(fDst.info()));
135
136     switch (fDst.info().colorType()) {
137         case kN32_SkColorType:
138             if (fDst.info().gammaCloseToSRGB()) {
139                 p->append(SkRasterPipeline::store_srgb, dst);
140             }
141             break;
142         case kRGBA_F16_SkColorType:
143             p->append(SkRasterPipeline::store_f16, dst);
144             break;
145         case kRGB_565_SkColorType:
146             p->append(SkRasterPipeline::store_565, dst);
147             break;
148         default: break;
149     }
150 }
151
152 void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
153     auto dst = fDst.writable_addr(0,y);
154
155     SkRasterPipeline p;
156     p.extend(fShader);
157     p.extend(fColorFilter);
158     this->append_load_d(&p, dst);
159     p.extend(fXfermode);
160     this->append_store(&p, dst);
161
162     p.run(x, w);
163 }
164
165 void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
166     auto dst = fDst.writable_addr(0,y);
167     float coverage;
168
169     SkRasterPipeline p;
170     p.extend(fShader);
171     p.extend(fColorFilter);
172     this->append_load_d(&p, dst);
173     p.extend(fXfermode);
174     p.append(SkRasterPipeline::lerp_constant_float, &coverage);
175     this->append_store(&p, dst);
176
177     for (int16_t run = *runs; run > 0; run = *runs) {
178         coverage = *aa * (1/255.0f);
179         p.run(x, run);
180
181         x    += run;
182         runs += run;
183         aa   += run;
184     }
185 }
186
187 void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
188     if (mask.fFormat == SkMask::kBW_Format) {
189         // TODO: native BW masks?
190         return INHERITED::blitMask(mask, clip);
191     }
192
193     int x = clip.left();
194     for (int y = clip.top(); y < clip.bottom(); y++) {
195         auto dst = fDst.writable_addr(0,y);
196
197         SkRasterPipeline p;
198         p.extend(fShader);
199         p.extend(fColorFilter);
200         this->append_load_d(&p, dst);
201         p.extend(fXfermode);
202         switch (mask.fFormat) {
203             case SkMask::kA8_Format:
204                 p.append(SkRasterPipeline::lerp_u8, mask.getAddr8(x,y)-x);
205                 break;
206             case SkMask::kLCD16_Format:
207                 p.append(SkRasterPipeline::lerp_565, mask.getAddrLCD16(x,y)-x);
208                 break;
209             default: break;
210         }
211         this->append_store(&p, dst);
212
213         p.run(x, clip.width());
214     }
215 }