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