Home | History | Annotate | Download | only in effects
      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 #include "SkReadBuffer.h"
     10 #include "SkWriteBuffer.h"
     11 #include "SkUnPreMultiply.h"
     12 #include "SkColorPriv.h"
     13 #if SK_SUPPORT_GPU
     14 #include "GrContext.h"
     15 #include "GrCoordTransform.h"
     16 #include "gl/GrGLEffect.h"
     17 #include "GrTBackendEffectFactory.h"
     18 #endif
     19 
     20 namespace {
     21 
     22 #define kChannelSelectorKeyBits 3; // Max value is 4, so 3 bits are required at most
     23 
     24 template<SkDisplacementMapEffect::ChannelSelectorType type>
     25 uint32_t getValue(SkColor, const SkUnPreMultiply::Scale*) {
     26     SkDEBUGFAIL("Unknown channel selector");
     27     return 0;
     28 }
     29 
     30 template<> uint32_t getValue<SkDisplacementMapEffect::kR_ChannelSelectorType>(
     31     SkColor l, const SkUnPreMultiply::Scale* table) {
     32     return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedR32(l));
     33 }
     34 
     35 template<> uint32_t getValue<SkDisplacementMapEffect::kG_ChannelSelectorType>(
     36     SkColor l, const SkUnPreMultiply::Scale* table) {
     37     return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedG32(l));
     38 }
     39 
     40 template<> uint32_t getValue<SkDisplacementMapEffect::kB_ChannelSelectorType>(
     41     SkColor l, const SkUnPreMultiply::Scale* table) {
     42     return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedB32(l));
     43 }
     44 
     45 template<> uint32_t getValue<SkDisplacementMapEffect::kA_ChannelSelectorType>(
     46     SkColor l, const SkUnPreMultiply::Scale*) {
     47     return SkGetPackedA32(l);
     48 }
     49 
     50 template<SkDisplacementMapEffect::ChannelSelectorType typeX,
     51          SkDisplacementMapEffect::ChannelSelectorType typeY>
     52 void computeDisplacement(const SkVector& scale, SkBitmap* dst,
     53                          SkBitmap* displ, const SkIPoint& offset,
     54                          SkBitmap* src,
     55                          const SkIRect& bounds)
     56 {
     57     static const SkScalar Inv8bit = SkScalarDiv(SK_Scalar1, 255.0f);
     58     const int srcW = src->width();
     59     const int srcH = src->height();
     60     const SkVector scaleForColor = SkVector::Make(SkScalarMul(scale.fX, Inv8bit),
     61                                                   SkScalarMul(scale.fY, Inv8bit));
     62     const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - SkScalarMul(scale.fX, SK_ScalarHalf),
     63                                              SK_ScalarHalf - SkScalarMul(scale.fY, SK_ScalarHalf));
     64     const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
     65     SkPMColor* dstPtr = dst->getAddr32(0, 0);
     66     for (int y = bounds.top(); y < bounds.bottom(); ++y) {
     67         const SkPMColor* displPtr = displ->getAddr32(bounds.left() + offset.fX,
     68                                                      y + offset.fY);
     69         for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) {
     70             const SkScalar displX = SkScalarMul(scaleForColor.fX,
     71                 SkIntToScalar(getValue<typeX>(*displPtr, table))) + scaleAdj.fX;
     72             const SkScalar displY = SkScalarMul(scaleForColor.fY,
     73                 SkIntToScalar(getValue<typeY>(*displPtr, table))) + scaleAdj.fY;
     74             // Truncate the displacement values
     75             const int srcX = x + SkScalarTruncToInt(displX);
     76             const int srcY = y + SkScalarTruncToInt(displY);
     77             *dstPtr++ = ((srcX < 0) || (srcX >= srcW) || (srcY < 0) || (srcY >= srcH)) ?
     78                       0 : *(src->getAddr32(srcX, srcY));
     79         }
     80     }
     81 }
     82 
     83 template<SkDisplacementMapEffect::ChannelSelectorType typeX>
     84 void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
     85                          const SkVector& scale, SkBitmap* dst,
     86                          SkBitmap* displ, const SkIPoint& offset,
     87                          SkBitmap* src,
     88                          const SkIRect& bounds)
     89 {
     90     switch (yChannelSelector) {
     91       case SkDisplacementMapEffect::kR_ChannelSelectorType:
     92         computeDisplacement<typeX, SkDisplacementMapEffect::kR_ChannelSelectorType>(
     93             scale, dst, displ, offset, src, bounds);
     94         break;
     95       case SkDisplacementMapEffect::kG_ChannelSelectorType:
     96         computeDisplacement<typeX, SkDisplacementMapEffect::kG_ChannelSelectorType>(
     97             scale, dst, displ, offset, src, bounds);
     98         break;
     99       case SkDisplacementMapEffect::kB_ChannelSelectorType:
    100         computeDisplacement<typeX, SkDisplacementMapEffect::kB_ChannelSelectorType>(
    101             scale, dst, displ, offset, src, bounds);
    102         break;
    103       case SkDisplacementMapEffect::kA_ChannelSelectorType:
    104         computeDisplacement<typeX, SkDisplacementMapEffect::kA_ChannelSelectorType>(
    105             scale, dst, displ, offset, src, bounds);
    106         break;
    107       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
    108       default:
    109         SkDEBUGFAIL("Unknown Y channel selector");
    110     }
    111 }
    112 
    113 void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
    114                          SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
    115                          const SkVector& scale, SkBitmap* dst,
    116                          SkBitmap* displ, const SkIPoint& offset,
    117                          SkBitmap* src,
    118                          const SkIRect& bounds)
    119 {
    120     switch (xChannelSelector) {
    121       case SkDisplacementMapEffect::kR_ChannelSelectorType:
    122         computeDisplacement<SkDisplacementMapEffect::kR_ChannelSelectorType>(
    123             yChannelSelector, scale, dst, displ, offset, src, bounds);
    124         break;
    125       case SkDisplacementMapEffect::kG_ChannelSelectorType:
    126         computeDisplacement<SkDisplacementMapEffect::kG_ChannelSelectorType>(
    127             yChannelSelector, scale, dst, displ, offset, src, bounds);
    128         break;
    129       case SkDisplacementMapEffect::kB_ChannelSelectorType:
    130         computeDisplacement<SkDisplacementMapEffect::kB_ChannelSelectorType>(
    131             yChannelSelector, scale, dst, displ, offset, src, bounds);
    132         break;
    133       case SkDisplacementMapEffect::kA_ChannelSelectorType:
    134         computeDisplacement<SkDisplacementMapEffect::kA_ChannelSelectorType>(
    135             yChannelSelector, scale, dst, displ, offset, src, bounds);
    136         break;
    137       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
    138       default:
    139         SkDEBUGFAIL("Unknown X channel selector");
    140     }
    141 }
    142 
    143 bool channel_selector_type_is_valid(SkDisplacementMapEffect::ChannelSelectorType cst) {
    144     switch (cst) {
    145     case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
    146     case SkDisplacementMapEffect::kR_ChannelSelectorType:
    147     case SkDisplacementMapEffect::kG_ChannelSelectorType:
    148     case SkDisplacementMapEffect::kB_ChannelSelectorType:
    149     case SkDisplacementMapEffect::kA_ChannelSelectorType:
    150         return true;
    151     default:
    152         break;
    153     }
    154     return false;
    155 }
    156 
    157 } // end namespace
    158 
    159 ///////////////////////////////////////////////////////////////////////////////
    160 
    161 SkDisplacementMapEffect::SkDisplacementMapEffect(ChannelSelectorType xChannelSelector,
    162                                                  ChannelSelectorType yChannelSelector,
    163                                                  SkScalar scale,
    164                                                  SkImageFilter* displacement,
    165                                                  SkImageFilter* color,
    166                                                  const CropRect* cropRect)
    167   : INHERITED(displacement, color, cropRect)
    168   , fXChannelSelector(xChannelSelector)
    169   , fYChannelSelector(yChannelSelector)
    170   , fScale(scale)
    171 {
    172 }
    173 
    174 SkDisplacementMapEffect::~SkDisplacementMapEffect() {
    175 }
    176 
    177 SkDisplacementMapEffect::SkDisplacementMapEffect(SkReadBuffer& buffer)
    178   : INHERITED(2, buffer)
    179 {
    180     fXChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt();
    181     fYChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt();
    182     fScale            = buffer.readScalar();
    183     buffer.validate(channel_selector_type_is_valid(fXChannelSelector) &&
    184                     channel_selector_type_is_valid(fYChannelSelector) &&
    185                     SkScalarIsFinite(fScale));
    186 }
    187 
    188 void SkDisplacementMapEffect::flatten(SkWriteBuffer& buffer) const {
    189     this->INHERITED::flatten(buffer);
    190     buffer.writeInt((int) fXChannelSelector);
    191     buffer.writeInt((int) fYChannelSelector);
    192     buffer.writeScalar(fScale);
    193 }
    194 
    195 bool SkDisplacementMapEffect::onFilterImage(Proxy* proxy,
    196                                             const SkBitmap& src,
    197                                             const Context& ctx,
    198                                             SkBitmap* dst,
    199                                             SkIPoint* offset) const {
    200     SkBitmap displ = src, color = src;
    201     const SkImageFilter* colorInput = getColorInput();
    202     const SkImageFilter* displInput = getDisplacementInput();
    203     SkIPoint colorOffset = SkIPoint::Make(0, 0), displOffset = SkIPoint::Make(0, 0);
    204     if ((colorInput && !colorInput->filterImage(proxy, src, ctx, &color, &colorOffset)) ||
    205         (displInput && !displInput->filterImage(proxy, src, ctx, &displ, &displOffset))) {
    206         return false;
    207     }
    208     if ((displ.colorType() != kN32_SkColorType) ||
    209         (color.colorType() != kN32_SkColorType)) {
    210         return false;
    211     }
    212     SkIRect bounds;
    213     // Since computeDisplacement does bounds checking on color pixel access, we don't need to pad
    214     // the color bitmap to bounds here.
    215     if (!this->applyCropRect(ctx, color, colorOffset, &bounds)) {
    216         return false;
    217     }
    218     SkIRect displBounds;
    219     if (!this->applyCropRect(ctx, proxy, displ, &displOffset, &displBounds, &displ)) {
    220         return false;
    221     }
    222     if (!bounds.intersect(displBounds)) {
    223         return false;
    224     }
    225     SkAutoLockPixels alp_displacement(displ), alp_color(color);
    226     if (!displ.getPixels() || !color.getPixels()) {
    227         return false;
    228     }
    229 
    230     if (!dst->allocPixels(color.info().makeWH(bounds.width(), bounds.height()))) {
    231         return false;
    232     }
    233 
    234     SkVector scale = SkVector::Make(fScale, fScale);
    235     ctx.ctm().mapVectors(&scale, 1);
    236     SkIRect colorBounds = bounds;
    237     colorBounds.offset(-colorOffset);
    238 
    239     computeDisplacement(fXChannelSelector, fYChannelSelector, scale, dst,
    240                         &displ, colorOffset - displOffset, &color, colorBounds);
    241 
    242     offset->fX = bounds.left();
    243     offset->fY = bounds.top();
    244     return true;
    245 }
    246 
    247 void SkDisplacementMapEffect::computeFastBounds(const SkRect& src, SkRect* dst) const {
    248     if (getColorInput()) {
    249         getColorInput()->computeFastBounds(src, dst);
    250     } else {
    251         *dst = src;
    252     }
    253     dst->outset(fScale * SK_ScalarHalf, fScale * SK_ScalarHalf);
    254 }
    255 
    256 bool SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
    257                                    SkIRect* dst) const {
    258     SkIRect bounds = src;
    259     SkVector scale = SkVector::Make(fScale, fScale);
    260     ctm.mapVectors(&scale, 1);
    261     bounds.outset(SkScalarCeilToInt(scale.fX * SK_ScalarHalf),
    262                   SkScalarCeilToInt(scale.fY * SK_ScalarHalf));
    263     if (getColorInput()) {
    264         return getColorInput()->filterBounds(bounds, ctm, dst);
    265     }
    266     *dst = bounds;
    267     return true;
    268 }
    269 
    270 ///////////////////////////////////////////////////////////////////////////////
    271 
    272 #if SK_SUPPORT_GPU
    273 class GrGLDisplacementMapEffect : public GrGLEffect {
    274 public:
    275     GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
    276                               const GrDrawEffect& drawEffect);
    277     virtual ~GrGLDisplacementMapEffect();
    278 
    279     virtual void emitCode(GrGLShaderBuilder*,
    280                           const GrDrawEffect&,
    281                           EffectKey,
    282                           const char* outputColor,
    283                           const char* inputColor,
    284                           const TransformedCoordsArray&,
    285                           const TextureSamplerArray&) SK_OVERRIDE;
    286 
    287     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
    288 
    289     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
    290 
    291 private:
    292     SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
    293     SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
    294     GrGLUniformManager::UniformHandle fScaleUni;
    295 
    296     typedef GrGLEffect INHERITED;
    297 };
    298 
    299 ///////////////////////////////////////////////////////////////////////////////
    300 
    301 class GrDisplacementMapEffect : public GrEffect {
    302 public:
    303     static GrEffectRef* Create(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
    304                                SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
    305                                SkVector scale,
    306                                GrTexture* displacement, const SkMatrix& offsetMatrix,
    307                                GrTexture* color) {
    308         AutoEffectUnref effect(SkNEW_ARGS(GrDisplacementMapEffect, (xChannelSelector,
    309                                                                     yChannelSelector,
    310                                                                     scale,
    311                                                                     displacement,
    312                                                                     offsetMatrix,
    313                                                                     color)));
    314         return CreateEffectRef(effect);
    315     }
    316 
    317     virtual ~GrDisplacementMapEffect();
    318 
    319     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
    320     SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const
    321         { return fXChannelSelector; }
    322     SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const
    323         { return fYChannelSelector; }
    324     const SkVector& scale() const { return fScale; }
    325 
    326     typedef GrGLDisplacementMapEffect GLEffect;
    327     static const char* Name() { return "DisplacementMap"; }
    328 
    329     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
    330 
    331 private:
    332     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
    333 
    334     GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
    335                             SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
    336                             const SkVector& scale,
    337                             GrTexture* displacement, const SkMatrix& offsetMatrix,
    338                             GrTexture* color);
    339 
    340     GR_DECLARE_EFFECT_TEST;
    341 
    342     GrCoordTransform            fDisplacementTransform;
    343     GrTextureAccess             fDisplacementAccess;
    344     GrCoordTransform            fColorTransform;
    345     GrTextureAccess             fColorAccess;
    346     SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
    347     SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
    348     SkVector fScale;
    349 
    350     typedef GrEffect INHERITED;
    351 };
    352 
    353 bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
    354                                              SkBitmap* result, SkIPoint* offset) const {
    355     SkBitmap colorBM = src;
    356     SkIPoint colorOffset = SkIPoint::Make(0, 0);
    357     if (getColorInput() && !getColorInput()->getInputResultGPU(proxy, src, ctx, &colorBM,
    358                                                                &colorOffset)) {
    359         return false;
    360     }
    361     SkBitmap displacementBM = src;
    362     SkIPoint displacementOffset = SkIPoint::Make(0, 0);
    363     if (getDisplacementInput() &&
    364         !getDisplacementInput()->getInputResultGPU(proxy, src, ctx, &displacementBM,
    365                                                    &displacementOffset)) {
    366         return false;
    367     }
    368     SkIRect bounds;
    369     // Since GrDisplacementMapEffect does bounds checking on color pixel access, we don't need to
    370     // pad the color bitmap to bounds here.
    371     if (!this->applyCropRect(ctx, colorBM, colorOffset, &bounds)) {
    372         return false;
    373     }
    374     SkIRect displBounds;
    375     if (!this->applyCropRect(ctx, proxy, displacementBM,
    376                              &displacementOffset, &displBounds, &displacementBM)) {
    377         return false;
    378     }
    379     if (!bounds.intersect(displBounds)) {
    380         return false;
    381     }
    382     GrTexture* color = colorBM.getTexture();
    383     GrTexture* displacement = displacementBM.getTexture();
    384     GrContext* context = color->getContext();
    385 
    386     GrTextureDesc desc;
    387     desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
    388     desc.fWidth = bounds.width();
    389     desc.fHeight = bounds.height();
    390     desc.fConfig = kSkia8888_GrPixelConfig;
    391 
    392     GrAutoScratchTexture ast(context, desc);
    393     SkAutoTUnref<GrTexture> dst(ast.detach());
    394 
    395     GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
    396 
    397     SkVector scale = SkVector::Make(fScale, fScale);
    398     ctx.ctm().mapVectors(&scale, 1);
    399 
    400     GrPaint paint;
    401     SkMatrix offsetMatrix = GrEffect::MakeDivByTextureWHMatrix(displacement);
    402     offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displacementOffset.fX),
    403                               SkIntToScalar(colorOffset.fY - displacementOffset.fY));
    404 
    405     paint.addColorEffect(
    406         GrDisplacementMapEffect::Create(fXChannelSelector,
    407                                         fYChannelSelector,
    408                                         scale,
    409                                         displacement,
    410                                         offsetMatrix,
    411                                         color))->unref();
    412     SkIRect colorBounds = bounds;
    413     colorBounds.offset(-colorOffset);
    414     GrContext::AutoMatrix am;
    415     am.setIdentity(context);
    416     SkMatrix matrix;
    417     matrix.setTranslate(-SkIntToScalar(colorBounds.x()),
    418                         -SkIntToScalar(colorBounds.y()));
    419     context->concatMatrix(matrix);
    420     context->drawRect(paint, SkRect::Make(colorBounds));
    421     offset->fX = bounds.left();
    422     offset->fY = bounds.top();
    423     WrapTexture(dst, bounds.width(), bounds.height(), result);
    424     return true;
    425 }
    426 
    427 ///////////////////////////////////////////////////////////////////////////////
    428 
    429 GrDisplacementMapEffect::GrDisplacementMapEffect(
    430                              SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
    431                              SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
    432                              const SkVector& scale,
    433                              GrTexture* displacement,
    434                              const SkMatrix& offsetMatrix,
    435                              GrTexture* color)
    436     : fDisplacementTransform(kLocal_GrCoordSet, offsetMatrix, displacement)
    437     , fDisplacementAccess(displacement)
    438     , fColorTransform(kLocal_GrCoordSet, color)
    439     , fColorAccess(color)
    440     , fXChannelSelector(xChannelSelector)
    441     , fYChannelSelector(yChannelSelector)
    442     , fScale(scale) {
    443     this->addCoordTransform(&fDisplacementTransform);
    444     this->addTextureAccess(&fDisplacementAccess);
    445     this->addCoordTransform(&fColorTransform);
    446     this->addTextureAccess(&fColorAccess);
    447     this->setWillNotUseInputColor();
    448 }
    449 
    450 GrDisplacementMapEffect::~GrDisplacementMapEffect() {
    451 }
    452 
    453 bool GrDisplacementMapEffect::onIsEqual(const GrEffect& sBase) const {
    454     const GrDisplacementMapEffect& s = CastEffect<GrDisplacementMapEffect>(sBase);
    455     return fDisplacementAccess.getTexture() == s.fDisplacementAccess.getTexture() &&
    456            fColorAccess.getTexture() == s.fColorAccess.getTexture() &&
    457            fXChannelSelector == s.fXChannelSelector &&
    458            fYChannelSelector == s.fYChannelSelector &&
    459            fScale == s.fScale;
    460 }
    461 
    462 const GrBackendEffectFactory& GrDisplacementMapEffect::getFactory() const {
    463     return GrTBackendEffectFactory<GrDisplacementMapEffect>::getInstance();
    464 }
    465 
    466 void GrDisplacementMapEffect::getConstantColorComponents(GrColor*,
    467                                                          uint32_t* validFlags) const {
    468     // Any displacement offset bringing a pixel out of bounds will output a color of (0,0,0,0),
    469     // so the only way we'd get a constant alpha is if the input color image has a constant alpha
    470     // and no displacement offset push any texture coordinates out of bounds OR if the constant
    471     // alpha is 0. Since this isn't trivial to compute at this point, let's assume the output is
    472     // not of constant color when a displacement effect is applied.
    473     *validFlags = 0;
    474 }
    475 
    476 ///////////////////////////////////////////////////////////////////////////////
    477 
    478 GR_DEFINE_EFFECT_TEST(GrDisplacementMapEffect);
    479 
    480 GrEffectRef* GrDisplacementMapEffect::TestCreate(SkRandom* random,
    481                                                  GrContext*,
    482                                                  const GrDrawTargetCaps&,
    483                                                  GrTexture* textures[]) {
    484     int texIdxDispl = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
    485                                            GrEffectUnitTest::kAlphaTextureIdx;
    486     int texIdxColor = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
    487                                            GrEffectUnitTest::kAlphaTextureIdx;
    488     static const int kMaxComponent = 4;
    489     SkDisplacementMapEffect::ChannelSelectorType xChannelSelector =
    490         static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
    491         random->nextRangeU(1, kMaxComponent));
    492     SkDisplacementMapEffect::ChannelSelectorType yChannelSelector =
    493         static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
    494         random->nextRangeU(1, kMaxComponent));
    495     SkVector scale = SkVector::Make(random->nextRangeScalar(0, 100.0f),
    496                                     random->nextRangeScalar(0, 100.0f));
    497 
    498     return GrDisplacementMapEffect::Create(xChannelSelector, yChannelSelector, scale,
    499                                            textures[texIdxDispl], SkMatrix::I(),
    500                                            textures[texIdxColor]);
    501 }
    502 
    503 ///////////////////////////////////////////////////////////////////////////////
    504 
    505 GrGLDisplacementMapEffect::GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
    506                                                      const GrDrawEffect& drawEffect)
    507     : INHERITED(factory)
    508     , fXChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().xChannelSelector())
    509     , fYChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().yChannelSelector()) {
    510 }
    511 
    512 GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() {
    513 }
    514 
    515 void GrGLDisplacementMapEffect::emitCode(GrGLShaderBuilder* builder,
    516                                          const GrDrawEffect&,
    517                                          EffectKey key,
    518                                          const char* outputColor,
    519                                          const char* inputColor,
    520                                          const TransformedCoordsArray& coords,
    521                                          const TextureSamplerArray& samplers) {
    522     sk_ignore_unused_variable(inputColor);
    523 
    524     fScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
    525                                     kVec2f_GrSLType, "Scale");
    526     const char* scaleUni = builder->getUniformCStr(fScaleUni);
    527     const char* dColor = "dColor";
    528     const char* cCoords = "cCoords";
    529     const char* outOfBounds = "outOfBounds";
    530     const char* nearZero = "1e-6"; // Since 6.10352e5 is the smallest half float, use
    531                                    // a number smaller than that to approximate 0, but
    532                                    // leave room for 32-bit float GPU rounding errors.
    533 
    534     builder->fsCodeAppendf("\t\tvec4 %s = ", dColor);
    535     builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
    536     builder->fsCodeAppend(";\n");
    537 
    538     // Unpremultiply the displacement
    539     builder->fsCodeAppendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
    540                            dColor, dColor, nearZero, dColor, dColor);
    541 
    542     builder->fsCodeAppendf("\t\tvec2 %s = %s + %s*(%s.",
    543                            cCoords, coords[1].c_str(), scaleUni, dColor);
    544 
    545     switch (fXChannelSelector) {
    546       case SkDisplacementMapEffect::kR_ChannelSelectorType:
    547         builder->fsCodeAppend("r");
    548         break;
    549       case SkDisplacementMapEffect::kG_ChannelSelectorType:
    550         builder->fsCodeAppend("g");
    551         break;
    552       case SkDisplacementMapEffect::kB_ChannelSelectorType:
    553         builder->fsCodeAppend("b");
    554         break;
    555       case SkDisplacementMapEffect::kA_ChannelSelectorType:
    556         builder->fsCodeAppend("a");
    557         break;
    558       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
    559       default:
    560         SkDEBUGFAIL("Unknown X channel selector");
    561     }
    562 
    563     switch (fYChannelSelector) {
    564       case SkDisplacementMapEffect::kR_ChannelSelectorType:
    565         builder->fsCodeAppend("r");
    566         break;
    567       case SkDisplacementMapEffect::kG_ChannelSelectorType:
    568         builder->fsCodeAppend("g");
    569         break;
    570       case SkDisplacementMapEffect::kB_ChannelSelectorType:
    571         builder->fsCodeAppend("b");
    572         break;
    573       case SkDisplacementMapEffect::kA_ChannelSelectorType:
    574         builder->fsCodeAppend("a");
    575         break;
    576       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
    577       default:
    578         SkDEBUGFAIL("Unknown Y channel selector");
    579     }
    580     builder->fsCodeAppend("-vec2(0.5));\t\t");
    581 
    582     // FIXME : This can be achieved with a "clamp to border" texture repeat mode and
    583     //         a 0 border color instead of computing if cCoords is out of bounds here.
    584     builder->fsCodeAppendf(
    585         "bool %s = (%s.x < 0.0) || (%s.y < 0.0) || (%s.x > 1.0) || (%s.y > 1.0);\t\t",
    586         outOfBounds, cCoords, cCoords, cCoords, cCoords);
    587     builder->fsCodeAppendf("%s = %s ? vec4(0.0) : ", outputColor, outOfBounds);
    588     builder->fsAppendTextureLookup(samplers[1], cCoords, coords[1].type());
    589     builder->fsCodeAppend(";\n");
    590 }
    591 
    592 void GrGLDisplacementMapEffect::setData(const GrGLUniformManager& uman,
    593                                         const GrDrawEffect& drawEffect) {
    594     const GrDisplacementMapEffect& displacementMap =
    595         drawEffect.castEffect<GrDisplacementMapEffect>();
    596     GrTexture* colorTex = displacementMap.texture(1);
    597     SkScalar scaleX = SkScalarDiv(displacementMap.scale().fX, SkIntToScalar(colorTex->width()));
    598     SkScalar scaleY = SkScalarDiv(displacementMap.scale().fY, SkIntToScalar(colorTex->height()));
    599     uman.set2f(fScaleUni, SkScalarToFloat(scaleX),
    600                colorTex->origin() == kTopLeft_GrSurfaceOrigin ?
    601                SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY));
    602 }
    603 
    604 GrGLEffect::EffectKey GrGLDisplacementMapEffect::GenKey(const GrDrawEffect& drawEffect,
    605                                                         const GrGLCaps&) {
    606     const GrDisplacementMapEffect& displacementMap =
    607         drawEffect.castEffect<GrDisplacementMapEffect>();
    608 
    609     EffectKey xKey = displacementMap.xChannelSelector();
    610     EffectKey yKey = displacementMap.yChannelSelector() << kChannelSelectorKeyBits;
    611 
    612     return xKey | yKey;
    613 }
    614 #endif
    615