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