blob: 2ada336cd86505bd793a4e1f5f7b1ec74e4582dc [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
50 typedef SkBlitter INHERITED;
51};
52
53SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
54 const SkPaint& paint,
55 SkTBlitterAllocator* alloc) {
56 return SkRasterPipelineBlitter::Create(dst, paint, alloc);
57}
58
mtklein8e4373f2016-07-22 14:20:27 -070059static bool supported(const SkImageInfo& info) {
mtklein8e4373f2016-07-22 14:20:27 -070060 switch (info.colorType()) {
mtklein4e90e3e2016-07-25 14:35:31 -070061 case kN32_SkColorType: return info.gammaCloseToSRGB();
62 case kRGBA_F16_SkColorType: return true;
63 case kRGB_565_SkColorType: return true;
64 default: return false;
mtklein8e4373f2016-07-22 14:20:27 -070065 }
66}
mtklein9a5c47f2016-07-22 11:05:04 -070067
68template <typename Effect>
69static bool append_effect_stages(const Effect* effect, SkRasterPipeline* pipeline) {
70 return !effect || effect->appendStages(pipeline);
71}
72
73
74SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
75 const SkPaint& paint,
76 SkTBlitterAllocator* alloc) {
mtklein8e4373f2016-07-22 14:20:27 -070077 if (!supported(dst.info())) {
78 return nullptr;
mtklein9a5c47f2016-07-22 11:05:04 -070079 }
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(paint.getXfermode(), &xfermode )) {
87 return nullptr;
88 }
89
mtklein8e4373f2016-07-22 14:20:27 -070090 uint32_t paintColor = paint.getColor();
91
92 SkColor4f color;
mtklein4e90e3e2016-07-25 14:35:31 -070093 if (SkImageInfoIsGammaCorrect(dst.info())) {
mtklein8e4373f2016-07-22 14:20:27 -070094 color = SkColor4f::FromColor(paintColor);
95 } else {
96 swizzle_rb(SkNx_cast<float>(Sk4b::Load(&paintColor)) * (1/255.0f)).store(&color);
97 }
98
mtklein9a5c47f2016-07-22 11:05:04 -070099 auto blitter = alloc->createT<SkRasterPipelineBlitter>(
100 dst,
101 shader, colorFilter, xfermode,
mtklein8e4373f2016-07-22 14:20:27 -0700102 color.premul());
mtklein9a5c47f2016-07-22 11:05:04 -0700103
104 if (!paint.getShader()) {
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400105 blitter->fShader.append(SkOpts::constant_color, &blitter->fPaintColor);
mtklein9a5c47f2016-07-22 11:05:04 -0700106 }
107 if (!paint.getXfermode()) {
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400108 blitter->fXfermode.append(SkOpts::srcover);
mtklein9a5c47f2016-07-22 11:05:04 -0700109 }
110
111 return blitter;
112}
113
mtklein8e4373f2016-07-22 14:20:27 -0700114void 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()) {
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400120 p->append(SkOpts::load_d_srgb_body, SkOpts::load_d_srgb_tail, dst);
mtklein8e4373f2016-07-22 14:20:27 -0700121 }
122 break;
mtklein4e90e3e2016-07-25 14:35:31 -0700123 case kRGBA_F16_SkColorType:
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400124 p->append(SkOpts::load_d_f16_body, SkOpts::load_d_f16_tail, dst);
mtklein4e90e3e2016-07-25 14:35:31 -0700125 break;
mtklein8e4373f2016-07-22 14:20:27 -0700126 case kRGB_565_SkColorType:
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400127 p->append(SkOpts::load_d_565_body, SkOpts::load_d_565_tail, dst);
mtklein8e4373f2016-07-22 14:20:27 -0700128 break;
129 default: break;
130 }
131}
132
133void 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()) {
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400139 p->append(SkOpts::store_srgb_body, SkOpts::store_srgb_tail, dst);
mtklein8e4373f2016-07-22 14:20:27 -0700140 }
141 break;
mtklein4e90e3e2016-07-25 14:35:31 -0700142 case kRGBA_F16_SkColorType:
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400143 p->append(SkOpts::store_f16_body, SkOpts::store_f16_tail, dst);
mtklein4e90e3e2016-07-25 14:35:31 -0700144 break;
mtklein8e4373f2016-07-22 14:20:27 -0700145 case kRGB_565_SkColorType:
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400146 p->append(SkOpts::store_565_body, SkOpts::store_565_tail, dst);
mtklein8e4373f2016-07-22 14:20:27 -0700147 break;
148 default: break;
149 }
150}
151
mtklein9a5c47f2016-07-22 11:05:04 -0700152void 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);
mtklein8e4373f2016-07-22 14:20:27 -0700158 this->append_load_d(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700159 p.extend(fXfermode);
mtklein8e4373f2016-07-22 14:20:27 -0700160 this->append_store(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700161
162 p.run(x, w);
163}
164
165void 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);
mtklein8e4373f2016-07-22 14:20:27 -0700172 this->append_load_d(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700173 p.extend(fXfermode);
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400174 p.append(SkOpts::lerp_constant_float, &coverage);
mtklein8e4373f2016-07-22 14:20:27 -0700175 this->append_store(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700176
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
187void 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);
mtklein8e4373f2016-07-22 14:20:27 -0700200 this->append_load_d(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700201 p.extend(fXfermode);
202 switch (mask.fFormat) {
203 case SkMask::kA8_Format:
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400204 p.append(SkOpts::lerp_u8_body, SkOpts::lerp_u8_tail, mask.getAddr8(x,y)-x);
mtklein9a5c47f2016-07-22 11:05:04 -0700205 break;
206 case SkMask::kLCD16_Format:
Mike Kleinbaaf8ad2016-09-29 09:04:15 -0400207 p.append(SkOpts::lerp_565_body, SkOpts::lerp_565_tail, mask.getAddrLCD16(x,y)-x);
mtklein9a5c47f2016-07-22 11:05:04 -0700208 break;
209 default: break;
210 }
mtklein8e4373f2016-07-22 14:20:27 -0700211 this->append_store(&p, dst);
mtklein9a5c47f2016-07-22 11:05:04 -0700212
213 p.run(x, clip.width());
214 }
215}