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
20namespace {
21
22#define kChannelSelectorKeyBits 3; // Max value is 4, so 3 bits are required at most
23
24template<SkDisplacementMapEffect::ChannelSelectorType type>
25uint32_t getValue(SkColor, const SkUnPreMultiply::Scale*) {
26    SkDEBUGFAIL("Unknown channel selector");
27    return 0;
28}
29
30template<> uint32_t getValue<SkDisplacementMapEffect::kR_ChannelSelectorType>(
31    SkColor l, const SkUnPreMultiply::Scale* table) {
32    return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedR32(l));
33}
34
35template<> uint32_t getValue<SkDisplacementMapEffect::kG_ChannelSelectorType>(
36    SkColor l, const SkUnPreMultiply::Scale* table) {
37    return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedG32(l));
38}
39
40template<> uint32_t getValue<SkDisplacementMapEffect::kB_ChannelSelectorType>(
41    SkColor l, const SkUnPreMultiply::Scale* table) {
42    return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedB32(l));
43}
44
45template<> uint32_t getValue<SkDisplacementMapEffect::kA_ChannelSelectorType>(
46    SkColor l, const SkUnPreMultiply::Scale*) {
47    return SkGetPackedA32(l);
48}
49
50template<SkDisplacementMapEffect::ChannelSelectorType typeX,
51         SkDisplacementMapEffect::ChannelSelectorType typeY>
52void 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
83template<SkDisplacementMapEffect::ChannelSelectorType typeX>
84void 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
113void 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
143bool 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
161SkDisplacementMapEffect::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
174SkDisplacementMapEffect::~SkDisplacementMapEffect() {
175}
176
177SkDisplacementMapEffect::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
188void 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
195bool 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
247void 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
256bool 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
273class GrGLDisplacementMapEffect : public GrGLEffect {
274public:
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
291private:
292    SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
293    SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
294    GrGLUniformManager::UniformHandle fScaleUni;
295
296    typedef GrGLEffect INHERITED;
297};
298
299///////////////////////////////////////////////////////////////////////////////
300
301class GrDisplacementMapEffect : public GrEffect {
302public:
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;
320    SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const
321        { return fXChannelSelector; }
322    SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const
323        { return fYChannelSelector; }
324    const SkVector& scale() const { return fScale; }
325
326    typedef GrGLDisplacementMapEffect GLEffect;
327    static const char* Name() { return "DisplacementMap"; }
328
329    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
330
331private:
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
353bool 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
429GrDisplacementMapEffect::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
450GrDisplacementMapEffect::~GrDisplacementMapEffect() {
451}
452
453bool 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
462const GrBackendEffectFactory& GrDisplacementMapEffect::getFactory() const {
463    return GrTBackendEffectFactory<GrDisplacementMapEffect>::getInstance();
464}
465
466void 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
478GR_DEFINE_EFFECT_TEST(GrDisplacementMapEffect);
479
480GrEffectRef* 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
505GrGLDisplacementMapEffect::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
512GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() {
513}
514
515void 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
592void 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
604GrGLEffect::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