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