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