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