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