|
1 /* |
|
2 * Copyright 2013 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 "SkDisplacementMapEffect.h" |
|
9 #include "SkReadBuffer.h" |
|
10 #include "SkWriteBuffer.h" |
|
11 #include "SkUnPreMultiply.h" |
|
12 #include "SkColorPriv.h" |
|
13 #if SK_SUPPORT_GPU |
|
14 #include "GrContext.h" |
|
15 #include "GrCoordTransform.h" |
|
16 #include "gl/GrGLEffect.h" |
|
17 #include "GrTBackendEffectFactory.h" |
|
18 #endif |
|
19 |
|
20 namespace { |
|
21 |
|
22 #define kChannelSelectorKeyBits 3; // Max value is 4, so 3 bits are required at most |
|
23 |
|
24 template<SkDisplacementMapEffect::ChannelSelectorType type> |
|
25 uint32_t getValue(SkColor, const SkUnPreMultiply::Scale*) { |
|
26 SkDEBUGFAIL("Unknown channel selector"); |
|
27 return 0; |
|
28 } |
|
29 |
|
30 template<> uint32_t getValue<SkDisplacementMapEffect::kR_ChannelSelectorType>( |
|
31 SkColor l, const SkUnPreMultiply::Scale* table) { |
|
32 return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedR32(l)); |
|
33 } |
|
34 |
|
35 template<> uint32_t getValue<SkDisplacementMapEffect::kG_ChannelSelectorType>( |
|
36 SkColor l, const SkUnPreMultiply::Scale* table) { |
|
37 return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedG32(l)); |
|
38 } |
|
39 |
|
40 template<> uint32_t getValue<SkDisplacementMapEffect::kB_ChannelSelectorType>( |
|
41 SkColor l, const SkUnPreMultiply::Scale* table) { |
|
42 return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedB32(l)); |
|
43 } |
|
44 |
|
45 template<> uint32_t getValue<SkDisplacementMapEffect::kA_ChannelSelectorType>( |
|
46 SkColor l, const SkUnPreMultiply::Scale*) { |
|
47 return SkGetPackedA32(l); |
|
48 } |
|
49 |
|
50 template<SkDisplacementMapEffect::ChannelSelectorType typeX, |
|
51 SkDisplacementMapEffect::ChannelSelectorType typeY> |
|
52 void computeDisplacement(const SkVector& scale, SkBitmap* dst, |
|
53 SkBitmap* displ, const SkIPoint& offset, |
|
54 SkBitmap* src, |
|
55 const SkIRect& bounds) |
|
56 { |
|
57 static const SkScalar Inv8bit = SkScalarDiv(SK_Scalar1, 255.0f); |
|
58 const int srcW = src->width(); |
|
59 const int srcH = src->height(); |
|
60 const SkVector scaleForColor = SkVector::Make(SkScalarMul(scale.fX, Inv8bit), |
|
61 SkScalarMul(scale.fY, Inv8bit)); |
|
62 const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - SkScalarMul(scale.fX, SK_ScalarHalf), |
|
63 SK_ScalarHalf - SkScalarMul(scale.fY, SK_ScalarHalf)); |
|
64 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); |
|
65 SkPMColor* dstPtr = dst->getAddr32(0, 0); |
|
66 for (int y = bounds.top(); y < bounds.bottom(); ++y) { |
|
67 const SkPMColor* displPtr = displ->getAddr32(bounds.left() + offset.fX, |
|
68 y + offset.fY); |
|
69 for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) { |
|
70 const SkScalar displX = SkScalarMul(scaleForColor.fX, |
|
71 SkIntToScalar(getValue<typeX>(*displPtr, table))) + scaleAdj.fX; |
|
72 const SkScalar displY = SkScalarMul(scaleForColor.fY, |
|
73 SkIntToScalar(getValue<typeY>(*displPtr, table))) + scaleAdj.fY; |
|
74 // Truncate the displacement values |
|
75 const int srcX = x + SkScalarTruncToInt(displX); |
|
76 const int srcY = y + SkScalarTruncToInt(displY); |
|
77 *dstPtr++ = ((srcX < 0) || (srcX >= srcW) || (srcY < 0) || (srcY >= srcH)) ? |
|
78 0 : *(src->getAddr32(srcX, srcY)); |
|
79 } |
|
80 } |
|
81 } |
|
82 |
|
83 template<SkDisplacementMapEffect::ChannelSelectorType typeX> |
|
84 void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, |
|
85 const SkVector& scale, SkBitmap* dst, |
|
86 SkBitmap* displ, const SkIPoint& offset, |
|
87 SkBitmap* src, |
|
88 const SkIRect& bounds) |
|
89 { |
|
90 switch (yChannelSelector) { |
|
91 case SkDisplacementMapEffect::kR_ChannelSelectorType: |
|
92 computeDisplacement<typeX, SkDisplacementMapEffect::kR_ChannelSelectorType>( |
|
93 scale, dst, displ, offset, src, bounds); |
|
94 break; |
|
95 case SkDisplacementMapEffect::kG_ChannelSelectorType: |
|
96 computeDisplacement<typeX, SkDisplacementMapEffect::kG_ChannelSelectorType>( |
|
97 scale, dst, displ, offset, src, bounds); |
|
98 break; |
|
99 case SkDisplacementMapEffect::kB_ChannelSelectorType: |
|
100 computeDisplacement<typeX, SkDisplacementMapEffect::kB_ChannelSelectorType>( |
|
101 scale, dst, displ, offset, src, bounds); |
|
102 break; |
|
103 case SkDisplacementMapEffect::kA_ChannelSelectorType: |
|
104 computeDisplacement<typeX, SkDisplacementMapEffect::kA_ChannelSelectorType>( |
|
105 scale, dst, displ, offset, src, bounds); |
|
106 break; |
|
107 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: |
|
108 default: |
|
109 SkDEBUGFAIL("Unknown Y channel selector"); |
|
110 } |
|
111 } |
|
112 |
|
113 void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, |
|
114 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, |
|
115 const SkVector& scale, SkBitmap* dst, |
|
116 SkBitmap* displ, const SkIPoint& offset, |
|
117 SkBitmap* src, |
|
118 const SkIRect& bounds) |
|
119 { |
|
120 switch (xChannelSelector) { |
|
121 case SkDisplacementMapEffect::kR_ChannelSelectorType: |
|
122 computeDisplacement<SkDisplacementMapEffect::kR_ChannelSelectorType>( |
|
123 yChannelSelector, scale, dst, displ, offset, src, bounds); |
|
124 break; |
|
125 case SkDisplacementMapEffect::kG_ChannelSelectorType: |
|
126 computeDisplacement<SkDisplacementMapEffect::kG_ChannelSelectorType>( |
|
127 yChannelSelector, scale, dst, displ, offset, src, bounds); |
|
128 break; |
|
129 case SkDisplacementMapEffect::kB_ChannelSelectorType: |
|
130 computeDisplacement<SkDisplacementMapEffect::kB_ChannelSelectorType>( |
|
131 yChannelSelector, scale, dst, displ, offset, src, bounds); |
|
132 break; |
|
133 case SkDisplacementMapEffect::kA_ChannelSelectorType: |
|
134 computeDisplacement<SkDisplacementMapEffect::kA_ChannelSelectorType>( |
|
135 yChannelSelector, scale, dst, displ, offset, src, bounds); |
|
136 break; |
|
137 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: |
|
138 default: |
|
139 SkDEBUGFAIL("Unknown X channel selector"); |
|
140 } |
|
141 } |
|
142 |
|
143 bool channel_selector_type_is_valid(SkDisplacementMapEffect::ChannelSelectorType cst) { |
|
144 switch (cst) { |
|
145 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: |
|
146 case SkDisplacementMapEffect::kR_ChannelSelectorType: |
|
147 case SkDisplacementMapEffect::kG_ChannelSelectorType: |
|
148 case SkDisplacementMapEffect::kB_ChannelSelectorType: |
|
149 case SkDisplacementMapEffect::kA_ChannelSelectorType: |
|
150 return true; |
|
151 default: |
|
152 break; |
|
153 } |
|
154 return false; |
|
155 } |
|
156 |
|
157 } // end namespace |
|
158 |
|
159 /////////////////////////////////////////////////////////////////////////////// |
|
160 |
|
161 SkDisplacementMapEffect::SkDisplacementMapEffect(ChannelSelectorType xChannelSelector, |
|
162 ChannelSelectorType yChannelSelector, |
|
163 SkScalar scale, |
|
164 SkImageFilter* displacement, |
|
165 SkImageFilter* color, |
|
166 const CropRect* cropRect) |
|
167 : INHERITED(displacement, color, cropRect) |
|
168 , fXChannelSelector(xChannelSelector) |
|
169 , fYChannelSelector(yChannelSelector) |
|
170 , fScale(scale) |
|
171 { |
|
172 } |
|
173 |
|
174 SkDisplacementMapEffect::~SkDisplacementMapEffect() { |
|
175 } |
|
176 |
|
177 SkDisplacementMapEffect::SkDisplacementMapEffect(SkReadBuffer& buffer) |
|
178 : INHERITED(2, buffer) |
|
179 { |
|
180 fXChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt(); |
|
181 fYChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt(); |
|
182 fScale = buffer.readScalar(); |
|
183 buffer.validate(channel_selector_type_is_valid(fXChannelSelector) && |
|
184 channel_selector_type_is_valid(fYChannelSelector) && |
|
185 SkScalarIsFinite(fScale)); |
|
186 } |
|
187 |
|
188 void SkDisplacementMapEffect::flatten(SkWriteBuffer& buffer) const { |
|
189 this->INHERITED::flatten(buffer); |
|
190 buffer.writeInt((int) fXChannelSelector); |
|
191 buffer.writeInt((int) fYChannelSelector); |
|
192 buffer.writeScalar(fScale); |
|
193 } |
|
194 |
|
195 bool SkDisplacementMapEffect::onFilterImage(Proxy* proxy, |
|
196 const SkBitmap& src, |
|
197 const Context& ctx, |
|
198 SkBitmap* dst, |
|
199 SkIPoint* offset) const { |
|
200 SkBitmap displ = src, color = src; |
|
201 const SkImageFilter* colorInput = getColorInput(); |
|
202 const SkImageFilter* displInput = getDisplacementInput(); |
|
203 SkIPoint colorOffset = SkIPoint::Make(0, 0), displOffset = SkIPoint::Make(0, 0); |
|
204 if ((colorInput && !colorInput->filterImage(proxy, src, ctx, &color, &colorOffset)) || |
|
205 (displInput && !displInput->filterImage(proxy, src, ctx, &displ, &displOffset))) { |
|
206 return false; |
|
207 } |
|
208 if ((displ.colorType() != kPMColor_SkColorType) || |
|
209 (color.colorType() != kPMColor_SkColorType)) { |
|
210 return false; |
|
211 } |
|
212 SkIRect bounds; |
|
213 // Since computeDisplacement does bounds checking on color pixel access, we don't need to pad |
|
214 // the color bitmap to bounds here. |
|
215 if (!this->applyCropRect(ctx, color, colorOffset, &bounds)) { |
|
216 return false; |
|
217 } |
|
218 SkIRect displBounds; |
|
219 if (!this->applyCropRect(ctx, proxy, displ, &displOffset, &displBounds, &displ)) { |
|
220 return false; |
|
221 } |
|
222 if (!bounds.intersect(displBounds)) { |
|
223 return false; |
|
224 } |
|
225 SkAutoLockPixels alp_displacement(displ), alp_color(color); |
|
226 if (!displ.getPixels() || !color.getPixels()) { |
|
227 return false; |
|
228 } |
|
229 |
|
230 dst->setConfig(color.config(), bounds.width(), bounds.height()); |
|
231 if (!dst->allocPixels()) { |
|
232 return false; |
|
233 } |
|
234 |
|
235 SkVector scale = SkVector::Make(fScale, fScale); |
|
236 ctx.ctm().mapVectors(&scale, 1); |
|
237 SkIRect colorBounds = bounds; |
|
238 colorBounds.offset(-colorOffset); |
|
239 |
|
240 computeDisplacement(fXChannelSelector, fYChannelSelector, scale, dst, |
|
241 &displ, colorOffset - displOffset, &color, colorBounds); |
|
242 |
|
243 offset->fX = bounds.left(); |
|
244 offset->fY = bounds.top(); |
|
245 return true; |
|
246 } |
|
247 |
|
248 void SkDisplacementMapEffect::computeFastBounds(const SkRect& src, SkRect* dst) const { |
|
249 if (getColorInput()) { |
|
250 getColorInput()->computeFastBounds(src, dst); |
|
251 } else { |
|
252 *dst = src; |
|
253 } |
|
254 dst->outset(fScale * SK_ScalarHalf, fScale * SK_ScalarHalf); |
|
255 } |
|
256 |
|
257 bool SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, |
|
258 SkIRect* dst) const { |
|
259 SkIRect bounds = src; |
|
260 if (getColorInput() && !getColorInput()->filterBounds(src, ctm, &bounds)) { |
|
261 return false; |
|
262 } |
|
263 bounds.outset(SkScalarCeilToInt(fScale * SK_ScalarHalf), |
|
264 SkScalarCeilToInt(fScale * SK_ScalarHalf)); |
|
265 *dst = bounds; |
|
266 return true; |
|
267 } |
|
268 |
|
269 /////////////////////////////////////////////////////////////////////////////// |
|
270 |
|
271 #if SK_SUPPORT_GPU |
|
272 class GrGLDisplacementMapEffect : public GrGLEffect { |
|
273 public: |
|
274 GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory, |
|
275 const GrDrawEffect& drawEffect); |
|
276 virtual ~GrGLDisplacementMapEffect(); |
|
277 |
|
278 virtual void emitCode(GrGLShaderBuilder*, |
|
279 const GrDrawEffect&, |
|
280 EffectKey, |
|
281 const char* outputColor, |
|
282 const char* inputColor, |
|
283 const TransformedCoordsArray&, |
|
284 const TextureSamplerArray&) SK_OVERRIDE; |
|
285 |
|
286 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); |
|
287 |
|
288 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; |
|
289 |
|
290 private: |
|
291 SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector; |
|
292 SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector; |
|
293 GrGLUniformManager::UniformHandle fScaleUni; |
|
294 |
|
295 typedef GrGLEffect INHERITED; |
|
296 }; |
|
297 |
|
298 /////////////////////////////////////////////////////////////////////////////// |
|
299 |
|
300 class GrDisplacementMapEffect : public GrEffect { |
|
301 public: |
|
302 static GrEffectRef* Create(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, |
|
303 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, |
|
304 SkVector scale, |
|
305 GrTexture* displacement, const SkMatrix& offsetMatrix, |
|
306 GrTexture* color) { |
|
307 AutoEffectUnref effect(SkNEW_ARGS(GrDisplacementMapEffect, (xChannelSelector, |
|
308 yChannelSelector, |
|
309 scale, |
|
310 displacement, |
|
311 offsetMatrix, |
|
312 color))); |
|
313 return CreateEffectRef(effect); |
|
314 } |
|
315 |
|
316 virtual ~GrDisplacementMapEffect(); |
|
317 |
|
318 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; |
|
319 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const |
|
320 { return fXChannelSelector; } |
|
321 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const |
|
322 { return fYChannelSelector; } |
|
323 const SkVector& scale() const { return fScale; } |
|
324 |
|
325 typedef GrGLDisplacementMapEffect GLEffect; |
|
326 static const char* Name() { return "DisplacementMap"; } |
|
327 |
|
328 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; |
|
329 |
|
330 private: |
|
331 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; |
|
332 |
|
333 GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, |
|
334 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, |
|
335 const SkVector& scale, |
|
336 GrTexture* displacement, const SkMatrix& offsetMatrix, |
|
337 GrTexture* color); |
|
338 |
|
339 GR_DECLARE_EFFECT_TEST; |
|
340 |
|
341 GrCoordTransform fDisplacementTransform; |
|
342 GrTextureAccess fDisplacementAccess; |
|
343 GrCoordTransform fColorTransform; |
|
344 GrTextureAccess fColorAccess; |
|
345 SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector; |
|
346 SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector; |
|
347 SkVector fScale; |
|
348 |
|
349 typedef GrEffect INHERITED; |
|
350 }; |
|
351 |
|
352 bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, |
|
353 SkBitmap* result, SkIPoint* offset) const { |
|
354 SkBitmap colorBM = src; |
|
355 SkIPoint colorOffset = SkIPoint::Make(0, 0); |
|
356 if (getColorInput() && !getColorInput()->getInputResultGPU(proxy, src, ctx, &colorBM, |
|
357 &colorOffset)) { |
|
358 return false; |
|
359 } |
|
360 SkBitmap displacementBM = src; |
|
361 SkIPoint displacementOffset = SkIPoint::Make(0, 0); |
|
362 if (getDisplacementInput() && |
|
363 !getDisplacementInput()->getInputResultGPU(proxy, src, ctx, &displacementBM, |
|
364 &displacementOffset)) { |
|
365 return false; |
|
366 } |
|
367 SkIRect bounds; |
|
368 // Since GrDisplacementMapEffect does bounds checking on color pixel access, we don't need to |
|
369 // pad the color bitmap to bounds here. |
|
370 if (!this->applyCropRect(ctx, colorBM, colorOffset, &bounds)) { |
|
371 return false; |
|
372 } |
|
373 SkIRect displBounds; |
|
374 if (!this->applyCropRect(ctx, proxy, displacementBM, |
|
375 &displacementOffset, &displBounds, &displacementBM)) { |
|
376 return false; |
|
377 } |
|
378 if (!bounds.intersect(displBounds)) { |
|
379 return false; |
|
380 } |
|
381 GrTexture* color = colorBM.getTexture(); |
|
382 GrTexture* displacement = displacementBM.getTexture(); |
|
383 GrContext* context = color->getContext(); |
|
384 |
|
385 GrTextureDesc desc; |
|
386 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; |
|
387 desc.fWidth = colorBM.width(); |
|
388 desc.fHeight = colorBM.height(); |
|
389 desc.fConfig = kSkia8888_GrPixelConfig; |
|
390 |
|
391 GrAutoScratchTexture ast(context, desc); |
|
392 SkAutoTUnref<GrTexture> dst(ast.detach()); |
|
393 |
|
394 GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); |
|
395 |
|
396 SkVector scale = SkVector::Make(fScale, fScale); |
|
397 ctx.ctm().mapVectors(&scale, 1); |
|
398 |
|
399 GrPaint paint; |
|
400 SkMatrix offsetMatrix = GrEffect::MakeDivByTextureWHMatrix(displacement); |
|
401 offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displacementOffset.fX), |
|
402 SkIntToScalar(colorOffset.fY - displacementOffset.fY)); |
|
403 |
|
404 paint.addColorEffect( |
|
405 GrDisplacementMapEffect::Create(fXChannelSelector, |
|
406 fYChannelSelector, |
|
407 scale, |
|
408 displacement, |
|
409 offsetMatrix, |
|
410 color))->unref(); |
|
411 SkIRect colorBounds = bounds; |
|
412 colorBounds.offset(-colorOffset); |
|
413 SkMatrix matrix; |
|
414 matrix.setTranslate(-SkIntToScalar(colorBounds.x()), |
|
415 -SkIntToScalar(colorBounds.y())); |
|
416 context->concatMatrix(matrix); |
|
417 context->drawRect(paint, SkRect::Make(colorBounds)); |
|
418 offset->fX = bounds.left(); |
|
419 offset->fY = bounds.top(); |
|
420 WrapTexture(dst, bounds.width(), bounds.height(), result); |
|
421 return true; |
|
422 } |
|
423 |
|
424 /////////////////////////////////////////////////////////////////////////////// |
|
425 |
|
426 GrDisplacementMapEffect::GrDisplacementMapEffect( |
|
427 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, |
|
428 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, |
|
429 const SkVector& scale, |
|
430 GrTexture* displacement, |
|
431 const SkMatrix& offsetMatrix, |
|
432 GrTexture* color) |
|
433 : fDisplacementTransform(kLocal_GrCoordSet, offsetMatrix, displacement) |
|
434 , fDisplacementAccess(displacement) |
|
435 , fColorTransform(kLocal_GrCoordSet, color) |
|
436 , fColorAccess(color) |
|
437 , fXChannelSelector(xChannelSelector) |
|
438 , fYChannelSelector(yChannelSelector) |
|
439 , fScale(scale) { |
|
440 this->addCoordTransform(&fDisplacementTransform); |
|
441 this->addTextureAccess(&fDisplacementAccess); |
|
442 this->addCoordTransform(&fColorTransform); |
|
443 this->addTextureAccess(&fColorAccess); |
|
444 this->setWillNotUseInputColor(); |
|
445 } |
|
446 |
|
447 GrDisplacementMapEffect::~GrDisplacementMapEffect() { |
|
448 } |
|
449 |
|
450 bool GrDisplacementMapEffect::onIsEqual(const GrEffect& sBase) const { |
|
451 const GrDisplacementMapEffect& s = CastEffect<GrDisplacementMapEffect>(sBase); |
|
452 return fDisplacementAccess.getTexture() == s.fDisplacementAccess.getTexture() && |
|
453 fColorAccess.getTexture() == s.fColorAccess.getTexture() && |
|
454 fXChannelSelector == s.fXChannelSelector && |
|
455 fYChannelSelector == s.fYChannelSelector && |
|
456 fScale == s.fScale; |
|
457 } |
|
458 |
|
459 const GrBackendEffectFactory& GrDisplacementMapEffect::getFactory() const { |
|
460 return GrTBackendEffectFactory<GrDisplacementMapEffect>::getInstance(); |
|
461 } |
|
462 |
|
463 void GrDisplacementMapEffect::getConstantColorComponents(GrColor*, |
|
464 uint32_t* validFlags) const { |
|
465 // Any displacement offset bringing a pixel out of bounds will output a color of (0,0,0,0), |
|
466 // so the only way we'd get a constant alpha is if the input color image has a constant alpha |
|
467 // and no displacement offset push any texture coordinates out of bounds OR if the constant |
|
468 // alpha is 0. Since this isn't trivial to compute at this point, let's assume the output is |
|
469 // not of constant color when a displacement effect is applied. |
|
470 *validFlags = 0; |
|
471 } |
|
472 |
|
473 /////////////////////////////////////////////////////////////////////////////// |
|
474 |
|
475 GR_DEFINE_EFFECT_TEST(GrDisplacementMapEffect); |
|
476 |
|
477 GrEffectRef* GrDisplacementMapEffect::TestCreate(SkRandom* random, |
|
478 GrContext*, |
|
479 const GrDrawTargetCaps&, |
|
480 GrTexture* textures[]) { |
|
481 int texIdxDispl = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : |
|
482 GrEffectUnitTest::kAlphaTextureIdx; |
|
483 int texIdxColor = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : |
|
484 GrEffectUnitTest::kAlphaTextureIdx; |
|
485 static const int kMaxComponent = 4; |
|
486 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector = |
|
487 static_cast<SkDisplacementMapEffect::ChannelSelectorType>( |
|
488 random->nextRangeU(1, kMaxComponent)); |
|
489 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector = |
|
490 static_cast<SkDisplacementMapEffect::ChannelSelectorType>( |
|
491 random->nextRangeU(1, kMaxComponent)); |
|
492 SkVector scale = SkVector::Make(random->nextRangeScalar(0, 100.0f), |
|
493 random->nextRangeScalar(0, 100.0f)); |
|
494 |
|
495 return GrDisplacementMapEffect::Create(xChannelSelector, yChannelSelector, scale, |
|
496 textures[texIdxDispl], SkMatrix::I(), |
|
497 textures[texIdxColor]); |
|
498 } |
|
499 |
|
500 /////////////////////////////////////////////////////////////////////////////// |
|
501 |
|
502 GrGLDisplacementMapEffect::GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory, |
|
503 const GrDrawEffect& drawEffect) |
|
504 : INHERITED(factory) |
|
505 , fXChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().xChannelSelector()) |
|
506 , fYChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().yChannelSelector()) { |
|
507 } |
|
508 |
|
509 GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() { |
|
510 } |
|
511 |
|
512 void GrGLDisplacementMapEffect::emitCode(GrGLShaderBuilder* builder, |
|
513 const GrDrawEffect&, |
|
514 EffectKey key, |
|
515 const char* outputColor, |
|
516 const char* inputColor, |
|
517 const TransformedCoordsArray& coords, |
|
518 const TextureSamplerArray& samplers) { |
|
519 sk_ignore_unused_variable(inputColor); |
|
520 |
|
521 fScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
|
522 kVec2f_GrSLType, "Scale"); |
|
523 const char* scaleUni = builder->getUniformCStr(fScaleUni); |
|
524 const char* dColor = "dColor"; |
|
525 const char* cCoords = "cCoords"; |
|
526 const char* outOfBounds = "outOfBounds"; |
|
527 const char* nearZero = "1e-6"; // Since 6.10352e−5 is the smallest half float, use |
|
528 // a number smaller than that to approximate 0, but |
|
529 // leave room for 32-bit float GPU rounding errors. |
|
530 |
|
531 builder->fsCodeAppendf("\t\tvec4 %s = ", dColor); |
|
532 builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type()); |
|
533 builder->fsCodeAppend(";\n"); |
|
534 |
|
535 // Unpremultiply the displacement |
|
536 builder->fsCodeAppendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);", |
|
537 dColor, dColor, nearZero, dColor, dColor); |
|
538 |
|
539 builder->fsCodeAppendf("\t\tvec2 %s = %s + %s*(%s.", |
|
540 cCoords, coords[1].c_str(), scaleUni, dColor); |
|
541 |
|
542 switch (fXChannelSelector) { |
|
543 case SkDisplacementMapEffect::kR_ChannelSelectorType: |
|
544 builder->fsCodeAppend("r"); |
|
545 break; |
|
546 case SkDisplacementMapEffect::kG_ChannelSelectorType: |
|
547 builder->fsCodeAppend("g"); |
|
548 break; |
|
549 case SkDisplacementMapEffect::kB_ChannelSelectorType: |
|
550 builder->fsCodeAppend("b"); |
|
551 break; |
|
552 case SkDisplacementMapEffect::kA_ChannelSelectorType: |
|
553 builder->fsCodeAppend("a"); |
|
554 break; |
|
555 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: |
|
556 default: |
|
557 SkDEBUGFAIL("Unknown X channel selector"); |
|
558 } |
|
559 |
|
560 switch (fYChannelSelector) { |
|
561 case SkDisplacementMapEffect::kR_ChannelSelectorType: |
|
562 builder->fsCodeAppend("r"); |
|
563 break; |
|
564 case SkDisplacementMapEffect::kG_ChannelSelectorType: |
|
565 builder->fsCodeAppend("g"); |
|
566 break; |
|
567 case SkDisplacementMapEffect::kB_ChannelSelectorType: |
|
568 builder->fsCodeAppend("b"); |
|
569 break; |
|
570 case SkDisplacementMapEffect::kA_ChannelSelectorType: |
|
571 builder->fsCodeAppend("a"); |
|
572 break; |
|
573 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: |
|
574 default: |
|
575 SkDEBUGFAIL("Unknown Y channel selector"); |
|
576 } |
|
577 builder->fsCodeAppend("-vec2(0.5));\t\t"); |
|
578 |
|
579 // FIXME : This can be achieved with a "clamp to border" texture repeat mode and |
|
580 // a 0 border color instead of computing if cCoords is out of bounds here. |
|
581 builder->fsCodeAppendf( |
|
582 "bool %s = (%s.x < 0.0) || (%s.y < 0.0) || (%s.x > 1.0) || (%s.y > 1.0);\t\t", |
|
583 outOfBounds, cCoords, cCoords, cCoords, cCoords); |
|
584 builder->fsCodeAppendf("%s = %s ? vec4(0.0) : ", outputColor, outOfBounds); |
|
585 builder->fsAppendTextureLookup(samplers[1], cCoords, coords[1].type()); |
|
586 builder->fsCodeAppend(";\n"); |
|
587 } |
|
588 |
|
589 void GrGLDisplacementMapEffect::setData(const GrGLUniformManager& uman, |
|
590 const GrDrawEffect& drawEffect) { |
|
591 const GrDisplacementMapEffect& displacementMap = |
|
592 drawEffect.castEffect<GrDisplacementMapEffect>(); |
|
593 GrTexture* colorTex = displacementMap.texture(1); |
|
594 SkScalar scaleX = SkScalarDiv(displacementMap.scale().fX, SkIntToScalar(colorTex->width())); |
|
595 SkScalar scaleY = SkScalarDiv(displacementMap.scale().fY, SkIntToScalar(colorTex->height())); |
|
596 uman.set2f(fScaleUni, SkScalarToFloat(scaleX), |
|
597 colorTex->origin() == kTopLeft_GrSurfaceOrigin ? |
|
598 SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY)); |
|
599 } |
|
600 |
|
601 GrGLEffect::EffectKey GrGLDisplacementMapEffect::GenKey(const GrDrawEffect& drawEffect, |
|
602 const GrGLCaps&) { |
|
603 const GrDisplacementMapEffect& displacementMap = |
|
604 drawEffect.castEffect<GrDisplacementMapEffect>(); |
|
605 |
|
606 EffectKey xKey = displacementMap.xChannelSelector(); |
|
607 EffectKey yKey = displacementMap.yChannelSelector() << kChannelSelectorKeyBits; |
|
608 |
|
609 return xKey | yKey; |
|
610 } |
|
611 #endif |