• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
getValue(SkColor,const SkUnPreMultiply::Scale *)25 uint32_t getValue(SkColor, const SkUnPreMultiply::Scale*) {
26     SkDEBUGFAIL("Unknown channel selector");
27     return 0;
28 }
29 
getValue(SkColor l,const SkUnPreMultiply::Scale * table)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 
getValue(SkColor l,const SkUnPreMultiply::Scale * table)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 
getValue(SkColor l,const SkUnPreMultiply::Scale * table)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 
getValue(SkColor l,const SkUnPreMultiply::Scale *)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>
computeDisplacement(const SkVector & scale,SkBitmap * dst,SkBitmap * displ,const SkIPoint & offset,SkBitmap * src,const SkIRect & bounds)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>
computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,const SkVector & scale,SkBitmap * dst,SkBitmap * displ,const SkIPoint & offset,SkBitmap * src,const SkIRect & bounds)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 
computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,const SkVector & scale,SkBitmap * dst,SkBitmap * displ,const SkIPoint & offset,SkBitmap * src,const SkIRect & bounds)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 
channel_selector_type_is_valid(SkDisplacementMapEffect::ChannelSelectorType cst)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 
SkDisplacementMapEffect(ChannelSelectorType xChannelSelector,ChannelSelectorType yChannelSelector,SkScalar scale,SkImageFilter * displacement,SkImageFilter * color,const CropRect * cropRect)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 
~SkDisplacementMapEffect()174 SkDisplacementMapEffect::~SkDisplacementMapEffect() {
175 }
176 
SkDisplacementMapEffect(SkReadBuffer & buffer)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 
flatten(SkWriteBuffer & buffer) const188 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 
onFilterImage(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * dst,SkIPoint * offset) const195 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() != kN32_SkColorType) ||
209         (color.colorType() != kN32_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     if (!dst->allocPixels(color.info().makeWH(bounds.width(), bounds.height()))) {
231         return false;
232     }
233 
234     SkVector scale = SkVector::Make(fScale, fScale);
235     ctx.ctm().mapVectors(&scale, 1);
236     SkIRect colorBounds = bounds;
237     colorBounds.offset(-colorOffset);
238 
239     computeDisplacement(fXChannelSelector, fYChannelSelector, scale, dst,
240                         &displ, colorOffset - displOffset, &color, colorBounds);
241 
242     offset->fX = bounds.left();
243     offset->fY = bounds.top();
244     return true;
245 }
246 
computeFastBounds(const SkRect & src,SkRect * dst) const247 void SkDisplacementMapEffect::computeFastBounds(const SkRect& src, SkRect* dst) const {
248     if (getColorInput()) {
249         getColorInput()->computeFastBounds(src, dst);
250     } else {
251         *dst = src;
252     }
253     dst->outset(fScale * SK_ScalarHalf, fScale * SK_ScalarHalf);
254 }
255 
onFilterBounds(const SkIRect & src,const SkMatrix & ctm,SkIRect * dst) const256 bool SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
257                                    SkIRect* dst) const {
258     SkIRect bounds = src;
259     SkVector scale = SkVector::Make(fScale, fScale);
260     ctm.mapVectors(&scale, 1);
261     bounds.outset(SkScalarCeilToInt(scale.fX * SK_ScalarHalf),
262                   SkScalarCeilToInt(scale.fY * SK_ScalarHalf));
263     if (getColorInput()) {
264         return getColorInput()->filterBounds(bounds, ctm, dst);
265     }
266     *dst = bounds;
267     return true;
268 }
269 
270 ///////////////////////////////////////////////////////////////////////////////
271 
272 #if SK_SUPPORT_GPU
273 class GrGLDisplacementMapEffect : public GrGLEffect {
274 public:
275     GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
276                               const GrDrawEffect& drawEffect);
277     virtual ~GrGLDisplacementMapEffect();
278 
279     virtual void emitCode(GrGLShaderBuilder*,
280                           const GrDrawEffect&,
281                           EffectKey,
282                           const char* outputColor,
283                           const char* inputColor,
284                           const TransformedCoordsArray&,
285                           const TextureSamplerArray&) SK_OVERRIDE;
286 
287     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
288 
289     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
290 
291 private:
292     SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
293     SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
294     GrGLUniformManager::UniformHandle fScaleUni;
295 
296     typedef GrGLEffect INHERITED;
297 };
298 
299 ///////////////////////////////////////////////////////////////////////////////
300 
301 class GrDisplacementMapEffect : public GrEffect {
302 public:
Create(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,SkVector scale,GrTexture * displacement,const SkMatrix & offsetMatrix,GrTexture * color)303     static GrEffectRef* Create(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
304                                SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
305                                SkVector scale,
306                                GrTexture* displacement, const SkMatrix& offsetMatrix,
307                                GrTexture* color) {
308         AutoEffectUnref effect(SkNEW_ARGS(GrDisplacementMapEffect, (xChannelSelector,
309                                                                     yChannelSelector,
310                                                                     scale,
311                                                                     displacement,
312                                                                     offsetMatrix,
313                                                                     color)));
314         return CreateEffectRef(effect);
315     }
316 
317     virtual ~GrDisplacementMapEffect();
318 
319     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
xChannelSelector() const320     SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const
321         { return fXChannelSelector; }
yChannelSelector() const322     SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const
323         { return fYChannelSelector; }
scale() const324     const SkVector& scale() const { return fScale; }
325 
326     typedef GrGLDisplacementMapEffect GLEffect;
Name()327     static const char* Name() { return "DisplacementMap"; }
328 
329     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
330 
331 private:
332     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
333 
334     GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
335                             SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
336                             const SkVector& scale,
337                             GrTexture* displacement, const SkMatrix& offsetMatrix,
338                             GrTexture* color);
339 
340     GR_DECLARE_EFFECT_TEST;
341 
342     GrCoordTransform            fDisplacementTransform;
343     GrTextureAccess             fDisplacementAccess;
344     GrCoordTransform            fColorTransform;
345     GrTextureAccess             fColorAccess;
346     SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
347     SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
348     SkVector fScale;
349 
350     typedef GrEffect INHERITED;
351 };
352 
filterImageGPU(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const353 bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
354                                              SkBitmap* result, SkIPoint* offset) const {
355     SkBitmap colorBM = src;
356     SkIPoint colorOffset = SkIPoint::Make(0, 0);
357     if (getColorInput() && !getColorInput()->getInputResultGPU(proxy, src, ctx, &colorBM,
358                                                                &colorOffset)) {
359         return false;
360     }
361     SkBitmap displacementBM = src;
362     SkIPoint displacementOffset = SkIPoint::Make(0, 0);
363     if (getDisplacementInput() &&
364         !getDisplacementInput()->getInputResultGPU(proxy, src, ctx, &displacementBM,
365                                                    &displacementOffset)) {
366         return false;
367     }
368     SkIRect bounds;
369     // Since GrDisplacementMapEffect does bounds checking on color pixel access, we don't need to
370     // pad the color bitmap to bounds here.
371     if (!this->applyCropRect(ctx, colorBM, colorOffset, &bounds)) {
372         return false;
373     }
374     SkIRect displBounds;
375     if (!this->applyCropRect(ctx, proxy, displacementBM,
376                              &displacementOffset, &displBounds, &displacementBM)) {
377         return false;
378     }
379     if (!bounds.intersect(displBounds)) {
380         return false;
381     }
382     GrTexture* color = colorBM.getTexture();
383     GrTexture* displacement = displacementBM.getTexture();
384     GrContext* context = color->getContext();
385 
386     GrTextureDesc desc;
387     desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
388     desc.fWidth = bounds.width();
389     desc.fHeight = bounds.height();
390     desc.fConfig = kSkia8888_GrPixelConfig;
391 
392     GrAutoScratchTexture ast(context, desc);
393     SkAutoTUnref<GrTexture> dst(ast.detach());
394 
395     GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
396 
397     SkVector scale = SkVector::Make(fScale, fScale);
398     ctx.ctm().mapVectors(&scale, 1);
399 
400     GrPaint paint;
401     SkMatrix offsetMatrix = GrEffect::MakeDivByTextureWHMatrix(displacement);
402     offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displacementOffset.fX),
403                               SkIntToScalar(colorOffset.fY - displacementOffset.fY));
404 
405     paint.addColorEffect(
406         GrDisplacementMapEffect::Create(fXChannelSelector,
407                                         fYChannelSelector,
408                                         scale,
409                                         displacement,
410                                         offsetMatrix,
411                                         color))->unref();
412     SkIRect colorBounds = bounds;
413     colorBounds.offset(-colorOffset);
414     GrContext::AutoMatrix am;
415     am.setIdentity(context);
416     SkMatrix matrix;
417     matrix.setTranslate(-SkIntToScalar(colorBounds.x()),
418                         -SkIntToScalar(colorBounds.y()));
419     context->concatMatrix(matrix);
420     context->drawRect(paint, SkRect::Make(colorBounds));
421     offset->fX = bounds.left();
422     offset->fY = bounds.top();
423     WrapTexture(dst, bounds.width(), bounds.height(), result);
424     return true;
425 }
426 
427 ///////////////////////////////////////////////////////////////////////////////
428 
GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,const SkVector & scale,GrTexture * displacement,const SkMatrix & offsetMatrix,GrTexture * color)429 GrDisplacementMapEffect::GrDisplacementMapEffect(
430                              SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
431                              SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
432                              const SkVector& scale,
433                              GrTexture* displacement,
434                              const SkMatrix& offsetMatrix,
435                              GrTexture* color)
436     : fDisplacementTransform(kLocal_GrCoordSet, offsetMatrix, displacement)
437     , fDisplacementAccess(displacement)
438     , fColorTransform(kLocal_GrCoordSet, color)
439     , fColorAccess(color)
440     , fXChannelSelector(xChannelSelector)
441     , fYChannelSelector(yChannelSelector)
442     , fScale(scale) {
443     this->addCoordTransform(&fDisplacementTransform);
444     this->addTextureAccess(&fDisplacementAccess);
445     this->addCoordTransform(&fColorTransform);
446     this->addTextureAccess(&fColorAccess);
447     this->setWillNotUseInputColor();
448 }
449 
~GrDisplacementMapEffect()450 GrDisplacementMapEffect::~GrDisplacementMapEffect() {
451 }
452 
onIsEqual(const GrEffect & sBase) const453 bool GrDisplacementMapEffect::onIsEqual(const GrEffect& sBase) const {
454     const GrDisplacementMapEffect& s = CastEffect<GrDisplacementMapEffect>(sBase);
455     return fDisplacementAccess.getTexture() == s.fDisplacementAccess.getTexture() &&
456            fColorAccess.getTexture() == s.fColorAccess.getTexture() &&
457            fXChannelSelector == s.fXChannelSelector &&
458            fYChannelSelector == s.fYChannelSelector &&
459            fScale == s.fScale;
460 }
461 
getFactory() const462 const GrBackendEffectFactory& GrDisplacementMapEffect::getFactory() const {
463     return GrTBackendEffectFactory<GrDisplacementMapEffect>::getInstance();
464 }
465 
getConstantColorComponents(GrColor *,uint32_t * validFlags) const466 void GrDisplacementMapEffect::getConstantColorComponents(GrColor*,
467                                                          uint32_t* validFlags) const {
468     // Any displacement offset bringing a pixel out of bounds will output a color of (0,0,0,0),
469     // so the only way we'd get a constant alpha is if the input color image has a constant alpha
470     // and no displacement offset push any texture coordinates out of bounds OR if the constant
471     // alpha is 0. Since this isn't trivial to compute at this point, let's assume the output is
472     // not of constant color when a displacement effect is applied.
473     *validFlags = 0;
474 }
475 
476 ///////////////////////////////////////////////////////////////////////////////
477 
478 GR_DEFINE_EFFECT_TEST(GrDisplacementMapEffect);
479 
TestCreate(SkRandom * random,GrContext *,const GrDrawTargetCaps &,GrTexture * textures[])480 GrEffectRef* GrDisplacementMapEffect::TestCreate(SkRandom* random,
481                                                  GrContext*,
482                                                  const GrDrawTargetCaps&,
483                                                  GrTexture* textures[]) {
484     int texIdxDispl = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
485                                            GrEffectUnitTest::kAlphaTextureIdx;
486     int texIdxColor = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
487                                            GrEffectUnitTest::kAlphaTextureIdx;
488     static const int kMaxComponent = 4;
489     SkDisplacementMapEffect::ChannelSelectorType xChannelSelector =
490         static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
491         random->nextRangeU(1, kMaxComponent));
492     SkDisplacementMapEffect::ChannelSelectorType yChannelSelector =
493         static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
494         random->nextRangeU(1, kMaxComponent));
495     SkVector scale = SkVector::Make(random->nextRangeScalar(0, 100.0f),
496                                     random->nextRangeScalar(0, 100.0f));
497 
498     return GrDisplacementMapEffect::Create(xChannelSelector, yChannelSelector, scale,
499                                            textures[texIdxDispl], SkMatrix::I(),
500                                            textures[texIdxColor]);
501 }
502 
503 ///////////////////////////////////////////////////////////////////////////////
504 
GrGLDisplacementMapEffect(const GrBackendEffectFactory & factory,const GrDrawEffect & drawEffect)505 GrGLDisplacementMapEffect::GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
506                                                      const GrDrawEffect& drawEffect)
507     : INHERITED(factory)
508     , fXChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().xChannelSelector())
509     , fYChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().yChannelSelector()) {
510 }
511 
~GrGLDisplacementMapEffect()512 GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() {
513 }
514 
emitCode(GrGLShaderBuilder * builder,const GrDrawEffect &,EffectKey key,const char * outputColor,const char * inputColor,const TransformedCoordsArray & coords,const TextureSamplerArray & samplers)515 void GrGLDisplacementMapEffect::emitCode(GrGLShaderBuilder* builder,
516                                          const GrDrawEffect&,
517                                          EffectKey key,
518                                          const char* outputColor,
519                                          const char* inputColor,
520                                          const TransformedCoordsArray& coords,
521                                          const TextureSamplerArray& samplers) {
522     sk_ignore_unused_variable(inputColor);
523 
524     fScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
525                                     kVec2f_GrSLType, "Scale");
526     const char* scaleUni = builder->getUniformCStr(fScaleUni);
527     const char* dColor = "dColor";
528     const char* cCoords = "cCoords";
529     const char* outOfBounds = "outOfBounds";
530     const char* nearZero = "1e-6"; // Since 6.10352e−5 is the smallest half float, use
531                                    // a number smaller than that to approximate 0, but
532                                    // leave room for 32-bit float GPU rounding errors.
533 
534     builder->fsCodeAppendf("\t\tvec4 %s = ", dColor);
535     builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
536     builder->fsCodeAppend(";\n");
537 
538     // Unpremultiply the displacement
539     builder->fsCodeAppendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
540                            dColor, dColor, nearZero, dColor, dColor);
541 
542     builder->fsCodeAppendf("\t\tvec2 %s = %s + %s*(%s.",
543                            cCoords, coords[1].c_str(), scaleUni, dColor);
544 
545     switch (fXChannelSelector) {
546       case SkDisplacementMapEffect::kR_ChannelSelectorType:
547         builder->fsCodeAppend("r");
548         break;
549       case SkDisplacementMapEffect::kG_ChannelSelectorType:
550         builder->fsCodeAppend("g");
551         break;
552       case SkDisplacementMapEffect::kB_ChannelSelectorType:
553         builder->fsCodeAppend("b");
554         break;
555       case SkDisplacementMapEffect::kA_ChannelSelectorType:
556         builder->fsCodeAppend("a");
557         break;
558       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
559       default:
560         SkDEBUGFAIL("Unknown X channel selector");
561     }
562 
563     switch (fYChannelSelector) {
564       case SkDisplacementMapEffect::kR_ChannelSelectorType:
565         builder->fsCodeAppend("r");
566         break;
567       case SkDisplacementMapEffect::kG_ChannelSelectorType:
568         builder->fsCodeAppend("g");
569         break;
570       case SkDisplacementMapEffect::kB_ChannelSelectorType:
571         builder->fsCodeAppend("b");
572         break;
573       case SkDisplacementMapEffect::kA_ChannelSelectorType:
574         builder->fsCodeAppend("a");
575         break;
576       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
577       default:
578         SkDEBUGFAIL("Unknown Y channel selector");
579     }
580     builder->fsCodeAppend("-vec2(0.5));\t\t");
581 
582     // FIXME : This can be achieved with a "clamp to border" texture repeat mode and
583     //         a 0 border color instead of computing if cCoords is out of bounds here.
584     builder->fsCodeAppendf(
585         "bool %s = (%s.x < 0.0) || (%s.y < 0.0) || (%s.x > 1.0) || (%s.y > 1.0);\t\t",
586         outOfBounds, cCoords, cCoords, cCoords, cCoords);
587     builder->fsCodeAppendf("%s = %s ? vec4(0.0) : ", outputColor, outOfBounds);
588     builder->fsAppendTextureLookup(samplers[1], cCoords, coords[1].type());
589     builder->fsCodeAppend(";\n");
590 }
591 
setData(const GrGLUniformManager & uman,const GrDrawEffect & drawEffect)592 void GrGLDisplacementMapEffect::setData(const GrGLUniformManager& uman,
593                                         const GrDrawEffect& drawEffect) {
594     const GrDisplacementMapEffect& displacementMap =
595         drawEffect.castEffect<GrDisplacementMapEffect>();
596     GrTexture* colorTex = displacementMap.texture(1);
597     SkScalar scaleX = SkScalarDiv(displacementMap.scale().fX, SkIntToScalar(colorTex->width()));
598     SkScalar scaleY = SkScalarDiv(displacementMap.scale().fY, SkIntToScalar(colorTex->height()));
599     uman.set2f(fScaleUni, SkScalarToFloat(scaleX),
600                colorTex->origin() == kTopLeft_GrSurfaceOrigin ?
601                SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY));
602 }
603 
GenKey(const GrDrawEffect & drawEffect,const GrGLCaps &)604 GrGLEffect::EffectKey GrGLDisplacementMapEffect::GenKey(const GrDrawEffect& drawEffect,
605                                                         const GrGLCaps&) {
606     const GrDisplacementMapEffect& displacementMap =
607         drawEffect.castEffect<GrDisplacementMapEffect>();
608 
609     EffectKey xKey = displacementMap.xChannelSelector();
610     EffectKey yKey = displacementMap.yChannelSelector() << kChannelSelectorKeyBits;
611 
612     return xKey | yKey;
613 }
614 #endif
615