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/effects/SkDisplacementMapEffect.h"
9
10#include "include/core/SkBitmap.h"
11#include "include/core/SkUnPreMultiply.h"
12#include "include/private/SkColorData.h"
13#include "src/core/SkImageFilter_Base.h"
14#include "src/core/SkReadBuffer.h"
15#include "src/core/SkSpecialImage.h"
16#include "src/core/SkWriteBuffer.h"
17#if SK_SUPPORT_GPU
18#include "include/private/GrRecordingContext.h"
19#include "src/gpu/GrCaps.h"
20#include "src/gpu/GrClip.h"
21#include "src/gpu/GrColorSpaceXform.h"
22#include "src/gpu/GrCoordTransform.h"
23#include "src/gpu/GrRecordingContextPriv.h"
24#include "src/gpu/GrRenderTargetContext.h"
25#include "src/gpu/GrTexture.h"
26#include "src/gpu/GrTextureProxy.h"
27#include "src/gpu/SkGr.h"
28#include "src/gpu/effects/GrTextureDomain.h"
29#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
30#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
31#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
32#include "src/gpu/glsl/GrGLSLUniformHandler.h"
33#endif
34
35namespace {
36
37class SkDisplacementMapEffectImpl final : public SkImageFilter_Base {
38public:
39 SkDisplacementMapEffectImpl(SkColorChannel xChannelSelector, SkColorChannel yChannelSelector,
40 SkScalar scale, sk_sp<SkImageFilter> inputs[2],
41 const CropRect* cropRect)
42 : INHERITED(inputs, 2, cropRect)
43 , fXChannelSelector(xChannelSelector)
44 , fYChannelSelector(yChannelSelector)
45 , fScale(scale) {}
46
47 SkRect computeFastBounds(const SkRect& src) const override;
48
49 virtual SkIRect onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
50 MapDirection, const SkIRect* inputRect) const override;
51 SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm,
52 MapDirection, const SkIRect* inputRect) const override;
53
54protected:
55 sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
56
57 void flatten(SkWriteBuffer&) const override;
58
59private:
60 friend void SkDisplacementMapEffect::RegisterFlattenables();
61 SK_FLATTENABLE_HOOKS(SkDisplacementMapEffectImpl)
62
63 SkColorChannel fXChannelSelector;
64 SkColorChannel fYChannelSelector;
65 SkScalar fScale;
66
67 const SkImageFilter* getDisplacementInput() const { return getInput(0); }
68 const SkImageFilter* getColorInput() const { return getInput(1); }
69
70 typedef SkImageFilter_Base INHERITED;
71};
72
73// Shift values to extract channels from an SkColor (SkColorGetR, SkColorGetG, etc)
74const uint8_t gChannelTypeToShift[] = {
75 16, // R
76 8, // G
77 0, // B
78 24, // A
79};
80struct Extractor {
81 Extractor(SkColorChannel typeX,
82 SkColorChannel typeY)
83 : fShiftX(gChannelTypeToShift[static_cast<int>(typeX)])
84 , fShiftY(gChannelTypeToShift[static_cast<int>(typeY)])
85 {}
86
87 unsigned fShiftX, fShiftY;
88
89 unsigned getX(SkColor c) const { return (c >> fShiftX) & 0xFF; }
90 unsigned getY(SkColor c) const { return (c >> fShiftY) & 0xFF; }
91};
92
93static bool channel_selector_type_is_valid(SkColorChannel cst) {
94 switch (cst) {
95 case SkColorChannel::kR:
96 case SkColorChannel::kG:
97 case SkColorChannel::kB:
98 case SkColorChannel::kA:
99 return true;
100 default:
101 break;
102 }
103 return false;
104}
105
106static SkColorChannel convert_channel_type(SkDisplacementMapEffect::ChannelSelectorType c) {
107 switch(c) {
108 case SkDisplacementMapEffect::kR_ChannelSelectorType:
109 return SkColorChannel::kR;
110 case SkDisplacementMapEffect::kG_ChannelSelectorType:
111 return SkColorChannel::kG;
112 case SkDisplacementMapEffect::kB_ChannelSelectorType:
113 return SkColorChannel::kB;
114 case SkDisplacementMapEffect::kA_ChannelSelectorType:
115 return SkColorChannel::kA;
116 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
117 default:
118 // Raster backend historically treated this as B, GPU backend would fail when generating
119 // shader code. Just return B without aborting in debug-builds in order to keep fuzzers
120 // happy when they pass in the technically still valid kUnknown_ChannelSelectorType.
121 return SkColorChannel::kB;
122 }
123}
124
125} // end namespace
126
127///////////////////////////////////////////////////////////////////////////////
128
129sk_sp<SkImageFilter> SkDisplacementMapEffect::Make(ChannelSelectorType xChannelSelector,
130 ChannelSelectorType yChannelSelector,
131 SkScalar scale,
132 sk_sp<SkImageFilter> displacement,
133 sk_sp<SkImageFilter> color,
134 const SkImageFilter::CropRect* cropRect) {
135 return Make(convert_channel_type(xChannelSelector), convert_channel_type(yChannelSelector),
136 scale, std::move(displacement), std::move(color), cropRect);
137}
138
139sk_sp<SkImageFilter> SkDisplacementMapEffect::Make(SkColorChannel xChannelSelector,
140 SkColorChannel yChannelSelector,
141 SkScalar scale,
142 sk_sp<SkImageFilter> displacement,
143 sk_sp<SkImageFilter> color,
144 const SkImageFilter::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 SkDisplacementMapEffectImpl(xChannelSelector, yChannelSelector,
152 scale, inputs, cropRect));
153}
154
155void SkDisplacementMapEffect::RegisterFlattenables() {
156 SK_REGISTER_FLATTENABLE(SkDisplacementMapEffectImpl);
157 // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
158 SkFlattenable::Register("SkDisplacementMapEffect", SkDisplacementMapEffectImpl::CreateProc);
159}
160
161///////////////////////////////////////////////////////////////////////////////
162
163sk_sp<SkFlattenable> SkDisplacementMapEffectImpl::CreateProc(SkReadBuffer& buffer) {
164 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2);
165
166 SkColorChannel xsel, ysel;
167 if (buffer.isVersionLT(SkPicturePriv::kCleanupImageFilterEnums_Version)) {
168 xsel = convert_channel_type(buffer.read32LE(
169 SkDisplacementMapEffect::kLast_ChannelSelectorType));
170 ysel = convert_channel_type(buffer.read32LE(
171 SkDisplacementMapEffect::kLast_ChannelSelectorType));
172 } else {
173 xsel = buffer.read32LE(SkColorChannel::kLastEnum);
174 ysel = buffer.read32LE(SkColorChannel::kLastEnum);
175 }
176
177 SkScalar scale = buffer.readScalar();
178
179 return SkDisplacementMapEffect::Make(xsel, ysel, scale, common.getInput(0), common.getInput(1),
180 &common.cropRect());
181}
182
183void SkDisplacementMapEffectImpl::flatten(SkWriteBuffer& buffer) const {
184 this->INHERITED::flatten(buffer);
185 buffer.writeInt((int) fXChannelSelector);
186 buffer.writeInt((int) fYChannelSelector);
187 buffer.writeScalar(fScale);
188}
189
190#if SK_SUPPORT_GPU
191class GrDisplacementMapEffect : public GrFragmentProcessor {
192public:
193 static std::unique_ptr<GrFragmentProcessor> Make(
194 SkColorChannel xChannelSelector, SkColorChannel yChannelSelector, SkVector scale,
195 GrSurfaceProxyView displacement, const SkIRect& displSubset,
196 const SkMatrix& offsetMatrix, GrSurfaceProxyView color, const SkIRect& colorSubset) {
197 return std::unique_ptr<GrFragmentProcessor>(new GrDisplacementMapEffect(
198 xChannelSelector, yChannelSelector, scale, std::move(displacement), displSubset,
199 offsetMatrix, std::move(color), colorSubset));
200 }
201
202 ~GrDisplacementMapEffect() override;
203
204 SkColorChannel xChannelSelector() const {
205 return fXChannelSelector;
206 }
207 SkColorChannel yChannelSelector() const {
208 return fYChannelSelector;
209 }
210 const SkVector& scale() const { return fScale; }
211
212 const char* name() const override { return "DisplacementMap"; }
213 const GrTextureDomain& domain() const { return fDomain; }
214
215 std::unique_ptr<GrFragmentProcessor> clone() const override;
216
217private:
218 GrDisplacementMapEffect(const GrDisplacementMapEffect&);
219
220 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
221
222 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
223
224 bool onIsEqual(const GrFragmentProcessor&) const override;
225
226 GrDisplacementMapEffect(SkColorChannel xChannelSelector,
227 SkColorChannel yChannelSelector,
228 const SkVector& scale, GrSurfaceProxyView displacement,
229 const SkIRect& displSubset, const SkMatrix& offsetMatrix,
230 GrSurfaceProxyView color, const SkIRect& colorSubset);
231
232 const TextureSampler& onTextureSampler(int i) const override {
233 return IthTextureSampler(i, fDisplacementSampler, fColorSampler);
234 }
235
236 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
237
238 GrCoordTransform fDisplacementTransform;
239 TextureSampler fDisplacementSampler;
240 GrCoordTransform fColorTransform;
241 GrTextureDomain fDomain;
242 TextureSampler fColorSampler;
243 SkColorChannel fXChannelSelector;
244 SkColorChannel fYChannelSelector;
245 SkVector fScale;
246
247 typedef GrFragmentProcessor INHERITED;
248};
249#endif
250
251static void compute_displacement(Extractor ex, const SkVector& scale, SkBitmap* dst,
252 const SkBitmap& displ, const SkIPoint& offset,
253 const SkBitmap& src,
254 const SkIRect& bounds) {
255 static const SkScalar Inv8bit = SkScalarInvert(255);
256 const int srcW = src.width();
257 const int srcH = src.height();
258 const SkVector scaleForColor = SkVector::Make(scale.fX * Inv8bit, scale.fY * Inv8bit);
259 const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - scale.fX * SK_ScalarHalf,
260 SK_ScalarHalf - scale.fY * SK_ScalarHalf);
261 SkPMColor* dstPtr = dst->getAddr32(0, 0);
262 for (int y = bounds.top(); y < bounds.bottom(); ++y) {
263 const SkPMColor* displPtr = displ.getAddr32(bounds.left() + offset.fX, y + offset.fY);
264 for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) {
265 SkColor c = SkUnPreMultiply::PMColorToColor(*displPtr);
266
267 SkScalar displX = scaleForColor.fX * ex.getX(c) + scaleAdj.fX;
268 SkScalar displY = scaleForColor.fY * ex.getY(c) + scaleAdj.fY;
269 // Truncate the displacement values
270 const int32_t srcX = Sk32_sat_add(x, SkScalarTruncToInt(displX));
271 const int32_t srcY = Sk32_sat_add(y, SkScalarTruncToInt(displY));
272 *dstPtr++ = ((srcX < 0) || (srcX >= srcW) || (srcY < 0) || (srcY >= srcH)) ?
273 0 : *(src.getAddr32(srcX, srcY));
274 }
275 }
276}
277
278sk_sp<SkSpecialImage> SkDisplacementMapEffectImpl::onFilterImage(const Context& ctx,
279 SkIPoint* offset) const {
280 SkIPoint colorOffset = SkIPoint::Make(0, 0);
281 sk_sp<SkSpecialImage> color(this->filterInput(1, ctx, &colorOffset));
282 if (!color) {
283 return nullptr;
284 }
285
286 SkIPoint displOffset = SkIPoint::Make(0, 0);
287 // Creation of the displacement map should happen in a non-colorspace aware context. This
288 // texture is a purely mathematical construct, so we want to just operate on the stored
289 // values. Consider:
290 // User supplies an sRGB displacement map. If we're rendering to a wider gamut, then we could
291 // end up filtering the displacement map into that gamut, which has the effect of reducing
292 // the amount of displacement that it represents (as encoded values move away from the
293 // primaries).
294 // With a more complex DAG attached to this input, it's not clear that working in ANY specific
295 // color space makes sense, so we ignore color spaces (and gamma) entirely. This may not be
296 // ideal, but it's at least consistent and predictable.
297 Context displContext(ctx.mapping(), ctx.desiredOutput(), ctx.cache(),
298 kN32_SkColorType, nullptr, ctx.source());
299 sk_sp<SkSpecialImage> displ(this->filterInput(0, displContext, &displOffset));
300 if (!displ) {
301 return nullptr;
302 }
303
304 const SkIRect srcBounds = SkIRect::MakeXYWH(colorOffset.x(), colorOffset.y(),
305 color->width(), color->height());
306
307 // Both paths do bounds checking on color pixel access, we don't need to
308 // pad the color bitmap to bounds here.
309 SkIRect bounds;
310 if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
311 return nullptr;
312 }
313
314 SkIRect displBounds;
315 displ = this->applyCropRectAndPad(ctx, displ.get(), &displOffset, &displBounds);
316 if (!displ) {
317 return nullptr;
318 }
319
320 if (!bounds.intersect(displBounds)) {
321 return nullptr;
322 }
323
324 const SkIRect colorBounds = bounds.makeOffset(-colorOffset);
325 // If the offset overflowed (saturated) then we have to abort, as we need their
326 // dimensions to be equal. See https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=7209
327 if (colorBounds.size() != bounds.size()) {
328 return nullptr;
329 }
330
331 SkVector scale = SkVector::Make(fScale, fScale);
332 ctx.ctm().mapVectors(&scale, 1);
333
334#if SK_SUPPORT_GPU
335 if (ctx.gpuBacked()) {
336 auto context = ctx.getContext();
337
338 GrSurfaceProxyView colorView = color->view(context);
339 GrSurfaceProxyView displView = displ->view(context);
340 if (!colorView.proxy() || !displView.proxy()) {
341 return nullptr;
342 }
343 const auto isProtected = colorView.proxy()->isProtected();
344
345 SkMatrix offsetMatrix = SkMatrix::MakeTrans(SkIntToScalar(colorOffset.fX - displOffset.fX),
346 SkIntToScalar(colorOffset.fY - displOffset.fY));
347
348 std::unique_ptr<GrFragmentProcessor> fp =
349 GrDisplacementMapEffect::Make(fXChannelSelector,
350 fYChannelSelector,
351 scale,
352 std::move(displView),
353 displ->subset(),
354 offsetMatrix,
355 std::move(colorView),
356 color->subset());
357 fp = GrColorSpaceXformEffect::Make(std::move(fp), color->getColorSpace(),
358 color->alphaType(), ctx.colorSpace());
359
360 GrPaint paint;
361 paint.addColorFragmentProcessor(std::move(fp));
362 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
363 SkMatrix matrix;
364 matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y()));
365
366 auto renderTargetContext = GrRenderTargetContext::Make(
367 context, ctx.grColorType(), ctx.refColorSpace(), SkBackingFit::kApprox,
368 bounds.size(), 1, GrMipMapped::kNo, isProtected, kBottomLeft_GrSurfaceOrigin);
369 if (!renderTargetContext) {
370 return nullptr;
371 }
372
373 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix,
374 SkRect::Make(colorBounds));
375
376 offset->fX = bounds.left();
377 offset->fY = bounds.top();
378 return SkSpecialImage::MakeDeferredFromGpu(
379 context,
380 SkIRect::MakeWH(bounds.width(), bounds.height()),
381 kNeedNewImageUniqueID_SpecialImage,
382 renderTargetContext->readSurfaceView(),
383 renderTargetContext->colorInfo().colorType(),
384 renderTargetContext->colorInfo().refColorSpace());
385 }
386#endif
387
388 SkBitmap colorBM, displBM;
389
390 if (!color->getROPixels(&colorBM) || !displ->getROPixels(&displBM)) {
391 return nullptr;
392 }
393
394 if ((colorBM.colorType() != kN32_SkColorType) ||
395 (displBM.colorType() != kN32_SkColorType)) {
396 return nullptr;
397 }
398
399 if (!colorBM.getPixels() || !displBM.getPixels()) {
400 return nullptr;
401 }
402
403 SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(),
404 colorBM.alphaType());
405
406 SkBitmap dst;
407 if (!dst.tryAllocPixels(info)) {
408 return nullptr;
409 }
410
411 compute_displacement(Extractor(fXChannelSelector, fYChannelSelector), scale, &dst,
412 displBM, colorOffset - displOffset, colorBM, colorBounds);
413
414 offset->fX = bounds.left();
415 offset->fY = bounds.top();
416 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()),
417 dst);
418}
419
420SkRect SkDisplacementMapEffectImpl::computeFastBounds(const SkRect& src) const {
421 SkRect bounds = this->getColorInput() ? this->getColorInput()->computeFastBounds(src) : src;
422 bounds.outset(SkScalarAbs(fScale) * SK_ScalarHalf, SkScalarAbs(fScale) * SK_ScalarHalf);
423 return bounds;
424}
425
426SkIRect SkDisplacementMapEffectImpl::onFilterNodeBounds(
427 const SkIRect& src, const SkMatrix& ctm, MapDirection, const SkIRect* inputRect) const {
428 SkVector scale = SkVector::Make(fScale, fScale);
429 ctm.mapVectors(&scale, 1);
430 return src.makeOutset(SkScalarCeilToInt(SkScalarAbs(scale.fX) * SK_ScalarHalf),
431 SkScalarCeilToInt(SkScalarAbs(scale.fY) * SK_ScalarHalf));
432}
433
434SkIRect SkDisplacementMapEffectImpl::onFilterBounds(
435 const SkIRect& src, const SkMatrix& ctm, MapDirection dir, const SkIRect* inputRect) const {
436 // Recurse only into color input.
437 if (this->getColorInput()) {
438 return this->getColorInput()->filterBounds(src, ctm, dir, inputRect);
439 }
440 return src;
441}
442
443///////////////////////////////////////////////////////////////////////////////
444
445#if SK_SUPPORT_GPU
446class GrGLDisplacementMapEffect : public GrGLSLFragmentProcessor {
447public:
448 void emitCode(EmitArgs&) override;
449
450 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
451
452protected:
453 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
454
455private:
456 typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
457
458 UniformHandle fScaleUni;
459 GrTextureDomain::GLDomain fGLDomain;
460
461 typedef GrGLSLFragmentProcessor INHERITED;
462};
463
464///////////////////////////////////////////////////////////////////////////////
465
466GrGLSLFragmentProcessor* GrDisplacementMapEffect::onCreateGLSLInstance() const {
467 return new GrGLDisplacementMapEffect;
468}
469
470void GrDisplacementMapEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
471 GrProcessorKeyBuilder* b) const {
472 GrGLDisplacementMapEffect::GenKey(*this, caps, b);
473}
474
475GrDisplacementMapEffect::GrDisplacementMapEffect(
476 SkColorChannel xChannelSelector,
477 SkColorChannel yChannelSelector,
478 const SkVector& scale,
479 GrSurfaceProxyView displacement,
480 const SkIRect& displSubset,
481 const SkMatrix& offsetMatrix,
482 GrSurfaceProxyView color,
483 const SkIRect& colorSubset)
484 : INHERITED(kGrDisplacementMapEffect_ClassID,
485 GrFragmentProcessor::kNone_OptimizationFlags)
486 , fDisplacementTransform(
487 SkMatrix::Concat(SkMatrix::MakeTrans(displSubset.x(), displSubset.y()),
488 offsetMatrix),
489 displacement.proxy(), displacement.origin())
490 , fDisplacementSampler(std::move(displacement))
491 , fColorTransform(SkMatrix::MakeTrans(colorSubset.x(), colorSubset.y()), color.proxy(),
492 color.origin())
493 , fDomain(color.proxy(),
494 GrTextureDomain::MakeTexelDomain(colorSubset,
495 GrTextureDomain::kDecal_Mode),
496 GrTextureDomain::kDecal_Mode, GrTextureDomain::kDecal_Mode)
497 , fColorSampler(std::move(color))
498 , fXChannelSelector(xChannelSelector)
499 , fYChannelSelector(yChannelSelector)
500 , fScale(scale) {
501 this->addCoordTransform(&fDisplacementTransform);
502 this->addCoordTransform(&fColorTransform);
503 this->setTextureSamplerCnt(2);
504}
505
506GrDisplacementMapEffect::GrDisplacementMapEffect(const GrDisplacementMapEffect& that)
507 : INHERITED(kGrDisplacementMapEffect_ClassID, that.optimizationFlags())
508 , fDisplacementTransform(that.fDisplacementTransform)
509 , fDisplacementSampler(that.fDisplacementSampler)
510 , fColorTransform(that.fColorTransform)
511 , fDomain(that.fDomain)
512 , fColorSampler(that.fColorSampler)
513 , fXChannelSelector(that.fXChannelSelector)
514 , fYChannelSelector(that.fYChannelSelector)
515 , fScale(that.fScale) {
516 this->addCoordTransform(&fDisplacementTransform);
517 this->addCoordTransform(&fColorTransform);
518 this->setTextureSamplerCnt(2);
519}
520
521GrDisplacementMapEffect::~GrDisplacementMapEffect() {}
522
523std::unique_ptr<GrFragmentProcessor> GrDisplacementMapEffect::clone() const {
524 return std::unique_ptr<GrFragmentProcessor>(new GrDisplacementMapEffect(*this));
525}
526
527bool GrDisplacementMapEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
528 const GrDisplacementMapEffect& s = sBase.cast<GrDisplacementMapEffect>();
529 return fXChannelSelector == s.fXChannelSelector &&
530 fYChannelSelector == s.fYChannelSelector &&
531 fScale == s.fScale;
532}
533
534///////////////////////////////////////////////////////////////////////////////
535
536GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDisplacementMapEffect);
537
538#if GR_TEST_UTILS
539std::unique_ptr<GrFragmentProcessor> GrDisplacementMapEffect::TestCreate(GrProcessorTestData* d) {
540 auto [dispView, ct1, at1] = d->randomView();
541 auto [colorView, ct2, at2] = d->randomView();
542 static const int kMaxComponent = static_cast<int>(SkColorChannel::kLastEnum);
543 SkColorChannel xChannelSelector =
544 static_cast<SkColorChannel>(d->fRandom->nextRangeU(1, kMaxComponent));
545 SkColorChannel yChannelSelector =
546 static_cast<SkColorChannel>(d->fRandom->nextRangeU(1, kMaxComponent));
547 SkVector scale = SkVector::Make(d->fRandom->nextRangeScalar(0, 100.0f),
548 d->fRandom->nextRangeScalar(0, 100.0f));
549 SkISize colorDimensions;
550 colorDimensions.fWidth = d->fRandom->nextRangeU(0, colorView.width());
551 colorDimensions.fHeight = d->fRandom->nextRangeU(0, colorView.height());
552 SkIRect dispRect = SkIRect::MakeSize(dispView.dimensions());
553
554 return GrDisplacementMapEffect::Make(xChannelSelector, yChannelSelector, scale,
555 std::move(dispView),
556 dispRect,
557 SkMatrix::I(),
558 std::move(colorView), SkIRect::MakeSize(colorDimensions));
559}
560
561#endif
562
563///////////////////////////////////////////////////////////////////////////////
564
565void GrGLDisplacementMapEffect::emitCode(EmitArgs& args) {
566 const GrDisplacementMapEffect& displacementMap = args.fFp.cast<GrDisplacementMapEffect>();
567 const GrTextureDomain& domain = displacementMap.domain();
568
569 fScaleUni = args.fUniformHandler->addUniform(&displacementMap, kFragment_GrShaderFlag,
570 kHalf2_GrSLType, "Scale");
571 const char* scaleUni = args.fUniformHandler->getUniformCStr(fScaleUni);
572 const char* dColor = "dColor";
573 const char* cCoords = "cCoords";
574 const char* nearZero = "1e-6"; // Since 6.10352e-5 is the smallest half float, use
575 // a number smaller than that to approximate 0, but
576 // leave room for 32-bit float GPU rounding errors.
577
578 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
579 fragBuilder->codeAppendf("\t\thalf4 %s = ", dColor);
580 fragBuilder->appendTextureLookup(args.fTexSamplers[0],
581 args.fTransformedCoords[0].fVaryingPoint.c_str());
582 fragBuilder->codeAppend(";\n");
583
584 // Unpremultiply the displacement
585 fragBuilder->codeAppendf(
586 "\t\t%s.rgb = (%s.a < %s) ? half3(0.0) : saturate(%s.rgb / %s.a);",
587 dColor, dColor, nearZero, dColor, dColor);
588 SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[1].fVaryingPoint);
589 fragBuilder->codeAppendf("\t\tfloat2 %s = %s + %s*(%s.",
590 cCoords, coords2D.c_str(), scaleUni, dColor);
591
592 switch (displacementMap.xChannelSelector()) {
593 case SkColorChannel::kR:
594 fragBuilder->codeAppend("r");
595 break;
596 case SkColorChannel::kG:
597 fragBuilder->codeAppend("g");
598 break;
599 case SkColorChannel::kB:
600 fragBuilder->codeAppend("b");
601 break;
602 case SkColorChannel::kA:
603 fragBuilder->codeAppend("a");
604 break;
605 default:
606 SkDEBUGFAIL("Unknown X channel selector");
607 }
608
609 switch (displacementMap.yChannelSelector()) {
610 case SkColorChannel::kR:
611 fragBuilder->codeAppend("r");
612 break;
613 case SkColorChannel::kG:
614 fragBuilder->codeAppend("g");
615 break;
616 case SkColorChannel::kB:
617 fragBuilder->codeAppend("b");
618 break;
619 case SkColorChannel::kA:
620 fragBuilder->codeAppend("a");
621 break;
622 default:
623 SkDEBUGFAIL("Unknown Y channel selector");
624 }
625 fragBuilder->codeAppend("-half2(0.5));\t\t");
626
627 fGLDomain.sampleTexture(&displacementMap,
628 fragBuilder,
629 args.fUniformHandler,
630 args.fShaderCaps,
631 domain,
632 args.fOutputColor,
633 SkString(cCoords),
634 args.fTexSamplers[1]);
635 fragBuilder->codeAppend(";\n");
636}
637
638void GrGLDisplacementMapEffect::onSetData(const GrGLSLProgramDataManager& pdman,
639 const GrFragmentProcessor& proc) {
640 const GrDisplacementMapEffect& displacementMap = proc.cast<GrDisplacementMapEffect>();
641 const auto& view = displacementMap.textureSampler(1).view();
642 SkISize texDimensions = view.proxy()->backingStoreDimensions();
643
644 SkScalar scaleX = displacementMap.scale().fX / texDimensions.width();
645 SkScalar scaleY = displacementMap.scale().fY / texDimensions.height();
646 pdman.set2f(fScaleUni, SkScalarToFloat(scaleX),
647 view.origin() == kTopLeft_GrSurfaceOrigin ?
648 SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY));
649 fGLDomain.setData(pdman, displacementMap.domain(), view,
650 displacementMap.textureSampler(1).samplerState());
651}
652
653void GrGLDisplacementMapEffect::GenKey(const GrProcessor& proc,
654 const GrShaderCaps&, GrProcessorKeyBuilder* b) {
655 const GrDisplacementMapEffect& displacementMap = proc.cast<GrDisplacementMapEffect>();
656
657 static constexpr int kChannelSelectorKeyBits = 2; // Max value is 3, so 2 bits are required
658
659 uint32_t xKey = static_cast<uint32_t>(displacementMap.xChannelSelector());
660 uint32_t yKey = static_cast<uint32_t>(displacementMap.yChannelSelector())
661 << kChannelSelectorKeyBits;
662
663 b->add32(xKey | yKey);
664}
665#endif
666