OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2013 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 "SkArithmeticImageFilter.h" | |
9 #include "SkArithmeticMode.h" | |
10 #include "SkCanvas.h" | |
11 #include "SkColorPriv.h" | |
12 #include "SkFlattenableBuffers.h" | |
13 #if SK_SUPPORT_GPU | |
14 #include "GrContext.h" | |
15 #include "gl/GrGLEffect.h" | |
16 #include "gl/GrGLEffectMatrix.h" | |
17 #include "GrTBackendEffectFactory.h" | |
18 #include "SkImageFilterUtils.h" | |
19 #endif | |
20 | |
21 /////////////////////////////////////////////////////////////////////////////// | |
22 | |
23 SkArithmeticImageFilter::SkArithmeticImageFilter(SkScalar k1, SkScalar k2, SkSca lar k3, SkScalar k4, SkImageFilter* background, SkImageFilter* foreground) | |
24 : INHERITED(background, foreground), fK1(k1), fK2(k2), fK3(k3), fK4(k4) | |
25 { | |
26 } | |
27 | |
28 SkArithmeticImageFilter::~SkArithmeticImageFilter() { | |
29 } | |
30 | |
31 SkArithmeticImageFilter::SkArithmeticImageFilter(SkFlattenableReadBuffer& buffer ) | |
32 : INHERITED(buffer) | |
33 { | |
34 fK1 = buffer.readScalar(); | |
35 fK2 = buffer.readScalar(); | |
36 fK3 = buffer.readScalar(); | |
37 fK4 = buffer.readScalar(); | |
38 } | |
39 | |
40 void SkArithmeticImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { | |
41 this->INHERITED::flatten(buffer); | |
42 buffer.writeScalar(fK1); | |
43 buffer.writeScalar(fK2); | |
44 buffer.writeScalar(fK3); | |
45 buffer.writeScalar(fK4); | |
46 } | |
47 | |
48 bool SkArithmeticImageFilter::onFilterImage(Proxy* proxy, | |
49 const SkBitmap& src, | |
50 const SkMatrix& ctm, | |
51 SkBitmap* dst, | |
52 SkIPoint* offset) { | |
53 SkBitmap background = src, foreground = src; | |
54 SkImageFilter* foregroundInput = getInput(0); | |
55 SkImageFilter* backgroundInput = getInput(1); | |
56 if (backgroundInput && !backgroundInput->filterImage(proxy, src, ctm, &backg round, offset)) { | |
57 return false; | |
58 } | |
59 if (foregroundInput && !foregroundInput->filterImage(proxy, src, ctm, &foreg round, offset)) { | |
60 return false; | |
61 } | |
62 dst->setConfig(background.config(), background.width(), background.height()) ; | |
63 dst->allocPixels(); | |
64 SkCanvas canvas(*dst); | |
65 SkPaint paint; | |
66 SkAutoTUnref<SkXfermode> mode(SkArithmeticMode::Create(fK1, fK2, fK3, fK4)); | |
67 paint.setXfermodeMode(SkXfermode::kSrc_Mode); | |
68 canvas.drawBitmap(background, 0, 0, &paint); | |
69 paint.setXfermode(mode); | |
70 canvas.drawBitmap(foreground, 0, 0, &paint); | |
71 return true; | |
72 } | |
73 | |
74 /////////////////////////////////////////////////////////////////////////////// | |
75 | |
76 #if SK_SUPPORT_GPU | |
77 class GrGLArithmeticEffect : public GrGLEffect { | |
78 public: | |
79 GrGLArithmeticEffect(const GrBackendEffectFactory&, const GrDrawEffect&); | |
80 virtual ~GrGLArithmeticEffect(); | |
81 | |
82 virtual void emitCode(GrGLShaderBuilder*, | |
83 const GrDrawEffect&, | |
84 EffectKey, | |
85 const char* outputColor, | |
86 const char* inputColor, | |
87 const TextureSamplerArray&) SK_OVERRIDE; | |
88 | |
89 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); | |
90 | |
91 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER RIDE; | |
92 | |
93 private: | |
94 static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType; | |
95 | |
96 GrGLUniformManager::UniformHandle fK1Uni, fK2Uni, fK3Uni, fK4Uni; | |
97 GrGLEffectMatrix fForegroundEffectMatrix; | |
98 GrGLEffectMatrix fBackgroundEffectMatrix; | |
99 | |
100 typedef GrGLEffect INHERITED; | |
101 }; | |
102 | |
103 /////////////////////////////////////////////////////////////////////////////// | |
104 | |
105 class GrArithmeticEffect : public GrEffect { | |
106 public: | |
107 static GrEffectRef* Create(float k1, float k2, float k3, float k4, | |
108 GrTexture* foreground, | |
109 GrTexture* background) { | |
110 AutoEffectUnref effect(SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4, f oreground, background))); | |
111 return CreateEffectRef(effect); | |
112 } | |
113 | |
114 virtual ~GrArithmeticEffect(); | |
115 | |
116 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; | |
117 | |
118 typedef GrGLArithmeticEffect GLEffect; | |
119 static const char* Name() { return "Arithmetic"; } | |
120 | |
121 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags ) const SK_OVERRIDE; | |
122 | |
123 float k1() const { return fK1; } | |
124 float k2() const { return fK2; } | |
125 float k3() const { return fK3; } | |
126 float k4() const { return fK4; } | |
127 | |
128 private: | |
129 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; | |
130 | |
131 GrArithmeticEffect(float k1, float k2, float k3, float k4, GrTexture* foregr ound, GrTexture* background); | |
132 float fK1, fK2, fK3, fK4; | |
133 GrTextureAccess fForegroundAccess; | |
134 GrTextureAccess fBackgroundAccess; | |
135 | |
136 typedef GrEffect INHERITED; | |
137 | |
138 }; | |
139 | |
140 bool SkArithmeticImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) { | |
141 SkBitmap backgroundBM; | |
142 if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &backgro undBM)) { | |
143 return false; | |
144 } | |
145 GrTexture* background = (GrTexture*) backgroundBM.getTexture(); | |
146 SkBitmap foregroundBM; | |
147 if (!SkImageFilterUtils::GetInputResultGPU(getInput(1), proxy, src, &foregro undBM)) { | |
148 return false; | |
149 } | |
150 GrTexture* foreground = (GrTexture*) foregroundBM.getTexture(); | |
151 GrContext* context = foreground->getContext(); | |
152 | |
153 GrTextureDesc desc; | |
154 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; | |
155 desc.fWidth = src.width(); | |
156 desc.fHeight = src.height(); | |
157 desc.fConfig = kSkia8888_GrPixelConfig; | |
158 | |
159 GrAutoScratchTexture ast(context, desc); | |
160 SkAutoTUnref<GrTexture> dst(ast.detach()); | |
161 | |
162 GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); | |
163 | |
164 GrPaint paint; | |
165 paint.colorStage(0)->setEffect( | |
166 GrArithmeticEffect::Create(SkScalarToFloat(fK1), | |
167 SkScalarToFloat(fK2), | |
168 SkScalarToFloat(fK3), | |
169 SkScalarToFloat(fK4), | |
170 foreground, | |
171 background))->unref(); | |
172 SkRect srcRect; | |
173 src.getBounds(&srcRect); | |
174 context->drawRect(paint, srcRect); | |
175 return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), resul t); | |
176 } | |
177 | |
178 /////////////////////////////////////////////////////////////////////////////// | |
179 | |
180 GrArithmeticEffect::GrArithmeticEffect(float k1, | |
181 float k2, | |
182 float k3, | |
183 float k4, | |
184 GrTexture* foreground, | |
185 GrTexture* background) | |
186 : fK1(k1), fK2(k2), fK3(k3), fK4(k4) | |
187 , fForegroundAccess(foreground) | |
188 , fBackgroundAccess(background) { | |
189 this->addTextureAccess(&fForegroundAccess); | |
190 this->addTextureAccess(&fBackgroundAccess); | |
191 } | |
192 | |
193 GrArithmeticEffect::~GrArithmeticEffect() { | |
194 } | |
195 | |
196 bool GrArithmeticEffect::onIsEqual(const GrEffect& sBase) const { | |
197 const GrArithmeticEffect& s = CastEffect<GrArithmeticEffect>(sBase); | |
198 return fForegroundAccess.getTexture() == s.fForegroundAccess.getTexture() && | |
199 fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture() && | |
200 fK1 == s.fK1 && | |
201 fK2 == s.fK2 && | |
202 fK3 == s.fK3 && | |
203 fK4 == s.fK4; | |
204 } | |
205 | |
206 const GrBackendEffectFactory& GrArithmeticEffect::getFactory() const { | |
207 return GrTBackendEffectFactory<GrArithmeticEffect>::getInstance(); | |
208 } | |
209 | |
210 void GrArithmeticEffect::getConstantColorComponents(GrColor* color, uint32_t* va lidFlags) const { | |
211 // TODO: optimize this | |
212 *validFlags = 0; | |
213 } | |
214 | |
215 /////////////////////////////////////////////////////////////////////////////// | |
216 | |
217 GrGLArithmeticEffect::GrGLArithmeticEffect(const GrBackendEffectFactory& factory , | |
218 const GrDrawEffect& drawEffect) | |
219 : INHERITED(factory) | |
220 , fForegroundEffectMatrix(kCoordsType) | |
221 , fBackgroundEffectMatrix(kCoordsType) { | |
222 } | |
223 | |
224 GrGLArithmeticEffect::~GrGLArithmeticEffect() { | |
225 } | |
226 | |
227 void GrGLArithmeticEffect::emitCode(GrGLShaderBuilder* builder, | |
228 const GrDrawEffect&, | |
229 EffectKey key, | |
230 const char* outputColor, | |
231 const char* inputColor, | |
232 const TextureSamplerArray& samplers) { | |
233 const char* fgCoords; | |
234 const char* bgCoords; | |
235 GrSLType fgCoordsType = fForegroundEffectMatrix.emitCode(builder, key, &fgCo ords, NULL, "FG"); | |
236 GrSLType bgCoordsType = fBackgroundEffectMatrix.emitCode(builder, key, &bgCo ords, NULL, "BG"); | |
237 | |
238 fK1Uni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | |
bsalomon
2013/05/28 14:21:20
Just wondering if it'd make sense to use a vec4 fo
Stephen White
2013/05/28 15:08:34
Yeah, I thought of that. Just thought it might mak
| |
239 kFloat_GrSLType, "k1"); | |
240 const char* k1Uni = builder->getUniformCStr(fK1Uni); | |
241 | |
242 fK2Uni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | |
243 kFloat_GrSLType, "k2"); | |
244 const char* k2Uni = builder->getUniformCStr(fK2Uni); | |
245 | |
246 fK3Uni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | |
247 kFloat_GrSLType, "k3"); | |
248 const char* k3Uni = builder->getUniformCStr(fK3Uni); | |
249 | |
250 fK4Uni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, | |
251 kFloat_GrSLType, "k4"); | |
252 const char* k4Uni = builder->getUniformCStr(fK4Uni); | |
253 | |
254 builder->fsCodeAppend("\t\tvec4 fgColor = "); | |
255 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | |
256 samplers[0], | |
257 fgCoords, | |
258 fgCoordsType); | |
259 builder->fsCodeAppend(";\n"); | |
260 | |
261 builder->fsCodeAppend("\t\tvec4 bgColor = "); | |
262 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | |
263 samplers[1], | |
264 bgCoords, | |
265 bgCoordsType); | |
266 builder->fsCodeAppend(";\n"); | |
267 builder->fsCodeAppend("\t\tfgColor.rgb = clamp(fgColor.rgb / fgColor.a, 0.0, 1.0);\n"); | |
bsalomon
2013/05/28 14:21:20
What does clamp do if the first param is NaN?
Stephen White
2013/05/28 15:08:34
It returns zero, as far as I can tell (empirically
| |
268 builder->fsCodeAppend("\t\tbgColor.rgb = clamp(bgColor.rgb / bgColor.a, 0.0, 1.0);\n"); | |
269 | |
270 builder->fsCodeAppendf("\t\t%s = %s * bgColor * fgColor + %s * bgColor + %s * fgColor + %s;\n", outputColor, k1Uni, k2Uni, k3Uni, k4Uni); | |
271 builder->fsCodeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outpu tColor); | |
272 builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor); | |
273 } | |
274 | |
275 void GrGLArithmeticEffect::setData(const GrGLUniformManager& uman, const GrDrawE ffect& drawEffect) { | |
276 const GrArithmeticEffect& arith = drawEffect.castEffect<GrArithmeticEffect>( ); | |
277 GrTexture* fgTex = arith.texture(0); | |
278 GrTexture* bgTex = arith.texture(1); | |
279 fForegroundEffectMatrix.setData(uman, | |
280 GrEffect::MakeDivByTextureWHMatrix(fgTex), | |
281 drawEffect, | |
282 fgTex); | |
283 fBackgroundEffectMatrix.setData(uman, | |
284 GrEffect::MakeDivByTextureWHMatrix(bgTex), | |
285 drawEffect, | |
286 bgTex); | |
287 | |
288 uman.set1f(fK1Uni, arith.k1()); | |
289 uman.set1f(fK2Uni, arith.k2()); | |
290 uman.set1f(fK3Uni, arith.k3()); | |
291 uman.set1f(fK4Uni, arith.k4()); | |
292 } | |
293 | |
294 GrGLEffect::EffectKey GrGLArithmeticEffect::GenKey(const GrDrawEffect& drawEffec t, const GrGLCaps&) { | |
295 const GrArithmeticEffect& arith = drawEffect.castEffect<GrArithmeticEffect>( ); | |
296 | |
297 GrTexture* fgTex = arith.texture(0); | |
298 GrTexture* bgTex = arith.texture(1); | |
299 | |
300 EffectKey fgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatri x(fgTex), | |
301 drawEffect, | |
302 kCoordsType, | |
303 fgTex); | |
304 | |
305 EffectKey bgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatri x(bgTex), | |
306 drawEffect, | |
307 kCoordsType, | |
308 bgTex); | |
309 bgKey <<= GrGLEffectMatrix::kKeyBits; | |
310 return bgKey | fgKey; | |
311 } | |
312 #endif | |
OLD | NEW |