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