2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkDisplacementMapEffect.h"
9 #include "SkReadBuffer.h"
10 #include "SkWriteBuffer.h"
11 #include "SkUnPreMultiply.h"
12 #include "SkColorPriv.h"
14 #include "GrContext.h"
15 #include "GrCoordTransform.h"
16 #include "gl/GrGLEffect.h"
17 #include "GrTBackendEffectFactory.h"
18 #include "SkImageFilterUtils.h"
23 template<SkDisplacementMapEffect::ChannelSelectorType type>
24 uint32_t getValue(SkColor, const SkUnPreMultiply::Scale*) {
25 SkDEBUGFAIL("Unknown channel selector");
29 template<> uint32_t getValue<SkDisplacementMapEffect::kR_ChannelSelectorType>(
30 SkColor l, const SkUnPreMultiply::Scale* table) {
31 return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedR32(l));
34 template<> uint32_t getValue<SkDisplacementMapEffect::kG_ChannelSelectorType>(
35 SkColor l, const SkUnPreMultiply::Scale* table) {
36 return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedG32(l));
39 template<> uint32_t getValue<SkDisplacementMapEffect::kB_ChannelSelectorType>(
40 SkColor l, const SkUnPreMultiply::Scale* table) {
41 return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedB32(l));
44 template<> uint32_t getValue<SkDisplacementMapEffect::kA_ChannelSelectorType>(
45 SkColor l, const SkUnPreMultiply::Scale*) {
46 return SkGetPackedA32(l);
49 template<SkDisplacementMapEffect::ChannelSelectorType typeX,
50 SkDisplacementMapEffect::ChannelSelectorType typeY>
51 void computeDisplacement(const SkVector& scale, SkBitmap* dst,
52 SkBitmap* displ, const SkIPoint& offset,
54 const SkIRect& bounds)
56 static const SkScalar Inv8bit = SkScalarDiv(SK_Scalar1, 255.0f);
57 const int srcW = src->width();
58 const int srcH = src->height();
59 const SkVector scaleForColor = SkVector::Make(SkScalarMul(scale.fX, Inv8bit),
60 SkScalarMul(scale.fY, Inv8bit));
61 const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - SkScalarMul(scale.fX, SK_ScalarHalf),
62 SK_ScalarHalf - SkScalarMul(scale.fY, SK_ScalarHalf));
63 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
64 SkPMColor* dstPtr = dst->getAddr32(0, 0);
65 for (int y = bounds.top(); y < bounds.bottom(); ++y) {
66 const SkPMColor* displPtr = displ->getAddr32(bounds.left() + offset.fX,
68 for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) {
69 const SkScalar displX = SkScalarMul(scaleForColor.fX,
70 SkIntToScalar(getValue<typeX>(*displPtr, table))) + scaleAdj.fX;
71 const SkScalar displY = SkScalarMul(scaleForColor.fY,
72 SkIntToScalar(getValue<typeY>(*displPtr, table))) + scaleAdj.fY;
73 // Truncate the displacement values
74 const int srcX = x + SkScalarTruncToInt(displX);
75 const int srcY = y + SkScalarTruncToInt(displY);
76 *dstPtr++ = ((srcX < 0) || (srcX >= srcW) || (srcY < 0) || (srcY >= srcH)) ?
77 0 : *(src->getAddr32(srcX, srcY));
82 template<SkDisplacementMapEffect::ChannelSelectorType typeX>
83 void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
84 const SkVector& scale, SkBitmap* dst,
85 SkBitmap* displ, const SkIPoint& offset,
87 const SkIRect& bounds)
89 switch (yChannelSelector) {
90 case SkDisplacementMapEffect::kR_ChannelSelectorType:
91 computeDisplacement<typeX, SkDisplacementMapEffect::kR_ChannelSelectorType>(
92 scale, dst, displ, offset, src, bounds);
94 case SkDisplacementMapEffect::kG_ChannelSelectorType:
95 computeDisplacement<typeX, SkDisplacementMapEffect::kG_ChannelSelectorType>(
96 scale, dst, displ, offset, src, bounds);
98 case SkDisplacementMapEffect::kB_ChannelSelectorType:
99 computeDisplacement<typeX, SkDisplacementMapEffect::kB_ChannelSelectorType>(
100 scale, dst, displ, offset, src, bounds);
102 case SkDisplacementMapEffect::kA_ChannelSelectorType:
103 computeDisplacement<typeX, SkDisplacementMapEffect::kA_ChannelSelectorType>(
104 scale, dst, displ, offset, src, bounds);
106 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
108 SkDEBUGFAIL("Unknown Y channel selector");
112 void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
113 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
114 const SkVector& scale, SkBitmap* dst,
115 SkBitmap* displ, const SkIPoint& offset,
117 const SkIRect& bounds)
119 switch (xChannelSelector) {
120 case SkDisplacementMapEffect::kR_ChannelSelectorType:
121 computeDisplacement<SkDisplacementMapEffect::kR_ChannelSelectorType>(
122 yChannelSelector, scale, dst, displ, offset, src, bounds);
124 case SkDisplacementMapEffect::kG_ChannelSelectorType:
125 computeDisplacement<SkDisplacementMapEffect::kG_ChannelSelectorType>(
126 yChannelSelector, scale, dst, displ, offset, src, bounds);
128 case SkDisplacementMapEffect::kB_ChannelSelectorType:
129 computeDisplacement<SkDisplacementMapEffect::kB_ChannelSelectorType>(
130 yChannelSelector, scale, dst, displ, offset, src, bounds);
132 case SkDisplacementMapEffect::kA_ChannelSelectorType:
133 computeDisplacement<SkDisplacementMapEffect::kA_ChannelSelectorType>(
134 yChannelSelector, scale, dst, displ, offset, src, bounds);
136 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
138 SkDEBUGFAIL("Unknown X channel selector");
142 bool channel_selector_type_is_valid(SkDisplacementMapEffect::ChannelSelectorType cst) {
144 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
145 case SkDisplacementMapEffect::kR_ChannelSelectorType:
146 case SkDisplacementMapEffect::kG_ChannelSelectorType:
147 case SkDisplacementMapEffect::kB_ChannelSelectorType:
148 case SkDisplacementMapEffect::kA_ChannelSelectorType:
158 ///////////////////////////////////////////////////////////////////////////////
160 SkDisplacementMapEffect::SkDisplacementMapEffect(ChannelSelectorType xChannelSelector,
161 ChannelSelectorType yChannelSelector,
163 SkImageFilter* displacement,
164 SkImageFilter* color,
165 const CropRect* cropRect)
166 : INHERITED(displacement, color, cropRect)
167 , fXChannelSelector(xChannelSelector)
168 , fYChannelSelector(yChannelSelector)
173 SkDisplacementMapEffect::~SkDisplacementMapEffect() {
176 SkDisplacementMapEffect::SkDisplacementMapEffect(SkReadBuffer& buffer)
177 : INHERITED(2, buffer)
179 fXChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt();
180 fYChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt();
181 fScale = buffer.readScalar();
182 buffer.validate(channel_selector_type_is_valid(fXChannelSelector) &&
183 channel_selector_type_is_valid(fYChannelSelector) &&
184 SkScalarIsFinite(fScale));
187 void SkDisplacementMapEffect::flatten(SkWriteBuffer& buffer) const {
188 this->INHERITED::flatten(buffer);
189 buffer.writeInt((int) fXChannelSelector);
190 buffer.writeInt((int) fYChannelSelector);
191 buffer.writeScalar(fScale);
194 bool SkDisplacementMapEffect::onFilterImage(Proxy* proxy,
198 SkIPoint* offset) const {
199 SkBitmap displ = src, color = src;
200 const SkImageFilter* colorInput = getColorInput();
201 const SkImageFilter* displInput = getDisplacementInput();
202 SkIPoint colorOffset = SkIPoint::Make(0, 0), displOffset = SkIPoint::Make(0, 0);
203 if ((colorInput && !colorInput->filterImage(proxy, src, ctm, &color, &colorOffset)) ||
204 (displInput && !displInput->filterImage(proxy, src, ctm, &displ, &displOffset))) {
207 if ((displ.config() != SkBitmap::kARGB_8888_Config) ||
208 (color.config() != SkBitmap::kARGB_8888_Config)) {
212 SkAutoLockPixels alp_displacement(displ), alp_color(color);
213 if (!displ.getPixels() || !color.getPixels()) {
217 color.getBounds(&bounds);
218 bounds.offset(colorOffset);
219 if (!this->applyCropRect(&bounds, ctm)) {
223 displ.getBounds(&displBounds);
224 displBounds.offset(displOffset);
225 if (!this->applyCropRect(&displBounds, ctm)) {
228 if (!bounds.intersect(displBounds)) {
232 dst->setConfig(color.config(), bounds.width(), bounds.height());
233 if (!dst->allocPixels()) {
237 SkVector scale = SkVector::Make(fScale, fScale);
238 ctm.mapVectors(&scale, 1);
239 SkIRect colorBounds = bounds;
240 colorBounds.offset(-colorOffset);
242 computeDisplacement(fXChannelSelector, fYChannelSelector, scale, dst,
243 &displ, colorOffset - displOffset, &color, colorBounds);
245 offset->fX = bounds.left();
246 offset->fY = bounds.top();
250 void SkDisplacementMapEffect::computeFastBounds(const SkRect& src, SkRect* dst) const {
251 if (getColorInput()) {
252 getColorInput()->computeFastBounds(src, dst);
258 bool SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
259 SkIRect* dst) const {
260 if (getColorInput()) {
261 return getColorInput()->filterBounds(src, ctm, dst);
267 ///////////////////////////////////////////////////////////////////////////////
270 class GrGLDisplacementMapEffect : public GrGLEffect {
272 GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
273 const GrDrawEffect& drawEffect);
274 virtual ~GrGLDisplacementMapEffect();
276 virtual void emitCode(GrGLShaderBuilder*,
279 const char* outputColor,
280 const char* inputColor,
281 const TransformedCoordsArray&,
282 const TextureSamplerArray&) SK_OVERRIDE;
284 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
286 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
289 SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
290 SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
291 GrGLUniformManager::UniformHandle fScaleUni;
293 typedef GrGLEffect INHERITED;
296 ///////////////////////////////////////////////////////////////////////////////
298 class GrDisplacementMapEffect : public GrEffect {
300 static GrEffectRef* Create(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
301 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
303 GrTexture* displacement, const SkMatrix& offsetMatrix,
305 AutoEffectUnref effect(SkNEW_ARGS(GrDisplacementMapEffect, (xChannelSelector,
311 return CreateEffectRef(effect);
314 virtual ~GrDisplacementMapEffect();
316 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
317 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const
318 { return fXChannelSelector; }
319 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const
320 { return fYChannelSelector; }
321 const SkVector& scale() const { return fScale; }
323 typedef GrGLDisplacementMapEffect GLEffect;
324 static const char* Name() { return "DisplacementMap"; }
326 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
329 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
331 GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
332 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
333 const SkVector& scale,
334 GrTexture* displacement, const SkMatrix& offsetMatrix,
337 GR_DECLARE_EFFECT_TEST;
339 GrCoordTransform fDisplacementTransform;
340 GrTextureAccess fDisplacementAccess;
341 GrCoordTransform fColorTransform;
342 GrTextureAccess fColorAccess;
343 SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
344 SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
347 typedef GrEffect INHERITED;
350 bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
351 SkBitmap* result, SkIPoint* offset) const {
353 SkIPoint colorOffset = SkIPoint::Make(0, 0);
354 if (!SkImageFilterUtils::GetInputResultGPU(getColorInput(), proxy, src, ctm, &colorBM,
358 GrTexture* color = colorBM.getTexture();
359 SkBitmap displacementBM;
360 SkIPoint displacementOffset = SkIPoint::Make(0, 0);
361 if (!SkImageFilterUtils::GetInputResultGPU(getDisplacementInput(), proxy, src, ctm,
362 &displacementBM, &displacementOffset)) {
365 GrTexture* displacement = displacementBM.getTexture();
366 GrContext* context = color->getContext();
369 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
370 desc.fWidth = colorBM.width();
371 desc.fHeight = colorBM.height();
372 desc.fConfig = kSkia8888_GrPixelConfig;
374 GrAutoScratchTexture ast(context, desc);
375 SkAutoTUnref<GrTexture> dst(ast.detach());
377 GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
379 SkVector scale = SkVector::Make(fScale, fScale);
380 ctm.mapVectors(&scale, 1);
382 colorBM.getBounds(&bounds);
383 bounds.offset(colorOffset);
384 if (!this->applyCropRect(&bounds, ctm)) {
388 displacementBM.getBounds(&displBounds);
389 displBounds.offset(displacementOffset);
390 if (!this->applyCropRect(&displBounds, ctm)) {
393 if (!bounds.intersect(displBounds)) {
398 SkMatrix offsetMatrix = GrEffect::MakeDivByTextureWHMatrix(displacement);
399 offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displacementOffset.fX),
400 SkIntToScalar(colorOffset.fY - displacementOffset.fY));
402 paint.addColorEffect(
403 GrDisplacementMapEffect::Create(fXChannelSelector,
409 SkIRect colorBounds = bounds;
410 colorBounds.offset(-colorOffset);
412 matrix.setTranslate(-SkIntToScalar(colorBounds.x()),
413 -SkIntToScalar(colorBounds.y()));
414 context->concatMatrix(matrix);
415 context->drawRect(paint, SkRect::Make(colorBounds));
416 offset->fX = bounds.left();
417 offset->fY = bounds.top();
418 return SkImageFilterUtils::WrapTexture(dst, bounds.width(), bounds.height(), result);
421 ///////////////////////////////////////////////////////////////////////////////
423 GrDisplacementMapEffect::GrDisplacementMapEffect(
424 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
425 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
426 const SkVector& scale,
427 GrTexture* displacement,
428 const SkMatrix& offsetMatrix,
430 : fDisplacementTransform(kLocal_GrCoordSet, offsetMatrix, displacement)
431 , fDisplacementAccess(displacement)
432 , fColorTransform(kLocal_GrCoordSet, color)
433 , fColorAccess(color)
434 , fXChannelSelector(xChannelSelector)
435 , fYChannelSelector(yChannelSelector)
437 this->addCoordTransform(&fDisplacementTransform);
438 this->addTextureAccess(&fDisplacementAccess);
439 this->addCoordTransform(&fColorTransform);
440 this->addTextureAccess(&fColorAccess);
441 this->setWillNotUseInputColor();
444 GrDisplacementMapEffect::~GrDisplacementMapEffect() {
447 bool GrDisplacementMapEffect::onIsEqual(const GrEffect& sBase) const {
448 const GrDisplacementMapEffect& s = CastEffect<GrDisplacementMapEffect>(sBase);
449 return fDisplacementAccess.getTexture() == s.fDisplacementAccess.getTexture() &&
450 fColorAccess.getTexture() == s.fColorAccess.getTexture() &&
451 fXChannelSelector == s.fXChannelSelector &&
452 fYChannelSelector == s.fYChannelSelector &&
456 const GrBackendEffectFactory& GrDisplacementMapEffect::getFactory() const {
457 return GrTBackendEffectFactory<GrDisplacementMapEffect>::getInstance();
460 void GrDisplacementMapEffect::getConstantColorComponents(GrColor*,
461 uint32_t* validFlags) const {
462 // Any displacement offset bringing a pixel out of bounds will output a color of (0,0,0,0),
463 // so the only way we'd get a constant alpha is if the input color image has a constant alpha
464 // and no displacement offset push any texture coordinates out of bounds OR if the constant
465 // alpha is 0. Since this isn't trivial to compute at this point, let's assume the output is
466 // not of constant color when a displacement effect is applied.
470 ///////////////////////////////////////////////////////////////////////////////
472 GR_DEFINE_EFFECT_TEST(GrDisplacementMapEffect);
474 GrEffectRef* GrDisplacementMapEffect::TestCreate(SkRandom* random,
476 const GrDrawTargetCaps&,
477 GrTexture* textures[]) {
478 int texIdxDispl = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
479 GrEffectUnitTest::kAlphaTextureIdx;
480 int texIdxColor = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
481 GrEffectUnitTest::kAlphaTextureIdx;
482 static const int kMaxComponent = 4;
483 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector =
484 static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
485 random->nextRangeU(1, kMaxComponent));
486 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector =
487 static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
488 random->nextRangeU(1, kMaxComponent));
489 SkVector scale = SkVector::Make(random->nextRangeScalar(0, 100.0f),
490 random->nextRangeScalar(0, 100.0f));
492 return GrDisplacementMapEffect::Create(xChannelSelector, yChannelSelector, scale,
493 textures[texIdxDispl], SkMatrix::I(),
494 textures[texIdxColor]);
497 ///////////////////////////////////////////////////////////////////////////////
499 GrGLDisplacementMapEffect::GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
500 const GrDrawEffect& drawEffect)
502 , fXChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().xChannelSelector())
503 , fYChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().yChannelSelector()) {
506 GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() {
509 void GrGLDisplacementMapEffect::emitCode(GrGLShaderBuilder* builder,
512 const char* outputColor,
513 const char* inputColor,
514 const TransformedCoordsArray& coords,
515 const TextureSamplerArray& samplers) {
516 sk_ignore_unused_variable(inputColor);
518 fScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
519 kVec2f_GrSLType, "Scale");
520 const char* scaleUni = builder->getUniformCStr(fScaleUni);
521 const char* dColor = "dColor";
522 const char* cCoords = "cCoords";
523 const char* outOfBounds = "outOfBounds";
524 const char* nearZero = "1e-6"; // Since 6.10352e−5 is the smallest half float, use
525 // a number smaller than that to approximate 0, but
526 // leave room for 32-bit float GPU rounding errors.
528 builder->fsCodeAppendf("\t\tvec4 %s = ", dColor);
529 builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
530 builder->fsCodeAppend(";\n");
532 // Unpremultiply the displacement
533 builder->fsCodeAppendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
534 dColor, dColor, nearZero, dColor, dColor);
536 builder->fsCodeAppendf("\t\tvec2 %s = %s + %s*(%s.",
537 cCoords, coords[1].c_str(), scaleUni, dColor);
539 switch (fXChannelSelector) {
540 case SkDisplacementMapEffect::kR_ChannelSelectorType:
541 builder->fsCodeAppend("r");
543 case SkDisplacementMapEffect::kG_ChannelSelectorType:
544 builder->fsCodeAppend("g");
546 case SkDisplacementMapEffect::kB_ChannelSelectorType:
547 builder->fsCodeAppend("b");
549 case SkDisplacementMapEffect::kA_ChannelSelectorType:
550 builder->fsCodeAppend("a");
552 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
554 SkDEBUGFAIL("Unknown X channel selector");
557 switch (fYChannelSelector) {
558 case SkDisplacementMapEffect::kR_ChannelSelectorType:
559 builder->fsCodeAppend("r");
561 case SkDisplacementMapEffect::kG_ChannelSelectorType:
562 builder->fsCodeAppend("g");
564 case SkDisplacementMapEffect::kB_ChannelSelectorType:
565 builder->fsCodeAppend("b");
567 case SkDisplacementMapEffect::kA_ChannelSelectorType:
568 builder->fsCodeAppend("a");
570 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
572 SkDEBUGFAIL("Unknown Y channel selector");
574 builder->fsCodeAppend("-vec2(0.5));\t\t");
576 // FIXME : This can be achieved with a "clamp to border" texture repeat mode and
577 // a 0 border color instead of computing if cCoords is out of bounds here.
578 builder->fsCodeAppendf(
579 "bool %s = (%s.x < 0.0) || (%s.y < 0.0) || (%s.x > 1.0) || (%s.y > 1.0);\t\t",
580 outOfBounds, cCoords, cCoords, cCoords, cCoords);
581 builder->fsCodeAppendf("%s = %s ? vec4(0.0) : ", outputColor, outOfBounds);
582 builder->fsAppendTextureLookup(samplers[1], cCoords, coords[1].type());
583 builder->fsCodeAppend(";\n");
586 void GrGLDisplacementMapEffect::setData(const GrGLUniformManager& uman,
587 const GrDrawEffect& drawEffect) {
588 const GrDisplacementMapEffect& displacementMap =
589 drawEffect.castEffect<GrDisplacementMapEffect>();
590 GrTexture* colorTex = displacementMap.texture(1);
591 SkScalar scaleX = SkScalarDiv(displacementMap.scale().fX, SkIntToScalar(colorTex->width()));
592 SkScalar scaleY = SkScalarDiv(displacementMap.scale().fY, SkIntToScalar(colorTex->height()));
593 uman.set2f(fScaleUni, SkScalarToFloat(scaleX),
594 colorTex->origin() == kTopLeft_GrSurfaceOrigin ?
595 SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY));
598 GrGLEffect::EffectKey GrGLDisplacementMapEffect::GenKey(const GrDrawEffect& drawEffect,
600 const GrDisplacementMapEffect& displacementMap =
601 drawEffect.castEffect<GrDisplacementMapEffect>();
603 EffectKey xKey = displacementMap.xChannelSelector();
604 EffectKey yKey = displacementMap.yChannelSelector() << SkDisplacementMapEffect::kKeyBits;