• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/core/SkBitmap.h"
9 #include "include/core/SkUnPreMultiply.h"
10 #include "include/effects/SkImageFilters.h"
11 #include "include/private/SkColorData.h"
12 #include "src/core/SkImageFilter_Base.h"
13 #include "src/core/SkReadBuffer.h"
14 #include "src/core/SkSpecialImage.h"
15 #include "src/core/SkWriteBuffer.h"
16 
17 #if SK_SUPPORT_GPU
18 #include "include/gpu/GrRecordingContext.h"
19 #include "src/gpu/GrCaps.h"
20 #include "src/gpu/GrColorSpaceXform.h"
21 #include "src/gpu/GrFragmentProcessor.h"
22 #include "src/gpu/GrRecordingContextPriv.h"
23 #include "src/gpu/GrTexture.h"
24 #include "src/gpu/GrTextureProxy.h"
25 #include "src/gpu/SkGr.h"
26 #include "src/gpu/SurfaceFillContext.h"
27 #include "src/gpu/effects/GrTextureEffect.h"
28 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
29 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
30 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
31 #endif
32 
33 namespace {
34 
35 class SkDisplacementMapImageFilter final : public SkImageFilter_Base {
36 public:
SkDisplacementMapImageFilter(SkColorChannel xChannelSelector,SkColorChannel yChannelSelector,SkScalar scale,sk_sp<SkImageFilter> inputs[2],const SkRect * cropRect)37     SkDisplacementMapImageFilter(SkColorChannel xChannelSelector, SkColorChannel yChannelSelector,
38                                  SkScalar scale, sk_sp<SkImageFilter> inputs[2],
39                                  const SkRect* cropRect)
40             : INHERITED(inputs, 2, cropRect)
41             , fXChannelSelector(xChannelSelector)
42             , fYChannelSelector(yChannelSelector)
43             , fScale(scale) {}
44 
45     SkRect computeFastBounds(const SkRect& src) const override;
46 
47     SkIRect onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
48                            MapDirection, const SkIRect* inputRect) const override;
49     SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm,
50                                MapDirection, const SkIRect* inputRect) const override;
51 
52 protected:
53     sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
54 
55     void flatten(SkWriteBuffer&) const override;
56 
57 private:
58     friend void ::SkRegisterDisplacementMapImageFilterFlattenable();
59     SK_FLATTENABLE_HOOKS(SkDisplacementMapImageFilter)
60 
61     SkColorChannel fXChannelSelector;
62     SkColorChannel fYChannelSelector;
63     SkScalar fScale;
64 
getDisplacementInput() const65     const SkImageFilter* getDisplacementInput() const { return getInput(0); }
getColorInput() const66     const SkImageFilter* getColorInput() const { return getInput(1); }
67 
68     using INHERITED = SkImageFilter_Base;
69 };
70 
71 // Shift values to extract channels from an SkColor (SkColorGetR, SkColorGetG, etc)
72 const uint8_t gChannelTypeToShift[] = {
73     16,  // R
74      8,  // G
75      0,  // B
76     24,  // A
77 };
78 struct Extractor {
Extractor__anon72ad787a0111::Extractor79     Extractor(SkColorChannel typeX,
80               SkColorChannel typeY)
81         : fShiftX(gChannelTypeToShift[static_cast<int>(typeX)])
82         , fShiftY(gChannelTypeToShift[static_cast<int>(typeY)])
83     {}
84 
85     unsigned fShiftX, fShiftY;
86 
getX__anon72ad787a0111::Extractor87     unsigned getX(SkColor c) const { return (c >> fShiftX) & 0xFF; }
getY__anon72ad787a0111::Extractor88     unsigned getY(SkColor c) const { return (c >> fShiftY) & 0xFF; }
89 };
90 
channel_selector_type_is_valid(SkColorChannel cst)91 static bool channel_selector_type_is_valid(SkColorChannel cst) {
92     switch (cst) {
93         case SkColorChannel::kR:
94         case SkColorChannel::kG:
95         case SkColorChannel::kB:
96         case SkColorChannel::kA:
97             return true;
98         default:
99             break;
100     }
101     return false;
102 }
103 
104 }  // anonymous namespace
105 
106 ///////////////////////////////////////////////////////////////////////////////
107 
DisplacementMap(SkColorChannel xChannelSelector,SkColorChannel yChannelSelector,SkScalar scale,sk_sp<SkImageFilter> displacement,sk_sp<SkImageFilter> color,const CropRect & cropRect)108 sk_sp<SkImageFilter> SkImageFilters::DisplacementMap(
109         SkColorChannel xChannelSelector, SkColorChannel yChannelSelector, SkScalar scale,
110         sk_sp<SkImageFilter> displacement, sk_sp<SkImageFilter> color, const CropRect& cropRect) {
111     if (!channel_selector_type_is_valid(xChannelSelector) ||
112         !channel_selector_type_is_valid(yChannelSelector)) {
113         return nullptr;
114     }
115 
116     sk_sp<SkImageFilter> inputs[2] = { std::move(displacement), std::move(color) };
117     return sk_sp<SkImageFilter>(new SkDisplacementMapImageFilter(xChannelSelector, yChannelSelector,
118                                                                  scale, inputs, cropRect));
119 }
120 
SkRegisterDisplacementMapImageFilterFlattenable()121 void SkRegisterDisplacementMapImageFilterFlattenable() {
122     SK_REGISTER_FLATTENABLE(SkDisplacementMapImageFilter);
123     // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
124     SkFlattenable::Register("SkDisplacementMapEffect", SkDisplacementMapImageFilter::CreateProc);
125     SkFlattenable::Register("SkDisplacementMapEffectImpl",
126                             SkDisplacementMapImageFilter::CreateProc);
127 }
128 
CreateProc(SkReadBuffer & buffer)129 sk_sp<SkFlattenable> SkDisplacementMapImageFilter::CreateProc(SkReadBuffer& buffer) {
130     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2);
131 
132     SkColorChannel xsel = buffer.read32LE(SkColorChannel::kLastEnum);
133     SkColorChannel ysel = buffer.read32LE(SkColorChannel::kLastEnum);
134     SkScalar      scale = buffer.readScalar();
135 
136     return SkImageFilters::DisplacementMap(xsel, ysel, scale, common.getInput(0),
137                                            common.getInput(1), common.cropRect());
138 }
139 
flatten(SkWriteBuffer & buffer) const140 void SkDisplacementMapImageFilter::flatten(SkWriteBuffer& buffer) const {
141     this->INHERITED::flatten(buffer);
142     buffer.writeInt((int) fXChannelSelector);
143     buffer.writeInt((int) fYChannelSelector);
144     buffer.writeScalar(fScale);
145 }
146 
147 ///////////////////////////////////////////////////////////////////////////////
148 
149 #if SK_SUPPORT_GPU
150 
151 namespace {
152 
153 class GrDisplacementMapEffect : public GrFragmentProcessor {
154 public:
155     static std::unique_ptr<GrFragmentProcessor> Make(SkColorChannel xChannelSelector,
156                                                      SkColorChannel yChannelSelector,
157                                                      SkVector scale,
158                                                      GrSurfaceProxyView displacement,
159                                                      const SkIRect& displSubset,
160                                                      const SkMatrix& offsetMatrix,
161                                                      GrSurfaceProxyView color,
162                                                      const SkIRect& colorSubset,
163                                                      const GrCaps&);
164 
165     ~GrDisplacementMapEffect() override;
166 
name() const167     const char* name() const override { return "DisplacementMap"; }
168 
169     std::unique_ptr<GrFragmentProcessor> clone() const override;
170 
171 private:
172     class Impl;
173 
174     explicit GrDisplacementMapEffect(const GrDisplacementMapEffect&);
175 
176     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
177 
178     void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
179 
180     bool onIsEqual(const GrFragmentProcessor&) const override;
181 
182     GrDisplacementMapEffect(SkColorChannel xChannelSelector,
183                             SkColorChannel yChannelSelector,
184                             const SkVector& scale,
185                             std::unique_ptr<GrFragmentProcessor> displacement,
186                             std::unique_ptr<GrFragmentProcessor> color);
187 
188     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
189 
190     SkColorChannel fXChannelSelector;
191     SkColorChannel fYChannelSelector;
192     SkVector fScale;
193 
194     using INHERITED = GrFragmentProcessor;
195 };
196 
197 }  // anonymous namespace
198 #endif
199 
compute_displacement(Extractor ex,const SkVector & scale,SkBitmap * dst,const SkBitmap & displ,const SkIPoint & offset,const SkBitmap & src,const SkIRect & bounds)200 static void compute_displacement(Extractor ex, const SkVector& scale, SkBitmap* dst,
201                                  const SkBitmap& displ, const SkIPoint& offset,
202                                  const SkBitmap& src,
203                                  const SkIRect& bounds) {
204     static const SkScalar Inv8bit = SkScalarInvert(255);
205     const int srcW = src.width();
206     const int srcH = src.height();
207     const SkVector scaleForColor = SkVector::Make(scale.fX * Inv8bit, scale.fY * Inv8bit);
208     const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - scale.fX * SK_ScalarHalf,
209                                              SK_ScalarHalf - scale.fY * SK_ScalarHalf);
210     SkPMColor* dstPtr = dst->getAddr32(0, 0);
211     for (int y = bounds.top(); y < bounds.bottom(); ++y) {
212         const SkPMColor* displPtr = displ.getAddr32(bounds.left() + offset.fX, y + offset.fY);
213         for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) {
214             SkColor c = SkUnPreMultiply::PMColorToColor(*displPtr);
215 
216             SkScalar displX = scaleForColor.fX * ex.getX(c) + scaleAdj.fX;
217             SkScalar displY = scaleForColor.fY * ex.getY(c) + scaleAdj.fY;
218             // Truncate the displacement values
219             const int32_t srcX = Sk32_sat_add(x, SkScalarTruncToInt(displX));
220             const int32_t srcY = Sk32_sat_add(y, SkScalarTruncToInt(displY));
221             *dstPtr++ = ((srcX < 0) || (srcX >= srcW) || (srcY < 0) || (srcY >= srcH)) ?
222                       0 : *(src.getAddr32(srcX, srcY));
223         }
224     }
225 }
226 
onFilterImage(const Context & ctx,SkIPoint * offset) const227 sk_sp<SkSpecialImage> SkDisplacementMapImageFilter::onFilterImage(const Context& ctx,
228                                                                   SkIPoint* offset) const {
229     SkIPoint colorOffset = SkIPoint::Make(0, 0);
230     sk_sp<SkSpecialImage> color(this->filterInput(1, ctx, &colorOffset));
231     if (!color) {
232         return nullptr;
233     }
234 
235     SkIPoint displOffset = SkIPoint::Make(0, 0);
236     // Creation of the displacement map should happen in a non-colorspace aware context. This
237     // texture is a purely mathematical construct, so we want to just operate on the stored
238     // values. Consider:
239     // User supplies an sRGB displacement map. If we're rendering to a wider gamut, then we could
240     // end up filtering the displacement map into that gamut, which has the effect of reducing
241     // the amount of displacement that it represents (as encoded values move away from the
242     // primaries).
243     // With a more complex DAG attached to this input, it's not clear that working in ANY specific
244     // color space makes sense, so we ignore color spaces (and gamma) entirely. This may not be
245     // ideal, but it's at least consistent and predictable.
246     Context displContext(ctx.mapping(), ctx.desiredOutput(), ctx.cache(),
247                          kN32_SkColorType, nullptr, ctx.source());
248     sk_sp<SkSpecialImage> displ(this->filterInput(0, displContext, &displOffset));
249     if (!displ) {
250         return nullptr;
251     }
252 
253     const SkIRect srcBounds = SkIRect::MakeXYWH(colorOffset.x(), colorOffset.y(),
254                                                 color->width(), color->height());
255 
256     // Both paths do bounds checking on color pixel access, we don't need to
257     // pad the color bitmap to bounds here.
258     SkIRect bounds;
259     if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
260         return nullptr;
261     }
262 
263     SkIRect displBounds;
264     displ = this->applyCropRectAndPad(ctx, displ.get(), &displOffset, &displBounds);
265     if (!displ) {
266         return nullptr;
267     }
268 
269     if (!bounds.intersect(displBounds)) {
270         return nullptr;
271     }
272 
273     const SkIRect colorBounds = bounds.makeOffset(-colorOffset);
274     // If the offset overflowed (saturated) then we have to abort, as we need their
275     // dimensions to be equal. See https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=7209
276     if (colorBounds.size() != bounds.size()) {
277         return nullptr;
278     }
279 
280     SkVector scale = SkVector::Make(fScale, fScale);
281     ctx.ctm().mapVectors(&scale, 1);
282 
283 #if SK_SUPPORT_GPU
284     if (ctx.gpuBacked()) {
285         auto rContext = ctx.getContext();
286 
287         GrSurfaceProxyView colorView = color->view(rContext);
288         GrSurfaceProxyView displView = displ->view(rContext);
289         if (!colorView.proxy() || !displView.proxy()) {
290             return nullptr;
291         }
292         const auto isProtected = colorView.proxy()->isProtected();
293 
294         SkMatrix offsetMatrix = SkMatrix::Translate(SkIntToScalar(colorOffset.fX - displOffset.fX),
295                                                     SkIntToScalar(colorOffset.fY - displOffset.fY));
296 
297         std::unique_ptr<GrFragmentProcessor> fp =
298                 GrDisplacementMapEffect::Make(fXChannelSelector,
299                                               fYChannelSelector,
300                                               scale,
301                                               std::move(displView),
302                                               displ->subset(),
303                                               offsetMatrix,
304                                               std::move(colorView),
305                                               color->subset(),
306                                               *rContext->priv().caps());
307         fp = GrColorSpaceXformEffect::Make(std::move(fp),
308                                            color->getColorSpace(), color->alphaType(),
309                                            ctx.colorSpace(), kPremul_SkAlphaType);
310         GrImageInfo info(ctx.grColorType(),
311                          kPremul_SkAlphaType,
312                          ctx.refColorSpace(),
313                          bounds.size());
314         auto sfc = rContext->priv().makeSFC(info,
315                                             SkBackingFit::kApprox,
316                                             1,
317                                             GrMipmapped::kNo,
318                                             isProtected,
319                                             kBottomLeft_GrSurfaceOrigin);
320         if (!sfc) {
321             return nullptr;
322         }
323 
324         sfc->fillRectToRectWithFP(colorBounds,
325                                   SkIRect::MakeSize(colorBounds.size()),
326                                   std::move(fp));
327 
328         offset->fX = bounds.left();
329         offset->fY = bounds.top();
330         return SkSpecialImage::MakeDeferredFromGpu(rContext,
331                                                    SkIRect::MakeWH(bounds.width(), bounds.height()),
332                                                    kNeedNewImageUniqueID_SpecialImage,
333                                                    sfc->readSurfaceView(),
334                                                    sfc->colorInfo().colorType(),
335                                                    sfc->colorInfo().refColorSpace(),
336                                                    ctx.surfaceProps());
337     }
338 #endif
339 
340     SkBitmap colorBM, displBM;
341 
342     if (!color->getROPixels(&colorBM) || !displ->getROPixels(&displBM)) {
343         return nullptr;
344     }
345 
346     if ((colorBM.colorType() != kN32_SkColorType) ||
347         (displBM.colorType() != kN32_SkColorType)) {
348         return nullptr;
349     }
350 
351     if (!colorBM.getPixels() || !displBM.getPixels()) {
352         return nullptr;
353     }
354 
355     SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(),
356                                             colorBM.alphaType());
357 
358     SkBitmap dst;
359     if (!dst.tryAllocPixels(info)) {
360         return nullptr;
361     }
362 
363     compute_displacement(Extractor(fXChannelSelector, fYChannelSelector), scale, &dst,
364                          displBM, colorOffset - displOffset, colorBM, colorBounds);
365 
366     offset->fX = bounds.left();
367     offset->fY = bounds.top();
368     return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()),
369                                           dst, ctx.surfaceProps());
370 }
371 
computeFastBounds(const SkRect & src) const372 SkRect SkDisplacementMapImageFilter::computeFastBounds(const SkRect& src) const {
373     SkRect bounds = this->getColorInput() ? this->getColorInput()->computeFastBounds(src) : src;
374     bounds.outset(SkScalarAbs(fScale) * SK_ScalarHalf, SkScalarAbs(fScale) * SK_ScalarHalf);
375     return bounds;
376 }
377 
onFilterNodeBounds(const SkIRect & src,const SkMatrix & ctm,MapDirection,const SkIRect * inputRect) const378 SkIRect SkDisplacementMapImageFilter::onFilterNodeBounds(
379         const SkIRect& src, const SkMatrix& ctm, MapDirection, const SkIRect* inputRect) const {
380     SkVector scale = SkVector::Make(fScale, fScale);
381     ctm.mapVectors(&scale, 1);
382     return src.makeOutset(SkScalarCeilToInt(SkScalarAbs(scale.fX) * SK_ScalarHalf),
383                           SkScalarCeilToInt(SkScalarAbs(scale.fY) * SK_ScalarHalf));
384 }
385 
onFilterBounds(const SkIRect & src,const SkMatrix & ctm,MapDirection dir,const SkIRect * inputRect) const386 SkIRect SkDisplacementMapImageFilter::onFilterBounds(
387         const SkIRect& src, const SkMatrix& ctm, MapDirection dir, const SkIRect* inputRect) const {
388     if (kReverse_MapDirection == dir) {
389         return INHERITED::onFilterBounds(src, ctm, dir, inputRect);
390     }
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 GrDisplacementMapEffect::Impl : public ProgramImpl {
402 public:
403     void emitCode(EmitArgs&) override;
404 
405 private:
406     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
407 
408     typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
409 
410     UniformHandle fScaleUni;
411 };
412 
413 ///////////////////////////////////////////////////////////////////////////////
414 
Make(SkColorChannel xChannelSelector,SkColorChannel yChannelSelector,SkVector scale,GrSurfaceProxyView displacement,const SkIRect & displSubset,const SkMatrix & offsetMatrix,GrSurfaceProxyView color,const SkIRect & colorSubset,const GrCaps & caps)415 std::unique_ptr<GrFragmentProcessor> GrDisplacementMapEffect::Make(SkColorChannel xChannelSelector,
416                                                                    SkColorChannel yChannelSelector,
417                                                                    SkVector scale,
418                                                                    GrSurfaceProxyView displacement,
419                                                                    const SkIRect& displSubset,
420                                                                    const SkMatrix& offsetMatrix,
421                                                                    GrSurfaceProxyView color,
422                                                                    const SkIRect& colorSubset,
423                                                                    const GrCaps& caps) {
424     static constexpr GrSamplerState kColorSampler(GrSamplerState::WrapMode::kClampToBorder,
425                                                   GrSamplerState::Filter::kNearest);
426     auto colorEffect = GrTextureEffect::MakeSubset(std::move(color),
427                                                    kPremul_SkAlphaType,
428                                                    SkMatrix::Translate(colorSubset.topLeft()),
429                                                    kColorSampler,
430                                                    SkRect::Make(colorSubset),
431                                                    caps);
432 
433     auto dispM = SkMatrix::Concat(SkMatrix::Translate(displSubset.topLeft()), offsetMatrix);
434     auto dispEffect = GrTextureEffect::Make(std::move(displacement),
435                                             kPremul_SkAlphaType,
436                                             dispM,
437                                             GrSamplerState::Filter::kNearest);
438 
439     return std::unique_ptr<GrFragmentProcessor>(
440             new GrDisplacementMapEffect(xChannelSelector,
441                                         yChannelSelector,
442                                         scale,
443                                         std::move(dispEffect),
444                                         std::move(colorEffect)));
445 }
446 
447 std::unique_ptr<GrFragmentProcessor::ProgramImpl>
onMakeProgramImpl() const448 GrDisplacementMapEffect::onMakeProgramImpl() const {
449     return std::make_unique<Impl>();
450 }
451 
onAddToKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const452 void GrDisplacementMapEffect::onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
453     static constexpr int kChannelSelectorKeyBits = 2;  // Max value is 3, so 2 bits are required
454 
455     uint32_t xKey = static_cast<uint32_t>(fXChannelSelector);
456     uint32_t yKey = static_cast<uint32_t>(fYChannelSelector) << kChannelSelectorKeyBits;
457 
458     b->add32(xKey | yKey);
459 }
460 
GrDisplacementMapEffect(SkColorChannel xChannelSelector,SkColorChannel yChannelSelector,const SkVector & scale,std::unique_ptr<GrFragmentProcessor> displacement,std::unique_ptr<GrFragmentProcessor> color)461 GrDisplacementMapEffect::GrDisplacementMapEffect(SkColorChannel xChannelSelector,
462                                                  SkColorChannel yChannelSelector,
463                                                  const SkVector& scale,
464                                                  std::unique_ptr<GrFragmentProcessor> displacement,
465                                                  std::unique_ptr<GrFragmentProcessor> color)
466         : INHERITED(kGrDisplacementMapEffect_ClassID, GrFragmentProcessor::kNone_OptimizationFlags)
467         , fXChannelSelector(xChannelSelector)
468         , fYChannelSelector(yChannelSelector)
469         , fScale(scale) {
470     this->registerChild(std::move(displacement));
471     this->registerChild(std::move(color), SkSL::SampleUsage::Explicit());
472     this->setUsesSampleCoordsDirectly();
473 }
474 
GrDisplacementMapEffect(const GrDisplacementMapEffect & that)475 GrDisplacementMapEffect::GrDisplacementMapEffect(const GrDisplacementMapEffect& that)
476         : INHERITED(that)
477         , fXChannelSelector(that.fXChannelSelector)
478         , fYChannelSelector(that.fYChannelSelector)
479         , fScale(that.fScale) {}
480 
~GrDisplacementMapEffect()481 GrDisplacementMapEffect::~GrDisplacementMapEffect() {}
482 
clone() const483 std::unique_ptr<GrFragmentProcessor> GrDisplacementMapEffect::clone() const {
484     return std::unique_ptr<GrFragmentProcessor>(new GrDisplacementMapEffect(*this));
485 }
486 
onIsEqual(const GrFragmentProcessor & sBase) const487 bool GrDisplacementMapEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
488     const GrDisplacementMapEffect& s = sBase.cast<GrDisplacementMapEffect>();
489     return fXChannelSelector == s.fXChannelSelector &&
490            fYChannelSelector == s.fYChannelSelector &&
491            fScale == s.fScale;
492 }
493 
494 ///////////////////////////////////////////////////////////////////////////////
495 
496 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDisplacementMapEffect);
497 
498 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)499 std::unique_ptr<GrFragmentProcessor> GrDisplacementMapEffect::TestCreate(GrProcessorTestData* d) {
500     auto [dispView,  ct1, at1] = d->randomView();
501     auto [colorView, ct2, at2] = d->randomView();
502     static const int kMaxComponent = static_cast<int>(SkColorChannel::kLastEnum);
503     SkColorChannel xChannelSelector =
504         static_cast<SkColorChannel>(d->fRandom->nextRangeU(1, kMaxComponent));
505     SkColorChannel yChannelSelector =
506         static_cast<SkColorChannel>(d->fRandom->nextRangeU(1, kMaxComponent));
507     SkVector scale;
508     scale.fX = d->fRandom->nextRangeScalar(0, 100.0f);
509     scale.fY = d->fRandom->nextRangeScalar(0, 100.0f);
510     SkISize colorDimensions;
511     colorDimensions.fWidth = d->fRandom->nextRangeU(0, colorView.width());
512     colorDimensions.fHeight = d->fRandom->nextRangeU(0, colorView.height());
513     SkIRect dispRect = SkIRect::MakeSize(dispView.dimensions());
514 
515     return GrDisplacementMapEffect::Make(xChannelSelector,
516                                          yChannelSelector,
517                                          scale,
518                                          std::move(dispView),
519                                          dispRect,
520                                          SkMatrix::I(),
521                                          std::move(colorView),
522                                          SkIRect::MakeSize(colorDimensions),
523                                          *d->caps());
524 }
525 
526 #endif
527 
528 ///////////////////////////////////////////////////////////////////////////////
529 
emitCode(EmitArgs & args)530 void GrDisplacementMapEffect::Impl::emitCode(EmitArgs& args) {
531     const GrDisplacementMapEffect& displacementMap = args.fFp.cast<GrDisplacementMapEffect>();
532 
533     fScaleUni = args.fUniformHandler->addUniform(&displacementMap, kFragment_GrShaderFlag,
534                                                  kHalf2_GrSLType, "Scale");
535     const char* scaleUni = args.fUniformHandler->getUniformCStr(fScaleUni);
536 
537     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
538     SkString displacementSample = this->invokeChild(/*childIndex=*/0, args);
539     fragBuilder->codeAppendf("half4 dColor = unpremul(%s);", displacementSample.c_str());
540 
541     auto chanChar = [](SkColorChannel c) {
542         switch(c) {
543             case SkColorChannel::kR: return 'r';
544             case SkColorChannel::kG: return 'g';
545             case SkColorChannel::kB: return 'b';
546             case SkColorChannel::kA: return 'a';
547             default: SkUNREACHABLE;
548         }
549     };
550     fragBuilder->codeAppendf("float2 cCoords = %s + %s * (dColor.%c%c - half2(0.5));",
551                              args.fSampleCoord,
552                              scaleUni,
553                              chanChar(displacementMap.fXChannelSelector),
554                              chanChar(displacementMap.fYChannelSelector));
555 
556     SkString colorSample = this->invokeChild(/*childIndex=*/1, args, "cCoords");
557 
558     fragBuilder->codeAppendf("return %s;", colorSample.c_str());
559 }
560 
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & proc)561 void GrDisplacementMapEffect::Impl::onSetData(const GrGLSLProgramDataManager& pdman,
562                                               const GrFragmentProcessor& proc) {
563     const auto& displacementMap = proc.cast<GrDisplacementMapEffect>();
564     pdman.set2f(fScaleUni, displacementMap.fScale.x(), displacementMap.fScale.y());
565 }
566 #endif
567