blob: 51c2fc1805de3dafb9e4b85c941a2a87a168ff2a [file] [log] [blame]
mtklein9a5c47f2016-07-22 11:05:04 -07001/*
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"
Mike Kleinbaaf8ad2016-09-29 09:04:15 -040011#include "SkOpts.h"
mtklein9a5c47f2016-07-22 11:05:04 -070012#include "SkPM4f.h"
mtklein9a5c47f2016-07-22 11:05:04 -070013#include "SkRasterPipeline.h"
14#include "SkShader.h"
mtklein9a5c47f2016-07-22 11:05:04 -070015#include "SkXfermode.h"
16
17
18class SkRasterPipelineBlitter : public SkBlitter {
19public:
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
42private:
mtklein8e4373f2016-07-22 14:20:27 -070043 void append_load_d(SkRasterPipeline*, const void*) const;
44 void append_store (SkRasterPipeline*, void*) const;
45
mtklein9a5c47f2016-07-22 11:05:04 -070046 SkPixmap fDst;
47 SkRasterPipeline fShader, fColorFilter, fXfermode;
48 SkPM4f fPaintColor;
49
Mike Kleinbd3fe472016-10-25 15:43:46 -040050 // These functions are compiled lazily when first used.
51 std::function<void(size_t, size_t)> fBlitH = nullptr,
52 fBlitAntiH = nullptr,
53 fBlitMaskA8 = nullptr,
54 fBlitMaskLCD16 = nullptr;
55
56 // These values are pointed to by the compiled blit functions
57 // above, which allows us to adjust them from call to call.
58 void* fDstPtr = nullptr;
59 const void* fMaskPtr = nullptr;
60 float fConstantCoverage = 0.0f;
61
mtklein9a5c47f2016-07-22 11:05:04 -070062 typedef SkBlitter INHERITED;
63};
64
65SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
66 const SkPaint& paint,
67 SkTBlitterAllocator* alloc) {
68 return SkRasterPipelineBlitter::Create(dst, paint, alloc);
69}
70
mtklein8e4373f2016-07-22 14:20:27 -070071static bool supported(const SkImageInfo& info) {
mtklein8e4373f2016-07-22 14:20:27 -070072 switch (info.colorType()) {
mtklein4e90e3e2016-07-25 14:35:31 -070073 case kN32_SkColorType: return info.gammaCloseToSRGB();
74 case kRGBA_F16_SkColorType: return true;
75 case kRGB_565_SkColorType: return true;
76 default: return false;
mtklein8e4373f2016-07-22 14:20:27 -070077 }
78}
mtklein9a5c47f2016-07-22 11:05:04 -070079
80template <typename Effect>
81static bool append_effect_stages(const Effect* effect, SkRasterPipeline* pipeline) {
82 return !effect || effect->appendStages(pipeline);
83}
84
85
86SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
87 const SkPaint& paint,
88 SkTBlitterAllocator* alloc) {
mtklein8e4373f2016-07-22 14:20:27 -070089 if (!supported(dst.info())) {
90 return nullptr;
mtklein9a5c47f2016-07-22 11:05:04 -070091 }
92 if (paint.getShader()) {
93 return nullptr; // TODO: need to work out how shaders and their contexts work
94 }
95
96 SkRasterPipeline shader, colorFilter, xfermode;
reed374772b2016-10-05 17:33:02 -070097 if (!append_effect_stages(paint.getColorFilter(), &colorFilter) ||
98 !append_effect_stages(SkXfermode::Peek(paint.getBlendMode()), &xfermode )) {
mtklein9a5c47f2016-07-22 11:05:04 -070099 return nullptr;
100 }
101
mtklein8e4373f2016-07-22 14:20:27 -0700102 uint32_t paintColor = paint.getColor();
103
104 SkColor4f color;
mtklein4e90e3e2016-07-25 14:35:31 -0700105 if (SkImageInfoIsGammaCorrect(dst.info())) {
mtklein8e4373f2016-07-22 14:20:27 -0700106 color = SkColor4f::FromColor(paintColor);
107 } else {
108 swizzle_rb(SkNx_cast<float>(Sk4b::Load(&paintColor)) * (1/255.0f)).store(&color);
109 }
110
mtklein9a5c47f2016-07-22 11:05:04 -0700111 auto blitter = alloc->createT<SkRasterPipelineBlitter>(
112 dst,
113 shader, colorFilter, xfermode,
mtklein8e4373f2016-07-22 14:20:27 -0700114 color.premul());
mtklein9a5c47f2016-07-22 11:05:04 -0700115
116 if (!paint.getShader()) {
Mike Kleinfa9f2412016-09-29 13:40:01 -0400117 blitter->fShader.append(SkRasterPipeline::constant_color, &blitter->fPaintColor);
mtklein9a5c47f2016-07-22 11:05:04 -0700118 }
reed374772b2016-10-05 17:33:02 -0700119 if (paint.isSrcOver()) {
Mike Kleinfa9f2412016-09-29 13:40:01 -0400120 blitter->fXfermode.append(SkRasterPipeline::srcover);
mtklein9a5c47f2016-07-22 11:05:04 -0700121 }
122
123 return blitter;
124}
125
mtklein8e4373f2016-07-22 14:20:27 -0700126void SkRasterPipelineBlitter::append_load_d(SkRasterPipeline* p, const void* dst) const {
127 SkASSERT(supported(fDst.info()));
128
129 switch (fDst.info().colorType()) {
130 case kN32_SkColorType:
131 if (fDst.info().gammaCloseToSRGB()) {
Mike Kleinfa9f2412016-09-29 13:40:01 -0400132 p->append(SkRasterPipeline::load_d_srgb, dst);
mtklein8e4373f2016-07-22 14:20:27 -0700133 }
134 break;
mtklein4e90e3e2016-07-25 14:35:31 -0700135 case kRGBA_F16_SkColorType:
Mike Kleinfa9f2412016-09-29 13:40:01 -0400136 p->append(SkRasterPipeline::load_d_f16, dst);
mtklein4e90e3e2016-07-25 14:35:31 -0700137 break;
mtklein8e4373f2016-07-22 14:20:27 -0700138 case kRGB_565_SkColorType:
Mike Kleinfa9f2412016-09-29 13:40:01 -0400139 p->append(SkRasterPipeline::load_d_565, dst);
mtklein8e4373f2016-07-22 14:20:27 -0700140 break;
141 default: break;
142 }
143}
144
145void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p, void* dst) const {
146 SkASSERT(supported(fDst.info()));
147
148 switch (fDst.info().colorType()) {
149 case kN32_SkColorType:
150 if (fDst.info().gammaCloseToSRGB()) {
Mike Kleinfa9f2412016-09-29 13:40:01 -0400151 p->append(SkRasterPipeline::store_srgb, dst);
mtklein8e4373f2016-07-22 14:20:27 -0700152 }
153 break;
mtklein4e90e3e2016-07-25 14:35:31 -0700154 case kRGBA_F16_SkColorType:
Mike Kleinfa9f2412016-09-29 13:40:01 -0400155 p->append(SkRasterPipeline::store_f16, dst);
mtklein4e90e3e2016-07-25 14:35:31 -0700156 break;
mtklein8e4373f2016-07-22 14:20:27 -0700157 case kRGB_565_SkColorType:
Mike Kleinfa9f2412016-09-29 13:40:01 -0400158 p->append(SkRasterPipeline::store_565, dst);
mtklein8e4373f2016-07-22 14:20:27 -0700159 break;
160 default: break;
161 }
162}
163
Mike Kleine9f74b82016-10-25 13:31:21 -0400164// TODO: Figure out how to cache some of the compiled pipelines.
165
mtklein9a5c47f2016-07-22 11:05:04 -0700166void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400167 if (!fBlitH) {
168 SkRasterPipeline p;
169 p.extend(fShader);
170 p.extend(fColorFilter);
171 this->append_load_d(&p, &fDstPtr);
172 p.extend(fXfermode);
173 this->append_store(&p, &fDstPtr);
174 fBlitH = p.compile();
175 }
mtklein9a5c47f2016-07-22 11:05:04 -0700176
Mike Kleinbd3fe472016-10-25 15:43:46 -0400177 fDstPtr = fDst.writable_addr(0,y);
178 fBlitH(x,w);
mtklein9a5c47f2016-07-22 11:05:04 -0700179}
180
181void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400182 if (!fBlitAntiH) {
183 SkRasterPipeline p;
184 p.extend(fShader);
185 p.extend(fColorFilter);
186 this->append_load_d(&p, &fDstPtr);
187 p.extend(fXfermode);
188 p.append(SkRasterPipeline::lerp_constant_float, &fConstantCoverage);
189 this->append_store(&p, &fDstPtr);
190 fBlitAntiH = p.compile();
191 }
mtklein9a5c47f2016-07-22 11:05:04 -0700192
Mike Kleinbd3fe472016-10-25 15:43:46 -0400193 fDstPtr = fDst.writable_addr(0,y);
mtklein9a5c47f2016-07-22 11:05:04 -0700194 for (int16_t run = *runs; run > 0; run = *runs) {
Mike Kleinbd3fe472016-10-25 15:43:46 -0400195 fConstantCoverage = *aa * (1/255.0f);
196 fBlitAntiH(x, run);
mtklein9a5c47f2016-07-22 11:05:04 -0700197
198 x += run;
199 runs += run;
200 aa += run;
201 }
202}
203
204void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
205 if (mask.fFormat == SkMask::kBW_Format) {
206 // TODO: native BW masks?
207 return INHERITED::blitMask(mask, clip);
208 }
209
Mike Kleinbd3fe472016-10-25 15:43:46 -0400210 if (mask.fFormat == SkMask::kA8_Format && !fBlitMaskA8) {
mtklein9a5c47f2016-07-22 11:05:04 -0700211 SkRasterPipeline p;
212 p.extend(fShader);
213 p.extend(fColorFilter);
Mike Kleinbd3fe472016-10-25 15:43:46 -0400214 this->append_load_d(&p, &fDstPtr);
mtklein9a5c47f2016-07-22 11:05:04 -0700215 p.extend(fXfermode);
Mike Kleinbd3fe472016-10-25 15:43:46 -0400216 p.append(SkRasterPipeline::lerp_u8, &fMaskPtr);
217 this->append_store(&p, &fDstPtr);
218 fBlitMaskA8 = p.compile();
219 }
220
221 if (mask.fFormat == SkMask::kLCD16_Format && !fBlitMaskLCD16) {
222 SkRasterPipeline p;
223 p.extend(fShader);
224 p.extend(fColorFilter);
225 this->append_load_d(&p, &fDstPtr);
226 p.extend(fXfermode);
227 p.append(SkRasterPipeline::lerp_565, &fMaskPtr);
228 this->append_store(&p, &fDstPtr);
229 fBlitMaskLCD16 = p.compile();
230 }
231
232 int x = clip.left();
233 for (int y = clip.top(); y < clip.bottom(); y++) {
234 fDstPtr = fDst.writable_addr(0,y);
235
mtklein9a5c47f2016-07-22 11:05:04 -0700236 switch (mask.fFormat) {
237 case SkMask::kA8_Format:
Mike Kleinbd3fe472016-10-25 15:43:46 -0400238 fMaskPtr = mask.getAddr8(x,y)-x;
239 fBlitMaskA8(x, clip.width());
mtklein9a5c47f2016-07-22 11:05:04 -0700240 break;
241 case SkMask::kLCD16_Format:
Mike Kleinbd3fe472016-10-25 15:43:46 -0400242 fMaskPtr = mask.getAddrLCD16(x,y)-x;
243 fBlitMaskLCD16(x, clip.width());
mtklein9a5c47f2016-07-22 11:05:04 -0700244 break;
Mike Kleinbd3fe472016-10-25 15:43:46 -0400245 default:
246 // TODO
247 break;
mtklein9a5c47f2016-07-22 11:05:04 -0700248 }
mtklein9a5c47f2016-07-22 11:05:04 -0700249 }
250}