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