OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2012 The Android Open Source Project | |
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 "SkBlendImageFilter.h" | |
9 #include "SkCanvas.h" | |
10 #include "SkColorPriv.h" | |
11 #include "SkFlattenableBuffers.h" | |
12 #if SK_SUPPORT_GPU | |
13 #include "GrContext.h" | |
14 #include "gl/GrGLEffect.h" | |
15 #include "gl/GrGLEffectMatrix.h" | |
16 #include "GrTBackendEffectFactory.h" | |
17 #include "SkImageFilterUtils.h" | |
18 #endif | |
19 | |
20 namespace { | |
21 | |
22 SkXfermode::Mode modeToXfermode(SkBlendImageFilter::Mode mode) { | |
23 switch (mode) { | |
24 case SkBlendImageFilter::kNormal_Mode: | |
25 return SkXfermode::kSrcOver_Mode; | |
26 case SkBlendImageFilter::kMultiply_Mode: | |
27 return SkXfermode::kMultiply_Mode; | |
28 case SkBlendImageFilter::kScreen_Mode: | |
29 return SkXfermode::kScreen_Mode; | |
30 case SkBlendImageFilter::kDarken_Mode: | |
31 return SkXfermode::kDarken_Mode; | |
32 case SkBlendImageFilter::kLighten_Mode: | |
33 return SkXfermode::kLighten_Mode; | |
34 } | |
35 SkASSERT(0); | |
36 return SkXfermode::kSrcOver_Mode; | |
37 } | |
38 | |
39 }; | |
40 | |
41 /////////////////////////////////////////////////////////////////////////////// | |
42 | |
43 SkBlendImageFilter::SkBlendImageFilter(SkBlendImageFilter::Mode mode, SkImageFil
ter* background, SkImageFilter* foreground) | |
44 : INHERITED(background, foreground), fMode(mode) | |
45 { | |
46 } | |
47 | |
48 SkBlendImageFilter::~SkBlendImageFilter() { | |
49 } | |
50 | |
51 SkBlendImageFilter::SkBlendImageFilter(SkFlattenableReadBuffer& buffer) | |
52 : INHERITED(buffer) | |
53 { | |
54 fMode = (SkBlendImageFilter::Mode) buffer.readInt(); | |
55 } | |
56 | |
57 void SkBlendImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { | |
58 this->INHERITED::flatten(buffer); | |
59 buffer.writeInt((int) fMode); | |
60 } | |
61 | |
62 bool SkBlendImageFilter::onFilterImage(Proxy* proxy, | |
63 const SkBitmap& src, | |
64 const SkMatrix& ctm, | |
65 SkBitmap* dst, | |
66 SkIPoint* offset) { | |
67 SkBitmap background, foreground = src; | |
68 SkImageFilter* backgroundInput = getBackgroundInput(); | |
69 SkImageFilter* foregroundInput = getForegroundInput(); | |
70 SkASSERT(NULL != backgroundInput); | |
71 SkIPoint backgroundOffset = SkIPoint::Make(0, 0); | |
72 if (!backgroundInput->filterImage(proxy, src, ctm, &background, &backgroundO
ffset)) { | |
73 return false; | |
74 } | |
75 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); | |
76 if (foregroundInput && | |
77 !foregroundInput->filterImage(proxy, src, ctm, &foreground, &foregroundO
ffset)) { | |
78 return false; | |
79 } | |
80 SkAutoLockPixels alp_foreground(foreground), alp_background(background); | |
81 if (!foreground.getPixels() || !background.getPixels()) { | |
82 return false; | |
83 } | |
84 dst->setConfig(background.config(), background.width(), background.height())
; | |
85 dst->allocPixels(); | |
86 SkCanvas canvas(*dst); | |
87 SkPaint paint; | |
88 paint.setXfermodeMode(SkXfermode::kSrc_Mode); | |
89 canvas.drawBitmap(background, SkIntToScalar(backgroundOffset.fX), | |
90 SkIntToScalar(backgroundOffset.fY), &paint); | |
91 paint.setXfermodeMode(modeToXfermode(fMode)); | |
92 canvas.drawBitmap(foreground, SkIntToScalar(foregroundOffset.fX), | |
93 SkIntToScalar(foregroundOffset.fY), &paint); | |
94 return true; | |
95 } | |
96 | |
97 /////////////////////////////////////////////////////////////////////////////// | |
98 | |
99 #if SK_SUPPORT_GPU | |
100 class GrGLBlendEffect : public GrGLEffect { | |
101 public: | |
102 GrGLBlendEffect(const GrBackendEffectFactory&, const GrDrawEffect&); | |
103 virtual ~GrGLBlendEffect(); | |
104 | |
105 virtual void emitCode(GrGLShaderBuilder*, | |
106 const GrDrawEffect&, | |
107 EffectKey, | |
108 const char* outputColor, | |
109 const char* inputColor, | |
110 const TextureSamplerArray&) SK_OVERRIDE; | |
111 | |
112 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); | |
113 | |
114 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER
RIDE; | |
115 | |
116 private: | |
117 static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType; | |
118 | |
119 SkBlendImageFilter::Mode fMode; | |
120 GrGLEffectMatrix fForegroundEffectMatrix; | |
121 GrGLEffectMatrix fBackgroundEffectMatrix; | |
122 | |
123 typedef GrGLEffect INHERITED; | |
124 }; | |
125 | |
126 /////////////////////////////////////////////////////////////////////////////// | |
127 | |
128 class GrBlendEffect : public GrEffect { | |
129 public: | |
130 static GrEffectRef* Create(SkBlendImageFilter::Mode mode, | |
131 GrTexture* foreground, | |
132 const SkIPoint& foregroundOffset, | |
133 GrTexture* background, | |
134 const SkIPoint& backgroundOffset) { | |
135 AutoEffectUnref effect(SkNEW_ARGS(GrBlendEffect, (mode, foreground, fore
groundOffset, | |
136 background, background
Offset))); | |
137 return CreateEffectRef(effect); | |
138 } | |
139 | |
140 virtual ~GrBlendEffect(); | |
141 | |
142 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; | |
143 SkBlendImageFilter::Mode mode() const { return fMode; } | |
144 const SkMatrix& foregroundMatrix() const { return fForegroundMatrix; } | |
145 const SkMatrix& backgroundMatrix() const { return fBackgroundMatrix; } | |
146 | |
147 typedef GrGLBlendEffect GLEffect; | |
148 static const char* Name() { return "Blend"; } | |
149 | |
150 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags
) const SK_OVERRIDE; | |
151 | |
152 private: | |
153 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; | |
154 | |
155 GrBlendEffect(SkBlendImageFilter::Mode mode, | |
156 GrTexture* foreground, const SkIPoint& foregroundOffset, | |
157 GrTexture* background, const SkIPoint& backgroundOffset); | |
158 GrTextureAccess fForegroundAccess; | |
159 SkMatrix fForegroundMatrix; | |
160 GrTextureAccess fBackgroundAccess; | |
161 SkMatrix fBackgroundMatrix; | |
162 SkBlendImageFilter::Mode fMode; | |
163 | |
164 typedef GrEffect INHERITED; | |
165 }; | |
166 | |
167 bool SkBlendImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBit
map* result, | |
168 SkIPoint* offset) { | |
169 SkBitmap backgroundBM; | |
170 SkIPoint backgroundOffset = SkIPoint::Make(0, 0); | |
171 if (!SkImageFilterUtils::GetInputResultGPU(getBackgroundInput(), proxy, src,
&backgroundBM, | |
172 &backgroundOffset)) { | |
173 return false; | |
174 } | |
175 GrTexture* background = backgroundBM.getTexture(); | |
176 SkBitmap foregroundBM; | |
177 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); | |
178 if (!SkImageFilterUtils::GetInputResultGPU(getForegroundInput(), proxy, src,
&foregroundBM, | |
179 &foregroundOffset)) { | |
180 return false; | |
181 } | |
182 GrTexture* foreground = foregroundBM.getTexture(); | |
183 GrContext* context = foreground->getContext(); | |
184 | |
185 GrTextureDesc desc; | |
186 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; | |
187 desc.fWidth = src.width(); | |
188 desc.fHeight = src.height(); | |
189 desc.fConfig = kSkia8888_GrPixelConfig; | |
190 | |
191 GrAutoScratchTexture ast(context, desc); | |
192 SkAutoTUnref<GrTexture> dst(ast.detach()); | |
193 | |
194 GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); | |
195 | |
196 GrPaint paint; | |
197 paint.addColorEffect(GrBlendEffect::Create(fMode, | |
198 foreground, foregroundOffset, | |
199 background, backgroundOffset))->u
nref(); | |
200 SkRect srcRect; | |
201 src.getBounds(&srcRect); | |
202 context->drawRect(paint, srcRect); | |
203 return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), resul
t); | |
204 } | |
205 | |
206 /////////////////////////////////////////////////////////////////////////////// | |
207 | |
208 GrBlendEffect::GrBlendEffect(SkBlendImageFilter::Mode mode, | |
209 GrTexture* foreground, | |
210 const SkIPoint& foregroundOffset, | |
211 GrTexture* background, | |
212 const SkIPoint& backgroundOffset) | |
213 : fForegroundAccess(foreground) | |
214 , fBackgroundAccess(background) | |
215 , fMode(mode) { | |
216 this->addTextureAccess(&fForegroundAccess); | |
217 this->addTextureAccess(&fBackgroundAccess); | |
218 fForegroundMatrix = GrEffect::MakeDivByTextureWHMatrix(foreground); | |
219 fForegroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), | |
220 SkIntToScalar(-foregroundOffset.fY)); | |
221 fBackgroundMatrix = GrEffect::MakeDivByTextureWHMatrix(background); | |
222 fBackgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), | |
223 SkIntToScalar(-backgroundOffset.fY)); | |
224 } | |
225 | |
226 GrBlendEffect::~GrBlendEffect() { | |
227 } | |
228 | |
229 bool GrBlendEffect::onIsEqual(const GrEffect& sBase) const { | |
230 const GrBlendEffect& s = CastEffect<GrBlendEffect>(sBase); | |
231 return fForegroundAccess.getTexture() == s.fForegroundAccess.getTexture() && | |
232 fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture() && | |
233 fMode == s.fMode; | |
234 } | |
235 | |
236 const GrBackendEffectFactory& GrBlendEffect::getFactory() const { | |
237 return GrTBackendEffectFactory<GrBlendEffect>::getInstance(); | |
238 } | |
239 | |
240 void GrBlendEffect::getConstantColorComponents(GrColor* color, uint32_t* validFl
ags) const { | |
241 // The output alpha is always 1 - (1 - FGa) * (1 - BGa). So if either FGa or
BGa is known to | |
242 // be one then the output alpha is one. (This effect ignores its input. We s
hould have a way to | |
243 // communicate this.) | |
244 if (GrPixelConfigIsOpaque(fForegroundAccess.getTexture()->config()) || | |
245 GrPixelConfigIsOpaque(fBackgroundAccess.getTexture()->config())) { | |
246 *validFlags = kA_GrColorComponentFlag; | |
247 *color = GrColorPackRGBA(0, 0, 0, 0xff); | |
248 } else { | |
249 *validFlags = 0; | |
250 } | |
251 } | |
252 | |
253 /////////////////////////////////////////////////////////////////////////////// | |
254 | |
255 GrGLBlendEffect::GrGLBlendEffect(const GrBackendEffectFactory& factory, | |
256 const GrDrawEffect& drawEffect) | |
257 : INHERITED(factory) | |
258 , fMode(drawEffect.castEffect<GrBlendEffect>().mode()) | |
259 , fForegroundEffectMatrix(kCoordsType) | |
260 , fBackgroundEffectMatrix(kCoordsType) { | |
261 } | |
262 | |
263 GrGLBlendEffect::~GrGLBlendEffect() { | |
264 } | |
265 | |
266 void GrGLBlendEffect::emitCode(GrGLShaderBuilder* builder, | |
267 const GrDrawEffect&, | |
268 EffectKey key, | |
269 const char* outputColor, | |
270 const char* inputColor, | |
271 const TextureSamplerArray& samplers) { | |
272 const char* fgCoords; | |
273 const char* bgCoords; | |
274 GrSLType fgCoordsType = fForegroundEffectMatrix.emitCode(builder, key, &fgCo
ords, NULL, "FG"); | |
275 GrSLType bgCoordsType = fBackgroundEffectMatrix.emitCode(builder, key, &bgCo
ords, NULL, "BG"); | |
276 | |
277 const char* bgColor = "bgColor"; | |
278 const char* fgColor = "fgColor"; | |
279 | |
280 builder->fsCodeAppendf("\t\tvec4 %s = ", fgColor); | |
281 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | |
282 samplers[0], | |
283 fgCoords, | |
284 fgCoordsType); | |
285 builder->fsCodeAppend(";\n"); | |
286 | |
287 builder->fsCodeAppendf("\t\tvec4 %s = ", bgColor); | |
288 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | |
289 samplers[1], | |
290 bgCoords, | |
291 bgCoordsType); | |
292 builder->fsCodeAppendf(";\n"); | |
293 | |
294 builder->fsCodeAppendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - %s.b);\n", ou
tputColor, bgColor, fgColor); | |
295 switch (fMode) { | |
296 case SkBlendImageFilter::kNormal_Mode: | |
297 builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + %s.rgb;\n",
outputColor, fgColor, bgColor, fgColor); | |
298 break; | |
299 case SkBlendImageFilter::kMultiply_Mode: | |
300 builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + (1.0 - %s.a
) * %s.rgb + %s.rgb * %s.rgb;\n", outputColor, fgColor, bgColor, bgColor, fgColo
r, fgColor, bgColor); | |
301 break; | |
302 case SkBlendImageFilter::kScreen_Mode: | |
303 builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - %s.rgb * %s.rgb;\
n", outputColor, bgColor, fgColor, fgColor, bgColor); | |
304 break; | |
305 case SkBlendImageFilter::kDarken_Mode: | |
306 builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb,
(1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bg
Color, fgColor, bgColor); | |
307 break; | |
308 case SkBlendImageFilter::kLighten_Mode: | |
309 builder->fsCodeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb,
(1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bg
Color, fgColor, bgColor); | |
310 break; | |
311 } | |
312 } | |
313 | |
314 void GrGLBlendEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect
& drawEffect) { | |
315 const GrBlendEffect& blend = drawEffect.castEffect<GrBlendEffect>(); | |
316 GrTexture* fgTex = blend.texture(0); | |
317 GrTexture* bgTex = blend.texture(1); | |
318 fForegroundEffectMatrix.setData(uman, | |
319 blend.foregroundMatrix(), | |
320 drawEffect, | |
321 fgTex); | |
322 fBackgroundEffectMatrix.setData(uman, | |
323 blend.backgroundMatrix(), | |
324 drawEffect, | |
325 bgTex); | |
326 | |
327 } | |
328 | |
329 GrGLEffect::EffectKey GrGLBlendEffect::GenKey(const GrDrawEffect& drawEffect, co
nst GrGLCaps&) { | |
330 const GrBlendEffect& blend = drawEffect.castEffect<GrBlendEffect>(); | |
331 | |
332 GrTexture* fgTex = blend.texture(0); | |
333 GrTexture* bgTex = blend.texture(1); | |
334 | |
335 EffectKey fgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatri
x(fgTex), | |
336 drawEffect, | |
337 kCoordsType, | |
338 fgTex); | |
339 | |
340 EffectKey bgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatri
x(bgTex), | |
341 drawEffect, | |
342 kCoordsType, | |
343 bgTex); | |
344 bgKey <<= GrGLEffectMatrix::kKeyBits; | |
345 EffectKey modeKey = blend.mode() << (2 * GrGLEffectMatrix::kKeyBits); | |
346 | |
347 return modeKey | bgKey | fgKey; | |
348 } | |
349 #endif | |
OLD | NEW |