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
10#include "SkBitmap.h"
11#include "SkColorSpaceXformer.h"
12#include "SkImageFilterPriv.h"
13#include "SkReadBuffer.h"
14#include "SkSpecialImage.h"
15#include "SkWriteBuffer.h"
16#include "SkUnPreMultiply.h"
17#include "SkColorData.h"
18#if SK_SUPPORT_GPU
19#include "GrClip.h"
20#include "GrColorSpaceXform.h"
21#include "GrContext.h"
22#include "GrCoordTransform.h"
23#include "GrRenderTargetContext.h"
24#include "GrTexture.h"
25#include "GrTextureProxy.h"
26#include "SkGr.h"
27#include "effects/GrTextureDomain.h"
28#include "glsl/GrGLSLFragmentProcessor.h"
29#include "glsl/GrGLSLFragmentShaderBuilder.h"
30#include "glsl/GrGLSLProgramDataManager.h"
31#include "glsl/GrGLSLUniformHandler.h"
32#endif
33
34namespace {
35
36#define kChannelSelectorKeyBits 3; // Max value is 4, so 3 bits are required at most
37
38const uint8_t gChannelTypeToShift[] = {
39     0,  // unknown
40    SK_R32_SHIFT,
41    SK_G32_SHIFT,
42    SK_B32_SHIFT,
43    SK_A32_SHIFT,
44};
45struct Extractor {
46    Extractor(SkDisplacementMapEffect::ChannelSelectorType typeX,
47              SkDisplacementMapEffect::ChannelSelectorType typeY)
48        : fShiftX(gChannelTypeToShift[typeX])
49        , fShiftY(gChannelTypeToShift[typeY])
50    {}
51
52    unsigned fShiftX, fShiftY;
53
54    unsigned getX(SkPMColor c) const { return (c >> fShiftX) & 0xFF; }
55    unsigned getY(SkPMColor c) const { return (c >> fShiftY) & 0xFF; }
56};
57
58static SkPMColor unpremul_pm(SkPMColor c) {
59    const U8CPU a = SkGetPackedA32(c);
60    if (0 == a) {
61        return 0;
62    } else if (0xFF == a) {
63        return c;
64    }
65    const unsigned scale = SkUnPreMultiply::GetScale(a);
66    return SkPackARGB32NoCheck(a,
67                               SkUnPreMultiply::ApplyScale(scale, SkGetPackedR32(c)),
68                               SkUnPreMultiply::ApplyScale(scale, SkGetPackedG32(c)),
69                               SkUnPreMultiply::ApplyScale(scale, SkGetPackedB32(c)));
70}
71
72void computeDisplacement(Extractor ex, const SkVector& scale, SkBitmap* dst,
73                         const SkBitmap& displ, const SkIPoint& offset,
74                         const SkBitmap& src,
75                         const SkIRect& bounds) {
76    static const SkScalar Inv8bit = SkScalarInvert(255);
77    const int srcW = src.width();
78    const int srcH = src.height();
79    const SkVector scaleForColor = SkVector::Make(scale.fX * Inv8bit, scale.fY * Inv8bit);
80    const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - scale.fX * SK_ScalarHalf,
81                                             SK_ScalarHalf - scale.fY * SK_ScalarHalf);
82    SkPMColor* dstPtr = dst->getAddr32(0, 0);
83    for (int y = bounds.top(); y < bounds.bottom(); ++y) {
84        const SkPMColor* displPtr = displ.getAddr32(bounds.left() + offset.fX, y + offset.fY);
85        for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) {
86            SkPMColor c = unpremul_pm(*displPtr);
87
88            SkScalar displX = scaleForColor.fX * ex.getX(c) + scaleAdj.fX;
89            SkScalar displY = scaleForColor.fY * ex.getY(c) + scaleAdj.fY;
90            // Truncate the displacement values
91            const int32_t srcX = Sk32_sat_add(x, SkScalarTruncToInt(displX));
92            const int32_t srcY = Sk32_sat_add(y, SkScalarTruncToInt(displY));
93            *dstPtr++ = ((srcX < 0) || (srcX >= srcW) || (srcY < 0) || (srcY >= srcH)) ?
94                      0 : *(src.getAddr32(srcX, srcY));
95        }
96    }
97}
98
99bool channel_selector_type_is_valid(SkDisplacementMapEffect::ChannelSelectorType cst) {
100    switch (cst) {
101    case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
102    case SkDisplacementMapEffect::kR_ChannelSelectorType:
103    case SkDisplacementMapEffect::kG_ChannelSelectorType:
104    case SkDisplacementMapEffect::kB_ChannelSelectorType:
105    case SkDisplacementMapEffect::kA_ChannelSelectorType:
106        return true;
107    default:
108        break;
109    }
110    return false;
111}
112
113} // end namespace
114
115///////////////////////////////////////////////////////////////////////////////
116
117sk_sp<SkImageFilter> SkDisplacementMapEffect::Make(ChannelSelectorType xChannelSelector,
118                                                   ChannelSelectorType yChannelSelector,
119                                                   SkScalar scale,
120                                                   sk_sp<SkImageFilter> displacement,
121                                                   sk_sp<SkImageFilter> color,
122                                                   const CropRect* cropRect) {
123    if (!channel_selector_type_is_valid(xChannelSelector) ||
124        !channel_selector_type_is_valid(yChannelSelector)) {
125        return nullptr;
126    }
127
128    sk_sp<SkImageFilter> inputs[2] = { std::move(displacement), std::move(color) };
129    return sk_sp<SkImageFilter>(new SkDisplacementMapEffect(xChannelSelector,
130                                                            yChannelSelector,
131                                                            scale, inputs, cropRect));
132}
133
134SkDisplacementMapEffect::SkDisplacementMapEffect(ChannelSelectorType xChannelSelector,
135                                                 ChannelSelectorType yChannelSelector,
136                                                 SkScalar scale,
137                                                 sk_sp<SkImageFilter> inputs[2],
138                                                 const CropRect* cropRect)
139    : INHERITED(inputs, 2, cropRect)
140    , fXChannelSelector(xChannelSelector)
141    , fYChannelSelector(yChannelSelector)
142    , fScale(scale) {
143}
144
145SkDisplacementMapEffect::~SkDisplacementMapEffect() {
146}
147
148sk_sp<SkFlattenable> SkDisplacementMapEffect::CreateProc(SkReadBuffer& buffer) {
149    SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2);
150
151    ChannelSelectorType xsel = buffer.read32LE(kLast_ChannelSelectorType);
152    ChannelSelectorType ysel = buffer.read32LE(kLast_ChannelSelectorType);
153    SkScalar scale = buffer.readScalar();
154
155    return Make(xsel, ysel, scale, common.getInput(0), common.getInput(1), &common.cropRect());
156}
157
158void SkDisplacementMapEffect::flatten(SkWriteBuffer& buffer) const {
159    this->INHERITED::flatten(buffer);
160    buffer.writeInt((int) fXChannelSelector);
161    buffer.writeInt((int) fYChannelSelector);
162    buffer.writeScalar(fScale);
163}
164
165#if SK_SUPPORT_GPU
166class GrDisplacementMapEffect : public GrFragmentProcessor {
167public:
168    static std::unique_ptr<GrFragmentProcessor> Make(
169            SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
170            SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, SkVector scale,
171            sk_sp<GrTextureProxy> displacement, const SkMatrix& offsetMatrix,
172            sk_sp<GrTextureProxy> color, const SkISize& colorDimensions) {
173        return std::unique_ptr<GrFragmentProcessor>(new GrDisplacementMapEffect(
174                xChannelSelector, yChannelSelector, scale, std::move(displacement), offsetMatrix,
175                std::move(color), colorDimensions));
176    }
177
178    ~GrDisplacementMapEffect() override;
179
180    SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const {
181        return fXChannelSelector;
182    }
183    SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const {
184        return fYChannelSelector;
185    }
186    const SkVector& scale() const { return fScale; }
187
188    const char* name() const override { return "DisplacementMap"; }
189    const GrTextureDomain& domain() const { return fDomain; }
190
191    std::unique_ptr<GrFragmentProcessor> clone() const override;
192
193private:
194    static OptimizationFlags OptimizationFlags(GrPixelConfig colorConfig);
195
196    GrDisplacementMapEffect(const GrDisplacementMapEffect&);
197
198    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
199
200    void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
201
202    bool onIsEqual(const GrFragmentProcessor&) const override;
203
204    GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
205                            SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
206                            const SkVector& scale,
207                            sk_sp<GrTextureProxy> displacement, const SkMatrix& offsetMatrix,
208                            sk_sp<GrTextureProxy> color, const SkISize& colorDimensions);
209
210    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
211
212    GrCoordTransform            fDisplacementTransform;
213    TextureSampler              fDisplacementSampler;
214    GrCoordTransform            fColorTransform;
215    GrTextureDomain             fDomain;
216    TextureSampler              fColorSampler;
217    SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
218    SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
219    SkVector fScale;
220
221    typedef GrFragmentProcessor INHERITED;
222};
223#endif
224
225sk_sp<SkSpecialImage> SkDisplacementMapEffect::onFilterImage(SkSpecialImage* source,
226                                                             const Context& ctx,
227                                                             SkIPoint* offset) const {
228    SkIPoint colorOffset = SkIPoint::Make(0, 0);
229    sk_sp<SkSpecialImage> color(this->filterInput(1, source, ctx, &colorOffset));
230    if (!color) {
231        return nullptr;
232    }
233
234    SkIPoint displOffset = SkIPoint::Make(0, 0);
235    // Creation of the displacement map should happen in a non-colorspace aware context. This
236    // texture is a purely mathematical construct, so we want to just operate on the stored
237    // values. Consider:
238    // User supplies an sRGB displacement map. If we're rendering to a wider gamut, then we could
239    // end up filtering the displacement map into that gamut, which has the effect of reducing
240    // the amount of displacement that it represents (as encoded values move away from the
241    // primaries).
242    // With a more complex DAG attached to this input, it's not clear that working in ANY specific
243    // color space makes sense, so we ignore color spaces (and gamma) entirely. This may not be
244    // ideal, but it's at least consistent and predictable.
245    Context displContext(ctx.ctm(), ctx.clipBounds(), ctx.cache(), OutputProperties(nullptr));
246    sk_sp<SkSpecialImage> displ(this->filterInput(0, source, displContext, &displOffset));
247    if (!displ) {
248        return nullptr;
249    }
250
251    const SkIRect srcBounds = SkIRect::MakeXYWH(colorOffset.x(), colorOffset.y(),
252                                                color->width(), color->height());
253
254    // Both paths do bounds checking on color pixel access, we don't need to
255    // pad the color bitmap to bounds here.
256    SkIRect bounds;
257    if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
258        return nullptr;
259    }
260
261    SkIRect displBounds;
262    displ = this->applyCropRect(ctx, displ.get(), &displOffset, &displBounds);
263    if (!displ) {
264        return nullptr;
265    }
266
267    if (!bounds.intersect(displBounds)) {
268        return nullptr;
269    }
270
271    const SkIRect colorBounds = bounds.makeOffset(-colorOffset.x(), -colorOffset.y());
272
273    SkVector scale = SkVector::Make(fScale, fScale);
274    ctx.ctm().mapVectors(&scale, 1);
275
276#if SK_SUPPORT_GPU
277    if (source->isTextureBacked()) {
278        GrContext* context = source->getContext();
279
280        sk_sp<GrTextureProxy> colorProxy(color->asTextureProxyRef(context));
281        sk_sp<GrTextureProxy> displProxy(displ->asTextureProxyRef(context));
282        if (!colorProxy || !displProxy) {
283            return nullptr;
284        }
285
286        SkMatrix offsetMatrix = SkMatrix::MakeTrans(SkIntToScalar(colorOffset.fX - displOffset.fX),
287                                                    SkIntToScalar(colorOffset.fY - displOffset.fY));
288        SkColorSpace* colorSpace = ctx.outputProperties().colorSpace();
289
290        GrPixelConfig colorConfig = colorProxy->config();
291        std::unique_ptr<GrFragmentProcessor> fp =
292                GrDisplacementMapEffect::Make(fXChannelSelector,
293                                              fYChannelSelector,
294                                              scale,
295                                              std::move(displProxy),
296                                              offsetMatrix,
297                                              std::move(colorProxy),
298                                              SkISize::Make(color->width(), color->height()));
299        fp = GrColorSpaceXformEffect::Make(std::move(fp), color->getColorSpace(), colorConfig,
300                                           colorSpace);
301
302        GrPaint paint;
303        paint.addColorFragmentProcessor(std::move(fp));
304        paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
305        SkMatrix matrix;
306        matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y()));
307
308        sk_sp<GrRenderTargetContext> renderTargetContext(
309            context->makeDeferredRenderTargetContext(SkBackingFit::kApprox,
310                                                     bounds.width(), bounds.height(),
311                                                     GrRenderableConfigForColorSpace(colorSpace),
312                                                     sk_ref_sp(colorSpace)));
313        if (!renderTargetContext) {
314            return nullptr;
315        }
316        paint.setGammaCorrect(renderTargetContext->colorSpaceInfo().isGammaCorrect());
317
318        renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix,
319                                      SkRect::Make(colorBounds));
320
321        offset->fX = bounds.left();
322        offset->fY = bounds.top();
323        return SkSpecialImage::MakeDeferredFromGpu(
324                context,
325                SkIRect::MakeWH(bounds.width(), bounds.height()),
326                kNeedNewImageUniqueID_SpecialImage,
327                renderTargetContext->asTextureProxyRef(),
328                renderTargetContext->colorSpaceInfo().refColorSpace());
329    }
330#endif
331
332    SkBitmap colorBM, displBM;
333
334    if (!color->getROPixels(&colorBM) || !displ->getROPixels(&displBM)) {
335        return nullptr;
336    }
337
338    if ((colorBM.colorType() != kN32_SkColorType) ||
339        (displBM.colorType() != kN32_SkColorType)) {
340        return nullptr;
341    }
342
343    if (!colorBM.getPixels() || !displBM.getPixels()) {
344        return nullptr;
345    }
346
347    SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(),
348                                            colorBM.alphaType());
349
350    SkBitmap dst;
351    if (!dst.tryAllocPixels(info)) {
352        return nullptr;
353    }
354
355    computeDisplacement(Extractor(fXChannelSelector, fYChannelSelector), scale, &dst,
356                        displBM, colorOffset - displOffset, colorBM, colorBounds);
357
358    offset->fX = bounds.left();
359    offset->fY = bounds.top();
360    return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()),
361                                          dst);
362}
363
364sk_sp<SkImageFilter> SkDisplacementMapEffect::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
365    SkASSERT(2 == this->countInputs());
366    // Intentionally avoid xforming the displacement filter.  The values will be used as
367    // offsets, not as colors.
368    sk_sp<SkImageFilter> displacement = sk_ref_sp(const_cast<SkImageFilter*>(this->getInput(0)));
369    sk_sp<SkImageFilter> color = xformer->apply(this->getInput(1));
370
371    if (color.get() != this->getInput(1)) {
372        return SkDisplacementMapEffect::Make(fXChannelSelector, fYChannelSelector, fScale,
373                                             std::move(displacement), std::move(color),
374                                             this->getCropRectIfSet());
375    }
376    return this->refMe();
377}
378
379SkRect SkDisplacementMapEffect::computeFastBounds(const SkRect& src) const {
380    SkRect bounds = this->getColorInput() ? this->getColorInput()->computeFastBounds(src) : src;
381    bounds.outset(SkScalarAbs(fScale) * SK_ScalarHalf, SkScalarAbs(fScale) * SK_ScalarHalf);
382    return bounds;
383}
384
385SkIRect SkDisplacementMapEffect::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
386                                                    MapDirection) const {
387    SkVector scale = SkVector::Make(fScale, fScale);
388    ctm.mapVectors(&scale, 1);
389    return src.makeOutset(SkScalarCeilToInt(SkScalarAbs(scale.fX) * SK_ScalarHalf),
390                          SkScalarCeilToInt(SkScalarAbs(scale.fY) * SK_ScalarHalf));
391}
392
393SkIRect SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
394                                                MapDirection direction) const {
395    // Recurse only into color input.
396    if (this->getColorInput()) {
397        return this->getColorInput()->filterBounds(src, ctm, direction);
398    }
399    return src;
400}
401
402#ifndef SK_IGNORE_TO_STRING
403void SkDisplacementMapEffect::toString(SkString* str) const {
404    str->appendf("SkDisplacementMapEffect: (");
405    str->appendf("scale: %f ", fScale);
406    str->appendf("displacement: (");
407    if (this->getDisplacementInput()) {
408        this->getDisplacementInput()->toString(str);
409    }
410    str->appendf(") color: (");
411    if (this->getColorInput()) {
412        this->getColorInput()->toString(str);
413    }
414    str->appendf("))");
415}
416#endif
417
418///////////////////////////////////////////////////////////////////////////////
419
420#if SK_SUPPORT_GPU
421class GrGLDisplacementMapEffect : public GrGLSLFragmentProcessor {
422public:
423    void emitCode(EmitArgs&) override;
424
425    static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
426
427protected:
428    void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
429
430private:
431    typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
432
433    UniformHandle fScaleUni;
434    GrTextureDomain::GLDomain fGLDomain;
435
436    typedef GrGLSLFragmentProcessor INHERITED;
437};
438
439///////////////////////////////////////////////////////////////////////////////
440
441GrGLSLFragmentProcessor* GrDisplacementMapEffect::onCreateGLSLInstance() const {
442    return new GrGLDisplacementMapEffect;
443}
444
445void GrDisplacementMapEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
446                                                    GrProcessorKeyBuilder* b) const {
447    GrGLDisplacementMapEffect::GenKey(*this, caps, b);
448}
449
450GrFragmentProcessor::OptimizationFlags GrDisplacementMapEffect::OptimizationFlags(
451        GrPixelConfig colorConfig) {
452    return GrPixelConfigIsOpaque(colorConfig)
453                   ? GrFragmentProcessor::kPreservesOpaqueInput_OptimizationFlag
454                   : GrFragmentProcessor::kNone_OptimizationFlags;
455}
456
457GrDisplacementMapEffect::GrDisplacementMapEffect(
458        SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
459        SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
460        const SkVector& scale,
461        sk_sp<GrTextureProxy> displacement,
462        const SkMatrix& offsetMatrix,
463        sk_sp<GrTextureProxy> color,
464        const SkISize& colorDimensions)
465        : INHERITED(kGrDisplacementMapEffect_ClassID, OptimizationFlags(color->config()))
466        , fDisplacementTransform(offsetMatrix, displacement.get())
467        , fDisplacementSampler(displacement)
468        , fColorTransform(color.get())
469        , fDomain(color.get(), GrTextureDomain::MakeTexelDomain(SkIRect::MakeSize(colorDimensions)),
470                  GrTextureDomain::kDecal_Mode)
471        , fColorSampler(color)
472        , fXChannelSelector(xChannelSelector)
473        , fYChannelSelector(yChannelSelector)
474        , fScale(scale) {
475    this->addCoordTransform(&fDisplacementTransform);
476    this->addTextureSampler(&fDisplacementSampler);
477    this->addCoordTransform(&fColorTransform);
478    this->addTextureSampler(&fColorSampler);
479}
480
481GrDisplacementMapEffect::GrDisplacementMapEffect(const GrDisplacementMapEffect& that)
482        : INHERITED(kGrDisplacementMapEffect_ClassID,
483                    OptimizationFlags(that.fColorSampler.proxy()->config()))
484        , fDisplacementTransform(that.fDisplacementTransform)
485        , fDisplacementSampler(that.fDisplacementSampler)
486        , fColorTransform(that.fColorTransform)
487        , fDomain(that.fDomain)
488        , fColorSampler(that.fColorSampler)
489        , fXChannelSelector(that.fXChannelSelector)
490        , fYChannelSelector(that.fYChannelSelector)
491        , fScale(that.fScale) {
492    this->addCoordTransform(&fDisplacementTransform);
493    this->addTextureSampler(&fDisplacementSampler);
494    this->addCoordTransform(&fColorTransform);
495    this->addTextureSampler(&fColorSampler);
496}
497
498GrDisplacementMapEffect::~GrDisplacementMapEffect() {}
499
500std::unique_ptr<GrFragmentProcessor> GrDisplacementMapEffect::clone() const {
501    return std::unique_ptr<GrFragmentProcessor>(new GrDisplacementMapEffect(*this));
502}
503
504bool GrDisplacementMapEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
505    const GrDisplacementMapEffect& s = sBase.cast<GrDisplacementMapEffect>();
506    return fXChannelSelector == s.fXChannelSelector &&
507           fYChannelSelector == s.fYChannelSelector &&
508           fScale == s.fScale;
509}
510
511///////////////////////////////////////////////////////////////////////////////
512
513GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDisplacementMapEffect);
514
515#if GR_TEST_UTILS
516std::unique_ptr<GrFragmentProcessor> GrDisplacementMapEffect::TestCreate(GrProcessorTestData* d) {
517    int texIdxDispl = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
518                                               GrProcessorUnitTest::kAlphaTextureIdx;
519    int texIdxColor = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
520                                               GrProcessorUnitTest::kAlphaTextureIdx;
521    sk_sp<GrTextureProxy> dispProxy = d->textureProxy(texIdxDispl);
522    sk_sp<GrTextureProxy> colorProxy = d->textureProxy(texIdxColor);
523    static const int kMaxComponent = 4;
524    SkDisplacementMapEffect::ChannelSelectorType xChannelSelector =
525        static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
526                d->fRandom->nextRangeU(1, kMaxComponent));
527    SkDisplacementMapEffect::ChannelSelectorType yChannelSelector =
528        static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
529                d->fRandom->nextRangeU(1, kMaxComponent));
530    SkVector scale = SkVector::Make(d->fRandom->nextRangeScalar(0, 100.0f),
531                                    d->fRandom->nextRangeScalar(0, 100.0f));
532    SkISize colorDimensions;
533    colorDimensions.fWidth = d->fRandom->nextRangeU(0, colorProxy->width());
534    colorDimensions.fHeight = d->fRandom->nextRangeU(0, colorProxy->height());
535    return GrDisplacementMapEffect::Make(xChannelSelector, yChannelSelector, scale,
536                                         std::move(dispProxy), SkMatrix::I(),
537                                         std::move(colorProxy), colorDimensions);
538}
539
540#endif
541
542///////////////////////////////////////////////////////////////////////////////
543
544void GrGLDisplacementMapEffect::emitCode(EmitArgs& args) {
545    const GrDisplacementMapEffect& displacementMap = args.fFp.cast<GrDisplacementMapEffect>();
546    const GrTextureDomain& domain = displacementMap.domain();
547
548    fScaleUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, "Scale");
549    const char* scaleUni = args.fUniformHandler->getUniformCStr(fScaleUni);
550    const char* dColor = "dColor";
551    const char* cCoords = "cCoords";
552    const char* nearZero = "1e-6"; // Since 6.10352e-5 is the smallest half float, use
553                                   // a number smaller than that to approximate 0, but
554                                   // leave room for 32-bit float GPU rounding errors.
555
556    GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
557    fragBuilder->codeAppendf("\t\thalf4 %s = ", dColor);
558    fragBuilder->appendTextureLookup(args.fTexSamplers[0], args.fTransformedCoords[0].c_str(),
559                                   args.fTransformedCoords[0].getType());
560    fragBuilder->codeAppend(";\n");
561
562    // Unpremultiply the displacement
563    fragBuilder->codeAppendf(
564        "\t\t%s.rgb = (%s.a < %s) ? half3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
565        dColor, dColor, nearZero, dColor, dColor);
566    SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[1]);
567    fragBuilder->codeAppendf("\t\tfloat2 %s = %s + %s*(%s.",
568                             cCoords, coords2D.c_str(), scaleUni, dColor);
569
570    switch (displacementMap.xChannelSelector()) {
571      case SkDisplacementMapEffect::kR_ChannelSelectorType:
572        fragBuilder->codeAppend("r");
573        break;
574      case SkDisplacementMapEffect::kG_ChannelSelectorType:
575        fragBuilder->codeAppend("g");
576        break;
577      case SkDisplacementMapEffect::kB_ChannelSelectorType:
578        fragBuilder->codeAppend("b");
579        break;
580      case SkDisplacementMapEffect::kA_ChannelSelectorType:
581        fragBuilder->codeAppend("a");
582        break;
583      case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
584      default:
585        SkDEBUGFAIL("Unknown X channel selector");
586    }
587
588    switch (displacementMap.yChannelSelector()) {
589      case SkDisplacementMapEffect::kR_ChannelSelectorType:
590        fragBuilder->codeAppend("r");
591        break;
592      case SkDisplacementMapEffect::kG_ChannelSelectorType:
593        fragBuilder->codeAppend("g");
594        break;
595      case SkDisplacementMapEffect::kB_ChannelSelectorType:
596        fragBuilder->codeAppend("b");
597        break;
598      case SkDisplacementMapEffect::kA_ChannelSelectorType:
599        fragBuilder->codeAppend("a");
600        break;
601      case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
602      default:
603        SkDEBUGFAIL("Unknown Y channel selector");
604    }
605    fragBuilder->codeAppend("-half2(0.5));\t\t");
606
607    fGLDomain.sampleTexture(fragBuilder,
608                            args.fUniformHandler,
609                            args.fShaderCaps,
610                            domain,
611                            args.fOutputColor,
612                            SkString(cCoords),
613                            args.fTexSamplers[1]);
614    fragBuilder->codeAppend(";\n");
615}
616
617void GrGLDisplacementMapEffect::onSetData(const GrGLSLProgramDataManager& pdman,
618                                          const GrFragmentProcessor& proc) {
619    const GrDisplacementMapEffect& displacementMap = proc.cast<GrDisplacementMapEffect>();
620    GrSurfaceProxy* proxy = displacementMap.textureSampler(1).proxy();
621    GrTexture* colorTex = proxy->priv().peekTexture();
622
623    SkScalar scaleX = displacementMap.scale().fX / colorTex->width();
624    SkScalar scaleY = displacementMap.scale().fY / colorTex->height();
625    pdman.set2f(fScaleUni, SkScalarToFloat(scaleX),
626                proxy->origin() == kTopLeft_GrSurfaceOrigin ?
627                SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY));
628    fGLDomain.setData(pdman, displacementMap.domain(), proxy);
629}
630
631void GrGLDisplacementMapEffect::GenKey(const GrProcessor& proc,
632                                       const GrShaderCaps&, GrProcessorKeyBuilder* b) {
633    const GrDisplacementMapEffect& displacementMap = proc.cast<GrDisplacementMapEffect>();
634
635    uint32_t xKey = displacementMap.xChannelSelector();
636    uint32_t yKey = displacementMap.yChannelSelector() << kChannelSelectorKeyBits;
637
638    b->add32(xKey | yKey);
639}
640#endif
641