• 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 "SkDisplacementMapEffect.h"
9 
10 #include "SkBitmap.h"
11 #include "SkColorSpaceXformer.h"
12 #include "SkReadBuffer.h"
13 #include "SkSpecialImage.h"
14 #include "SkWriteBuffer.h"
15 #include "SkUnPreMultiply.h"
16 #include "SkColorPriv.h"
17 #if SK_SUPPORT_GPU
18 #include "GrClip.h"
19 #include "GrContext.h"
20 #include "GrCoordTransform.h"
21 #include "GrRenderTargetContext.h"
22 #include "GrTexture.h"
23 #include "GrTextureProxy.h"
24 #include "SkGr.h"
25 #include "effects/GrTextureDomain.h"
26 #include "glsl/GrGLSLColorSpaceXformHelper.h"
27 #include "glsl/GrGLSLFragmentProcessor.h"
28 #include "glsl/GrGLSLFragmentShaderBuilder.h"
29 #include "glsl/GrGLSLProgramDataManager.h"
30 #include "glsl/GrGLSLUniformHandler.h"
31 #endif
32 
33 namespace {
34 
35 #define kChannelSelectorKeyBits 3; // Max value is 4, so 3 bits are required at most
36 
37 const uint8_t gChannelTypeToShift[] = {
38      0,  // unknown
39     SK_R32_SHIFT,
40     SK_G32_SHIFT,
41     SK_B32_SHIFT,
42     SK_A32_SHIFT,
43 };
44 struct Extractor {
Extractor__anonbdb5eb400111::Extractor45     Extractor(SkDisplacementMapEffect::ChannelSelectorType typeX,
46               SkDisplacementMapEffect::ChannelSelectorType typeY)
47         : fShiftX(gChannelTypeToShift[typeX])
48         , fShiftY(gChannelTypeToShift[typeY])
49     {}
50 
51     unsigned fShiftX, fShiftY;
52 
getX__anonbdb5eb400111::Extractor53     unsigned getX(SkPMColor c) const { return (c >> fShiftX) & 0xFF; }
getY__anonbdb5eb400111::Extractor54     unsigned getY(SkPMColor c) const { return (c >> fShiftY) & 0xFF; }
55 };
56 
unpremul_pm(SkPMColor c)57 static SkPMColor unpremul_pm(SkPMColor c) {
58     const U8CPU a = SkGetPackedA32(c);
59     if (0 == a) {
60         return 0;
61     } else if (0xFF == a) {
62         return c;
63     }
64     const unsigned scale = SkUnPreMultiply::GetScale(a);
65     return SkPackARGB32NoCheck(a,
66                                SkUnPreMultiply::ApplyScale(scale, SkGetPackedR32(c)),
67                                SkUnPreMultiply::ApplyScale(scale, SkGetPackedG32(c)),
68                                SkUnPreMultiply::ApplyScale(scale, SkGetPackedB32(c)));
69 }
70 
computeDisplacement(Extractor ex,const SkVector & scale,SkBitmap * dst,const SkBitmap & displ,const SkIPoint & offset,const SkBitmap & src,const SkIRect & bounds)71 void computeDisplacement(Extractor ex, const SkVector& scale, SkBitmap* dst,
72                          const SkBitmap& displ, const SkIPoint& offset,
73                          const SkBitmap& src,
74                          const SkIRect& bounds) {
75     static const SkScalar Inv8bit = SkScalarInvert(255);
76     const int srcW = src.width();
77     const int srcH = src.height();
78     const SkVector scaleForColor = SkVector::Make(scale.fX * Inv8bit, scale.fY * Inv8bit);
79     const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - scale.fX * SK_ScalarHalf,
80                                              SK_ScalarHalf - scale.fY * SK_ScalarHalf);
81     SkPMColor* dstPtr = dst->getAddr32(0, 0);
82     for (int y = bounds.top(); y < bounds.bottom(); ++y) {
83         const SkPMColor* displPtr = displ.getAddr32(bounds.left() + offset.fX, y + offset.fY);
84         for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) {
85             SkPMColor c = unpremul_pm(*displPtr);
86 
87             SkScalar displX = scaleForColor.fX * ex.getX(c) + scaleAdj.fX;
88             SkScalar displY = scaleForColor.fY * ex.getY(c) + scaleAdj.fY;
89             // Truncate the displacement values
90             const int srcX = x + SkScalarTruncToInt(displX);
91             const int srcY = y + SkScalarTruncToInt(displY);
92             *dstPtr++ = ((srcX < 0) || (srcX >= srcW) || (srcY < 0) || (srcY >= srcH)) ?
93                       0 : *(src.getAddr32(srcX, srcY));
94         }
95     }
96 }
97 
channel_selector_type_is_valid(SkDisplacementMapEffect::ChannelSelectorType cst)98 bool channel_selector_type_is_valid(SkDisplacementMapEffect::ChannelSelectorType cst) {
99     switch (cst) {
100     case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
101     case SkDisplacementMapEffect::kR_ChannelSelectorType:
102     case SkDisplacementMapEffect::kG_ChannelSelectorType:
103     case SkDisplacementMapEffect::kB_ChannelSelectorType:
104     case SkDisplacementMapEffect::kA_ChannelSelectorType:
105         return true;
106     default:
107         break;
108     }
109     return false;
110 }
111 
112 } // end namespace
113 
114 ///////////////////////////////////////////////////////////////////////////////
115 
Make(ChannelSelectorType xChannelSelector,ChannelSelectorType yChannelSelector,SkScalar scale,sk_sp<SkImageFilter> displacement,sk_sp<SkImageFilter> color,const CropRect * cropRect)116 sk_sp<SkImageFilter> SkDisplacementMapEffect::Make(ChannelSelectorType xChannelSelector,
117                                                    ChannelSelectorType yChannelSelector,
118                                                    SkScalar scale,
119                                                    sk_sp<SkImageFilter> displacement,
120                                                    sk_sp<SkImageFilter> color,
121                                                    const CropRect* cropRect) {
122     if (!channel_selector_type_is_valid(xChannelSelector) ||
123         !channel_selector_type_is_valid(yChannelSelector)) {
124         return nullptr;
125     }
126 
127     sk_sp<SkImageFilter> inputs[2] = { std::move(displacement), std::move(color) };
128     return sk_sp<SkImageFilter>(new SkDisplacementMapEffect(xChannelSelector,
129                                                             yChannelSelector,
130                                                             scale, inputs, cropRect));
131 }
132 
SkDisplacementMapEffect(ChannelSelectorType xChannelSelector,ChannelSelectorType yChannelSelector,SkScalar scale,sk_sp<SkImageFilter> inputs[2],const CropRect * cropRect)133 SkDisplacementMapEffect::SkDisplacementMapEffect(ChannelSelectorType xChannelSelector,
134                                                  ChannelSelectorType yChannelSelector,
135                                                  SkScalar scale,
136                                                  sk_sp<SkImageFilter> inputs[2],
137                                                  const CropRect* cropRect)
138     : INHERITED(inputs, 2, cropRect)
139     , fXChannelSelector(xChannelSelector)
140     , fYChannelSelector(yChannelSelector)
141     , fScale(scale) {
142 }
143 
~SkDisplacementMapEffect()144 SkDisplacementMapEffect::~SkDisplacementMapEffect() {
145 }
146 
CreateProc(SkReadBuffer & buffer)147 sk_sp<SkFlattenable> SkDisplacementMapEffect::CreateProc(SkReadBuffer& buffer) {
148     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2);
149     ChannelSelectorType xsel = (ChannelSelectorType)buffer.readInt();
150     ChannelSelectorType ysel = (ChannelSelectorType)buffer.readInt();
151     SkScalar scale = buffer.readScalar();
152     return Make(xsel, ysel, scale,
153                 common.getInput(0), common.getInput(1),
154                 &common.cropRect());
155 }
156 
flatten(SkWriteBuffer & buffer) const157 void SkDisplacementMapEffect::flatten(SkWriteBuffer& buffer) const {
158     this->INHERITED::flatten(buffer);
159     buffer.writeInt((int) fXChannelSelector);
160     buffer.writeInt((int) fYChannelSelector);
161     buffer.writeScalar(fScale);
162 }
163 
164 #if SK_SUPPORT_GPU
165 class GrDisplacementMapEffect : public GrFragmentProcessor {
166 public:
Make(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,SkVector scale,sk_sp<GrTextureProxy> displacement,const SkMatrix & offsetMatrix,sk_sp<GrTextureProxy> color,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkISize & colorDimensions)167     static sk_sp<GrFragmentProcessor> Make(
168                 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
169                 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, SkVector scale,
170                 sk_sp<GrTextureProxy> displacement, const SkMatrix& offsetMatrix,
171                 sk_sp<GrTextureProxy> color,
172                 sk_sp<GrColorSpaceXform> colorSpaceXform, const SkISize& colorDimensions) {
173         return sk_sp<GrFragmentProcessor>(
174             new GrDisplacementMapEffect(xChannelSelector, yChannelSelector, scale,
175                                         std::move(displacement),
176                                         offsetMatrix, std::move(color), std::move(colorSpaceXform),
177                                         colorDimensions));
178     }
179 
180     ~GrDisplacementMapEffect() override;
181 
xChannelSelector() const182     SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const {
183         return fXChannelSelector;
184     }
yChannelSelector() const185     SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const {
186         return fYChannelSelector;
187     }
scale() const188     const SkVector& scale() const { return fScale; }
189 
name() const190     const char* name() const override { return "DisplacementMap"; }
domain() const191     const GrTextureDomain& domain() const { return fDomain; }
colorSpaceXform() const192     GrColorSpaceXform* colorSpaceXform() const { return fColorSpaceXform.get(); }
193 
194 private:
195     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
196 
197     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
198 
199     bool onIsEqual(const GrFragmentProcessor&) const override;
200 
201     GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
202                             SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
203                             const SkVector& scale,
204                             sk_sp<GrTextureProxy> displacement, const SkMatrix& offsetMatrix,
205                             sk_sp<GrTextureProxy> color, sk_sp<GrColorSpaceXform> colorSpaceXform,
206                             const SkISize& colorDimensions);
207 
208     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
209 
210     GrCoordTransform            fDisplacementTransform;
211     TextureSampler              fDisplacementSampler;
212     GrCoordTransform            fColorTransform;
213     GrTextureDomain             fDomain;
214     TextureSampler              fColorSampler;
215     sk_sp<GrColorSpaceXform>    fColorSpaceXform;
216     SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
217     SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
218     SkVector fScale;
219 
220     typedef GrFragmentProcessor INHERITED;
221 };
222 #endif
223 
onFilterImage(SkSpecialImage * source,const Context & ctx,SkIPoint * offset) const224 sk_sp<SkSpecialImage> SkDisplacementMapEffect::onFilterImage(SkSpecialImage* source,
225                                                              const Context& ctx,
226                                                              SkIPoint* offset) const {
227     SkIPoint colorOffset = SkIPoint::Make(0, 0);
228     sk_sp<SkSpecialImage> color(this->filterInput(1, source, ctx, &colorOffset));
229     if (!color) {
230         return nullptr;
231     }
232 
233     SkIPoint displOffset = SkIPoint::Make(0, 0);
234     // Creation of the displacement map should happen in a non-colorspace aware context. This
235     // texture is a purely mathematical construct, so we want to just operate on the stored
236     // values. Consider:
237     // User supplies an sRGB displacement map. If we're rendering to a wider gamut, then we could
238     // end up filtering the displacement map into that gamut, which has the effect of reducing
239     // the amount of displacement that it represents (as encoded values move away from the
240     // primaries).
241     // With a more complex DAG attached to this input, it's not clear that working in ANY specific
242     // color space makes sense, so we ignore color spaces (and gamma) entirely. This may not be
243     // ideal, but it's at least consistent and predictable.
244     Context displContext(ctx.ctm(), ctx.clipBounds(), ctx.cache(), OutputProperties(nullptr));
245     sk_sp<SkSpecialImage> displ(this->filterInput(0, source, displContext, &displOffset));
246     if (!displ) {
247         return nullptr;
248     }
249 
250     const SkIRect srcBounds = SkIRect::MakeXYWH(colorOffset.x(), colorOffset.y(),
251                                                 color->width(), color->height());
252 
253     // Both paths do bounds checking on color pixel access, we don't need to
254     // pad the color bitmap to bounds here.
255     SkIRect bounds;
256     if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
257         return nullptr;
258     }
259 
260     SkIRect displBounds;
261     displ = this->applyCropRect(ctx, displ.get(), &displOffset, &displBounds);
262     if (!displ) {
263         return nullptr;
264     }
265 
266     if (!bounds.intersect(displBounds)) {
267         return nullptr;
268     }
269 
270     const SkIRect colorBounds = bounds.makeOffset(-colorOffset.x(), -colorOffset.y());
271 
272     SkVector scale = SkVector::Make(fScale, fScale);
273     ctx.ctm().mapVectors(&scale, 1);
274 
275 #if SK_SUPPORT_GPU
276     if (source->isTextureBacked()) {
277         GrContext* context = source->getContext();
278 
279         sk_sp<GrTextureProxy> colorProxy(color->asTextureProxyRef(context));
280         sk_sp<GrTextureProxy> displProxy(displ->asTextureProxyRef(context));
281         if (!colorProxy || !displProxy) {
282             return nullptr;
283         }
284 
285         SkMatrix offsetMatrix = SkMatrix::MakeTrans(SkIntToScalar(colorOffset.fX - displOffset.fX),
286                                                     SkIntToScalar(colorOffset.fY - displOffset.fY));
287         SkColorSpace* colorSpace = ctx.outputProperties().colorSpace();
288         sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(color->getColorSpace(),
289                                                                            colorSpace);
290         GrPaint paint;
291         paint.addColorFragmentProcessor(
292             GrDisplacementMapEffect::Make(fXChannelSelector,
293                                           fYChannelSelector,
294                                           scale,
295                                           std::move(displProxy),
296                                           offsetMatrix,
297                                           std::move(colorProxy),
298                                           std::move(colorSpaceXform),
299                                           SkISize::Make(color->width(), color->height())));
300         paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
301         SkMatrix matrix;
302         matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y()));
303 
304         sk_sp<GrRenderTargetContext> renderTargetContext(
305             context->makeDeferredRenderTargetContext(SkBackingFit::kApprox,
306                                                      bounds.width(), bounds.height(),
307                                                      GrRenderableConfigForColorSpace(colorSpace),
308                                                      sk_ref_sp(colorSpace)));
309         if (!renderTargetContext) {
310             return nullptr;
311         }
312         paint.setGammaCorrect(renderTargetContext->isGammaCorrect());
313 
314         renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix,
315                                       SkRect::Make(colorBounds));
316 
317         offset->fX = bounds.left();
318         offset->fY = bounds.top();
319         return SkSpecialImage::MakeDeferredFromGpu(
320                                             context,
321                                             SkIRect::MakeWH(bounds.width(), bounds.height()),
322                                             kNeedNewImageUniqueID_SpecialImage,
323                                             renderTargetContext->asTextureProxyRef(),
324                                             renderTargetContext->refColorSpace());
325     }
326 #endif
327 
328     SkBitmap colorBM, displBM;
329 
330     if (!color->getROPixels(&colorBM) || !displ->getROPixels(&displBM)) {
331         return nullptr;
332     }
333 
334     if ((colorBM.colorType() != kN32_SkColorType) ||
335         (displBM.colorType() != kN32_SkColorType)) {
336         return nullptr;
337     }
338 
339     if (!colorBM.getPixels() || !displBM.getPixels()) {
340         return nullptr;
341     }
342 
343     SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(),
344                                             colorBM.alphaType());
345 
346     SkBitmap dst;
347     if (!dst.tryAllocPixels(info)) {
348         return nullptr;
349     }
350 
351     computeDisplacement(Extractor(fXChannelSelector, fYChannelSelector), scale, &dst,
352                         displBM, colorOffset - displOffset, colorBM, colorBounds);
353 
354     offset->fX = bounds.left();
355     offset->fY = bounds.top();
356     return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()),
357                                           dst);
358 }
359 
onMakeColorSpace(SkColorSpaceXformer * xformer) const360 sk_sp<SkImageFilter> SkDisplacementMapEffect::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
361     SkASSERT(2 == this->countInputs());
362     // Intentionally avoid xforming the displacement filter.  The values will be used as
363     // offsets, not as colors.
364     sk_sp<SkImageFilter> displacement = sk_ref_sp(const_cast<SkImageFilter*>(this->getInput(0)));
365     sk_sp<SkImageFilter> color = xformer->apply(this->getInput(1));
366 
367     if (color.get() != this->getInput(1)) {
368         return SkDisplacementMapEffect::Make(fXChannelSelector, fYChannelSelector, fScale,
369                                              std::move(displacement), std::move(color),
370                                              this->getCropRectIfSet());
371     }
372     return this->refMe();
373 }
374 
computeFastBounds(const SkRect & src) const375 SkRect SkDisplacementMapEffect::computeFastBounds(const SkRect& src) const {
376     SkRect bounds = this->getColorInput() ? this->getColorInput()->computeFastBounds(src) : src;
377     bounds.outset(SkScalarAbs(fScale) * SK_ScalarHalf, SkScalarAbs(fScale) * SK_ScalarHalf);
378     return bounds;
379 }
380 
onFilterNodeBounds(const SkIRect & src,const SkMatrix & ctm,MapDirection) const381 SkIRect SkDisplacementMapEffect::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
382                                                     MapDirection) const {
383     SkVector scale = SkVector::Make(fScale, fScale);
384     ctm.mapVectors(&scale, 1);
385     return src.makeOutset(SkScalarCeilToInt(SkScalarAbs(scale.fX) * SK_ScalarHalf),
386                           SkScalarCeilToInt(SkScalarAbs(scale.fY) * SK_ScalarHalf));
387 }
388 
onFilterBounds(const SkIRect & src,const SkMatrix & ctm,MapDirection direction) const389 SkIRect SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
390                                                 MapDirection direction) const {
391     // Recurse only into color input.
392     if (this->getColorInput()) {
393         return this->getColorInput()->filterBounds(src, ctm, direction);
394     }
395     return src;
396 }
397 
398 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const399 void SkDisplacementMapEffect::toString(SkString* str) const {
400     str->appendf("SkDisplacementMapEffect: (");
401     str->appendf("scale: %f ", fScale);
402     str->appendf("displacement: (");
403     if (this->getDisplacementInput()) {
404         this->getDisplacementInput()->toString(str);
405     }
406     str->appendf(") color: (");
407     if (this->getColorInput()) {
408         this->getColorInput()->toString(str);
409     }
410     str->appendf("))");
411 }
412 #endif
413 
414 ///////////////////////////////////////////////////////////////////////////////
415 
416 #if SK_SUPPORT_GPU
417 class GrGLDisplacementMapEffect : public GrGLSLFragmentProcessor {
418 public:
419     void emitCode(EmitArgs&) override;
420 
421     static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
422 
423 protected:
424     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
425 
426 private:
427     typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
428 
429     UniformHandle fScaleUni;
430     GrGLSLColorSpaceXformHelper fColorSpaceHelper;
431     GrTextureDomain::GLDomain fGLDomain;
432 
433     typedef GrGLSLFragmentProcessor INHERITED;
434 };
435 
436 ///////////////////////////////////////////////////////////////////////////////
437 
onCreateGLSLInstance() const438 GrGLSLFragmentProcessor* GrDisplacementMapEffect::onCreateGLSLInstance() const {
439     return new GrGLDisplacementMapEffect;
440 }
441 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const442 void GrDisplacementMapEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
443                                                     GrProcessorKeyBuilder* b) const {
444     GrGLDisplacementMapEffect::GenKey(*this, caps, b);
445 }
446 
GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,const SkVector & scale,sk_sp<GrTextureProxy> displacement,const SkMatrix & offsetMatrix,sk_sp<GrTextureProxy> color,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkISize & colorDimensions)447 GrDisplacementMapEffect::GrDisplacementMapEffect(
448         SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
449         SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
450         const SkVector& scale,
451         sk_sp<GrTextureProxy> displacement,
452         const SkMatrix& offsetMatrix,
453         sk_sp<GrTextureProxy> color,
454         sk_sp<GrColorSpaceXform> colorSpaceXform,
455         const SkISize& colorDimensions)
456         : INHERITED(GrPixelConfigIsOpaque(color->config()) ? kPreservesOpaqueInput_OptimizationFlag
457                                                            : kNone_OptimizationFlags)
458         , fDisplacementTransform(offsetMatrix, displacement.get())
459         , fDisplacementSampler(displacement)
460         , fColorTransform(color.get())
461         , fDomain(color.get(), GrTextureDomain::MakeTexelDomain(SkIRect::MakeSize(colorDimensions)),
462                   GrTextureDomain::kDecal_Mode)
463         , fColorSampler(color)
464         , fColorSpaceXform(std::move(colorSpaceXform))
465         , fXChannelSelector(xChannelSelector)
466         , fYChannelSelector(yChannelSelector)
467         , fScale(scale) {
468     this->initClassID<GrDisplacementMapEffect>();
469     this->addCoordTransform(&fDisplacementTransform);
470     this->addTextureSampler(&fDisplacementSampler);
471     this->addCoordTransform(&fColorTransform);
472     this->addTextureSampler(&fColorSampler);
473 }
474 
~GrDisplacementMapEffect()475 GrDisplacementMapEffect::~GrDisplacementMapEffect() {
476 }
477 
onIsEqual(const GrFragmentProcessor & sBase) const478 bool GrDisplacementMapEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
479     const GrDisplacementMapEffect& s = sBase.cast<GrDisplacementMapEffect>();
480     return fXChannelSelector == s.fXChannelSelector &&
481            fYChannelSelector == s.fYChannelSelector &&
482            fScale == s.fScale;
483 }
484 
485 ///////////////////////////////////////////////////////////////////////////////
486 
487 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDisplacementMapEffect);
488 
489 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)490 sk_sp<GrFragmentProcessor> GrDisplacementMapEffect::TestCreate(GrProcessorTestData* d) {
491     int texIdxDispl = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
492                                                GrProcessorUnitTest::kAlphaTextureIdx;
493     int texIdxColor = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
494                                                GrProcessorUnitTest::kAlphaTextureIdx;
495     sk_sp<GrTextureProxy> dispProxy = d->textureProxy(texIdxDispl);
496     sk_sp<GrTextureProxy> colorProxy = d->textureProxy(texIdxColor);
497     static const int kMaxComponent = 4;
498     SkDisplacementMapEffect::ChannelSelectorType xChannelSelector =
499         static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
500                 d->fRandom->nextRangeU(1, kMaxComponent));
501     SkDisplacementMapEffect::ChannelSelectorType yChannelSelector =
502         static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
503                 d->fRandom->nextRangeU(1, kMaxComponent));
504     SkVector scale = SkVector::Make(d->fRandom->nextRangeScalar(0, 100.0f),
505                                     d->fRandom->nextRangeScalar(0, 100.0f));
506     SkISize colorDimensions;
507     colorDimensions.fWidth = d->fRandom->nextRangeU(0, colorProxy->width());
508     colorDimensions.fHeight = d->fRandom->nextRangeU(0, colorProxy->height());
509     auto colorSpaceXform = GrTest::TestColorXform(d->fRandom);
510     return GrDisplacementMapEffect::Make(xChannelSelector, yChannelSelector, scale,
511                                          std::move(dispProxy), SkMatrix::I(),
512                                          std::move(colorProxy), colorSpaceXform,
513                                          colorDimensions);
514 }
515 #endif
516 
517 ///////////////////////////////////////////////////////////////////////////////
518 
emitCode(EmitArgs & args)519 void GrGLDisplacementMapEffect::emitCode(EmitArgs& args) {
520     const GrDisplacementMapEffect& displacementMap = args.fFp.cast<GrDisplacementMapEffect>();
521     const GrTextureDomain& domain = displacementMap.domain();
522 
523     fScaleUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
524                                                  kVec2f_GrSLType, kDefault_GrSLPrecision, "Scale");
525     const char* scaleUni = args.fUniformHandler->getUniformCStr(fScaleUni);
526     const char* dColor = "dColor";
527     const char* cCoords = "cCoords";
528     const char* nearZero = "1e-6"; // Since 6.10352e-5 is the smallest half float, use
529                                    // a number smaller than that to approximate 0, but
530                                    // leave room for 32-bit float GPU rounding errors.
531 
532     fColorSpaceHelper.emitCode(args.fUniformHandler, displacementMap.colorSpaceXform());
533 
534     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
535     fragBuilder->codeAppendf("\t\tvec4 %s = ", dColor);
536     fragBuilder->appendTextureLookup(args.fTexSamplers[0], args.fTransformedCoords[0].c_str(),
537                                    args.fTransformedCoords[0].getType());
538     fragBuilder->codeAppend(";\n");
539 
540     // Unpremultiply the displacement
541     fragBuilder->codeAppendf(
542         "\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
543         dColor, dColor, nearZero, dColor, dColor);
544     SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[1]);
545     fragBuilder->codeAppendf("\t\tvec2 %s = %s + %s*(%s.",
546                              cCoords, coords2D.c_str(), scaleUni, dColor);
547 
548     switch (displacementMap.xChannelSelector()) {
549       case SkDisplacementMapEffect::kR_ChannelSelectorType:
550         fragBuilder->codeAppend("r");
551         break;
552       case SkDisplacementMapEffect::kG_ChannelSelectorType:
553         fragBuilder->codeAppend("g");
554         break;
555       case SkDisplacementMapEffect::kB_ChannelSelectorType:
556         fragBuilder->codeAppend("b");
557         break;
558       case SkDisplacementMapEffect::kA_ChannelSelectorType:
559         fragBuilder->codeAppend("a");
560         break;
561       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
562       default:
563         SkDEBUGFAIL("Unknown X channel selector");
564     }
565 
566     switch (displacementMap.yChannelSelector()) {
567       case SkDisplacementMapEffect::kR_ChannelSelectorType:
568         fragBuilder->codeAppend("r");
569         break;
570       case SkDisplacementMapEffect::kG_ChannelSelectorType:
571         fragBuilder->codeAppend("g");
572         break;
573       case SkDisplacementMapEffect::kB_ChannelSelectorType:
574         fragBuilder->codeAppend("b");
575         break;
576       case SkDisplacementMapEffect::kA_ChannelSelectorType:
577         fragBuilder->codeAppend("a");
578         break;
579       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
580       default:
581         SkDEBUGFAIL("Unknown Y channel selector");
582     }
583     fragBuilder->codeAppend("-vec2(0.5));\t\t");
584 
585     fGLDomain.sampleTexture(fragBuilder,
586                             args.fUniformHandler,
587                             args.fShaderCaps,
588                             domain,
589                             args.fOutputColor,
590                             SkString(cCoords),
591                             args.fTexSamplers[1],
592                             nullptr,
593                             &fColorSpaceHelper);
594     fragBuilder->codeAppend(";\n");
595 }
596 
onSetData(const GrGLSLProgramDataManager & pdman,const GrFragmentProcessor & proc)597 void GrGLDisplacementMapEffect::onSetData(const GrGLSLProgramDataManager& pdman,
598                                           const GrFragmentProcessor& proc) {
599     const GrDisplacementMapEffect& displacementMap = proc.cast<GrDisplacementMapEffect>();
600     GrTexture* colorTex = displacementMap.textureSampler(1).peekTexture();
601 
602     SkScalar scaleX = displacementMap.scale().fX / colorTex->width();
603     SkScalar scaleY = displacementMap.scale().fY / colorTex->height();
604     pdman.set2f(fScaleUni, SkScalarToFloat(scaleX),
605                 colorTex->origin() == kTopLeft_GrSurfaceOrigin ?
606                 SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY));
607     fGLDomain.setData(pdman, displacementMap.domain(), colorTex);
608     if (SkToBool(displacementMap.colorSpaceXform())) {
609         fColorSpaceHelper.setData(pdman, displacementMap.colorSpaceXform());
610     }
611 }
612 
GenKey(const GrProcessor & proc,const GrShaderCaps &,GrProcessorKeyBuilder * b)613 void GrGLDisplacementMapEffect::GenKey(const GrProcessor& proc,
614                                        const GrShaderCaps&, GrProcessorKeyBuilder* b) {
615     const GrDisplacementMapEffect& displacementMap = proc.cast<GrDisplacementMapEffect>();
616 
617     uint32_t xKey = displacementMap.xChannelSelector();
618     uint32_t yKey = displacementMap.yChannelSelector() << kChannelSelectorKeyBits;
619 
620     b->add32(xKey | yKey);
621     b->add32(GrColorSpaceXform::XformKey(displacementMap.colorSpaceXform()));
622 }
623 #endif
624