Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / effects / SkDisplacementMapEffect.cpp
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() != 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     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 = bounds.width();
388     desc.fHeight = bounds.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     GrContext::AutoMatrix am;
414     am.setIdentity(context);
415     SkMatrix matrix;
416     matrix.setTranslate(-SkIntToScalar(colorBounds.x()),
417                         -SkIntToScalar(colorBounds.y()));
418     context->concatMatrix(matrix);
419     context->drawRect(paint, SkRect::Make(colorBounds));
420     offset->fX = bounds.left();
421     offset->fY = bounds.top();
422     WrapTexture(dst, bounds.width(), bounds.height(), result);
423     return true;
424 }
425
426 ///////////////////////////////////////////////////////////////////////////////
427
428 GrDisplacementMapEffect::GrDisplacementMapEffect(
429                              SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
430                              SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
431                              const SkVector& scale,
432                              GrTexture* displacement,
433                              const SkMatrix& offsetMatrix,
434                              GrTexture* color)
435     : fDisplacementTransform(kLocal_GrCoordSet, offsetMatrix, displacement)
436     , fDisplacementAccess(displacement)
437     , fColorTransform(kLocal_GrCoordSet, color)
438     , fColorAccess(color)
439     , fXChannelSelector(xChannelSelector)
440     , fYChannelSelector(yChannelSelector)
441     , fScale(scale) {
442     this->addCoordTransform(&fDisplacementTransform);
443     this->addTextureAccess(&fDisplacementAccess);
444     this->addCoordTransform(&fColorTransform);
445     this->addTextureAccess(&fColorAccess);
446     this->setWillNotUseInputColor();
447 }
448
449 GrDisplacementMapEffect::~GrDisplacementMapEffect() {
450 }
451
452 bool GrDisplacementMapEffect::onIsEqual(const GrEffect& sBase) const {
453     const GrDisplacementMapEffect& s = CastEffect<GrDisplacementMapEffect>(sBase);
454     return fDisplacementAccess.getTexture() == s.fDisplacementAccess.getTexture() &&
455            fColorAccess.getTexture() == s.fColorAccess.getTexture() &&
456            fXChannelSelector == s.fXChannelSelector &&
457            fYChannelSelector == s.fYChannelSelector &&
458            fScale == s.fScale;
459 }
460
461 const GrBackendEffectFactory& GrDisplacementMapEffect::getFactory() const {
462     return GrTBackendEffectFactory<GrDisplacementMapEffect>::getInstance();
463 }
464
465 void GrDisplacementMapEffect::getConstantColorComponents(GrColor*,
466                                                          uint32_t* validFlags) const {
467     // Any displacement offset bringing a pixel out of bounds will output a color of (0,0,0,0),
468     // so the only way we'd get a constant alpha is if the input color image has a constant alpha
469     // and no displacement offset push any texture coordinates out of bounds OR if the constant
470     // alpha is 0. Since this isn't trivial to compute at this point, let's assume the output is
471     // not of constant color when a displacement effect is applied.
472     *validFlags = 0;
473 }
474
475 ///////////////////////////////////////////////////////////////////////////////
476
477 GR_DEFINE_EFFECT_TEST(GrDisplacementMapEffect);
478
479 GrEffectRef* GrDisplacementMapEffect::TestCreate(SkRandom* random,
480                                                  GrContext*,
481                                                  const GrDrawTargetCaps&,
482                                                  GrTexture* textures[]) {
483     int texIdxDispl = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
484                                            GrEffectUnitTest::kAlphaTextureIdx;
485     int texIdxColor = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
486                                            GrEffectUnitTest::kAlphaTextureIdx;
487     static const int kMaxComponent = 4;
488     SkDisplacementMapEffect::ChannelSelectorType xChannelSelector =
489         static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
490         random->nextRangeU(1, kMaxComponent));
491     SkDisplacementMapEffect::ChannelSelectorType yChannelSelector =
492         static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
493         random->nextRangeU(1, kMaxComponent));
494     SkVector scale = SkVector::Make(random->nextRangeScalar(0, 100.0f),
495                                     random->nextRangeScalar(0, 100.0f));
496
497     return GrDisplacementMapEffect::Create(xChannelSelector, yChannelSelector, scale,
498                                            textures[texIdxDispl], SkMatrix::I(),
499                                            textures[texIdxColor]);
500 }
501
502 ///////////////////////////////////////////////////////////////////////////////
503
504 GrGLDisplacementMapEffect::GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
505                                                      const GrDrawEffect& drawEffect)
506     : INHERITED(factory)
507     , fXChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().xChannelSelector())
508     , fYChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().yChannelSelector()) {
509 }
510
511 GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() {
512 }
513
514 void GrGLDisplacementMapEffect::emitCode(GrGLShaderBuilder* builder,
515                                          const GrDrawEffect&,
516                                          EffectKey key,
517                                          const char* outputColor,
518                                          const char* inputColor,
519                                          const TransformedCoordsArray& coords,
520                                          const TextureSamplerArray& samplers) {
521     sk_ignore_unused_variable(inputColor);
522
523     fScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
524                                     kVec2f_GrSLType, "Scale");
525     const char* scaleUni = builder->getUniformCStr(fScaleUni);
526     const char* dColor = "dColor";
527     const char* cCoords = "cCoords";
528     const char* outOfBounds = "outOfBounds";
529     const char* nearZero = "1e-6"; // Since 6.10352e−5 is the smallest half float, use
530                                    // a number smaller than that to approximate 0, but
531                                    // leave room for 32-bit float GPU rounding errors.
532
533     builder->fsCodeAppendf("\t\tvec4 %s = ", dColor);
534     builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
535     builder->fsCodeAppend(";\n");
536
537     // Unpremultiply the displacement
538     builder->fsCodeAppendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
539                            dColor, dColor, nearZero, dColor, dColor);
540
541     builder->fsCodeAppendf("\t\tvec2 %s = %s + %s*(%s.",
542                            cCoords, coords[1].c_str(), scaleUni, dColor);
543
544     switch (fXChannelSelector) {
545       case SkDisplacementMapEffect::kR_ChannelSelectorType:
546         builder->fsCodeAppend("r");
547         break;
548       case SkDisplacementMapEffect::kG_ChannelSelectorType:
549         builder->fsCodeAppend("g");
550         break;
551       case SkDisplacementMapEffect::kB_ChannelSelectorType:
552         builder->fsCodeAppend("b");
553         break;
554       case SkDisplacementMapEffect::kA_ChannelSelectorType:
555         builder->fsCodeAppend("a");
556         break;
557       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
558       default:
559         SkDEBUGFAIL("Unknown X channel selector");
560     }
561
562     switch (fYChannelSelector) {
563       case SkDisplacementMapEffect::kR_ChannelSelectorType:
564         builder->fsCodeAppend("r");
565         break;
566       case SkDisplacementMapEffect::kG_ChannelSelectorType:
567         builder->fsCodeAppend("g");
568         break;
569       case SkDisplacementMapEffect::kB_ChannelSelectorType:
570         builder->fsCodeAppend("b");
571         break;
572       case SkDisplacementMapEffect::kA_ChannelSelectorType:
573         builder->fsCodeAppend("a");
574         break;
575       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
576       default:
577         SkDEBUGFAIL("Unknown Y channel selector");
578     }
579     builder->fsCodeAppend("-vec2(0.5));\t\t");
580
581     // FIXME : This can be achieved with a "clamp to border" texture repeat mode and
582     //         a 0 border color instead of computing if cCoords is out of bounds here.
583     builder->fsCodeAppendf(
584         "bool %s = (%s.x < 0.0) || (%s.y < 0.0) || (%s.x > 1.0) || (%s.y > 1.0);\t\t",
585         outOfBounds, cCoords, cCoords, cCoords, cCoords);
586     builder->fsCodeAppendf("%s = %s ? vec4(0.0) : ", outputColor, outOfBounds);
587     builder->fsAppendTextureLookup(samplers[1], cCoords, coords[1].type());
588     builder->fsCodeAppend(";\n");
589 }
590
591 void GrGLDisplacementMapEffect::setData(const GrGLUniformManager& uman,
592                                         const GrDrawEffect& drawEffect) {
593     const GrDisplacementMapEffect& displacementMap =
594         drawEffect.castEffect<GrDisplacementMapEffect>();
595     GrTexture* colorTex = displacementMap.texture(1);
596     SkScalar scaleX = SkScalarDiv(displacementMap.scale().fX, SkIntToScalar(colorTex->width()));
597     SkScalar scaleY = SkScalarDiv(displacementMap.scale().fY, SkIntToScalar(colorTex->height()));
598     uman.set2f(fScaleUni, SkScalarToFloat(scaleX),
599                colorTex->origin() == kTopLeft_GrSurfaceOrigin ?
600                SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY));
601 }
602
603 GrGLEffect::EffectKey GrGLDisplacementMapEffect::GenKey(const GrDrawEffect& drawEffect,
604                                                         const GrGLCaps&) {
605     const GrDisplacementMapEffect& displacementMap =
606         drawEffect.castEffect<GrDisplacementMapEffect>();
607
608     EffectKey xKey = displacementMap.xChannelSelector();
609     EffectKey yKey = displacementMap.yChannelSelector() << kChannelSelectorKeyBits;
610
611     return xKey | yKey;
612 }
613 #endif