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 "SkFlattenableBuffers.h"
10#include "SkUnPreMultiply.h"
11#include "SkColorPriv.h"
12#if SK_SUPPORT_GPU
13#include "GrContext.h"
14#include "gl/GrGLEffect.h"
15#include "gl/GrGLEffectMatrix.h"
16#include "GrTBackendEffectFactory.h"
17#include "SkImageFilterUtils.h"
18#endif
19
20namespace {
21
22template<SkDisplacementMapEffect::ChannelSelectorType type>
23uint32_t getValue(SkColor, const SkUnPreMultiply::Scale*) {
24    SkASSERT(!"Unknown channel selector");
25    return 0;
26}
27
28template<> uint32_t getValue<SkDisplacementMapEffect::kR_ChannelSelectorType>(
29    SkColor l, const SkUnPreMultiply::Scale* table) {
30    return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedR32(l));
31}
32
33template<> uint32_t getValue<SkDisplacementMapEffect::kG_ChannelSelectorType>(
34    SkColor l, const SkUnPreMultiply::Scale* table) {
35    return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedG32(l));
36}
37
38template<> uint32_t getValue<SkDisplacementMapEffect::kB_ChannelSelectorType>(
39    SkColor l, const SkUnPreMultiply::Scale* table) {
40    return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedB32(l));
41}
42
43template<> uint32_t getValue<SkDisplacementMapEffect::kA_ChannelSelectorType>(
44    SkColor l, const SkUnPreMultiply::Scale*) {
45    return SkGetPackedA32(l);
46}
47
48template<SkDisplacementMapEffect::ChannelSelectorType typeX,
49         SkDisplacementMapEffect::ChannelSelectorType typeY>
50void computeDisplacement(SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src)
51{
52    static const SkScalar Inv8bit = SkScalarDiv(SK_Scalar1, SkFloatToScalar(255.0f));
53    static const SkScalar Half8bit = SkFloatToScalar(255.0f * 0.5f);
54    const int dstW = displ->width();
55    const int dstH = displ->height();
56    const int srcW = src->width();
57    const int srcH = src->height();
58    const SkScalar scaleX = SkScalarMul(SkScalarMul(scale, SkIntToScalar(dstW)), Inv8bit);
59    const SkScalar scaleY = SkScalarMul(SkScalarMul(scale, SkIntToScalar(dstH)), Inv8bit);
60    const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
61    for (int y = 0; y < dstH; ++y) {
62        const SkPMColor* displPtr = displ->getAddr32(0, y);
63        SkPMColor* dstPtr = dst->getAddr32(0, y);
64        for (int x = 0; x < dstW; ++x, ++displPtr, ++dstPtr) {
65            const SkScalar displX =
66                SkScalarMul(scaleX, SkIntToScalar(getValue<typeX>(*displPtr, table))-Half8bit);
67            const SkScalar displY =
68                SkScalarMul(scaleY, SkIntToScalar(getValue<typeY>(*displPtr, table))-Half8bit);
69            const int coordX = x + SkScalarRoundToInt(displX);
70            const int coordY = y + SkScalarRoundToInt(displY);
71            *dstPtr = ((coordX < 0) || (coordX >= srcW) || (coordY < 0) || (coordY >= srcH)) ?
72                      0 : *(src->getAddr32(coordX, coordY));
73        }
74    }
75}
76
77template<SkDisplacementMapEffect::ChannelSelectorType typeX>
78void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
79                         SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src)
80{
81    switch (yChannelSelector) {
82      case SkDisplacementMapEffect::kR_ChannelSelectorType:
83        computeDisplacement<typeX, SkDisplacementMapEffect::kR_ChannelSelectorType>(
84            scale, dst, displ, src);
85        break;
86      case SkDisplacementMapEffect::kG_ChannelSelectorType:
87        computeDisplacement<typeX, SkDisplacementMapEffect::kG_ChannelSelectorType>(
88            scale, dst, displ, src);
89        break;
90      case SkDisplacementMapEffect::kB_ChannelSelectorType:
91        computeDisplacement<typeX, SkDisplacementMapEffect::kB_ChannelSelectorType>(
92            scale, dst, displ, src);
93        break;
94      case SkDisplacementMapEffect::kA_ChannelSelectorType:
95        computeDisplacement<typeX, SkDisplacementMapEffect::kA_ChannelSelectorType>(
96            scale, dst, displ, src);
97        break;
98      case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
99      default:
100        SkASSERT(!"Unknown Y channel selector");
101    }
102}
103
104void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
105                         SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
106                         SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src)
107{
108    switch (xChannelSelector) {
109      case SkDisplacementMapEffect::kR_ChannelSelectorType:
110        computeDisplacement<SkDisplacementMapEffect::kR_ChannelSelectorType>(
111            yChannelSelector, scale, dst, displ, src);
112        break;
113      case SkDisplacementMapEffect::kG_ChannelSelectorType:
114        computeDisplacement<SkDisplacementMapEffect::kG_ChannelSelectorType>(
115            yChannelSelector, scale, dst, displ, src);
116        break;
117      case SkDisplacementMapEffect::kB_ChannelSelectorType:
118        computeDisplacement<SkDisplacementMapEffect::kB_ChannelSelectorType>(
119            yChannelSelector, scale, dst, displ, src);
120        break;
121      case SkDisplacementMapEffect::kA_ChannelSelectorType:
122        computeDisplacement<SkDisplacementMapEffect::kA_ChannelSelectorType>(
123            yChannelSelector, scale, dst, displ, src);
124        break;
125      case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
126      default:
127        SkASSERT(!"Unknown X channel selector");
128    }
129}
130
131} // end namespace
132
133///////////////////////////////////////////////////////////////////////////////
134
135SkDisplacementMapEffect::SkDisplacementMapEffect(ChannelSelectorType xChannelSelector,
136                                                 ChannelSelectorType yChannelSelector,
137                                                 SkScalar scale,
138                                                 SkImageFilter* displacement,
139                                                 SkImageFilter* color)
140  : INHERITED(displacement, color)
141  , fXChannelSelector(xChannelSelector)
142  , fYChannelSelector(yChannelSelector)
143  , fScale(scale)
144{
145}
146
147SkDisplacementMapEffect::~SkDisplacementMapEffect() {
148}
149
150SkDisplacementMapEffect::SkDisplacementMapEffect(SkFlattenableReadBuffer& buffer)
151  : INHERITED(buffer)
152{
153    fXChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt();
154    fYChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt();
155    fScale            = buffer.readScalar();
156}
157
158void SkDisplacementMapEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
159    this->INHERITED::flatten(buffer);
160    buffer.writeInt((int) fXChannelSelector);
161    buffer.writeInt((int) fYChannelSelector);
162    buffer.writeScalar(fScale);
163}
164
165bool SkDisplacementMapEffect::onFilterImage(Proxy* proxy,
166                                            const SkBitmap& src,
167                                            const SkMatrix& ctm,
168                                            SkBitmap* dst,
169                                            SkIPoint* offset) {
170    SkBitmap displ, color = src;
171    SkImageFilter* colorInput = getColorInput();
172    SkImageFilter* displacementInput = getDisplacementInput();
173    SkASSERT(NULL != displacementInput);
174    if ((colorInput && !colorInput->filterImage(proxy, src, ctm, &color, offset)) ||
175        !displacementInput->filterImage(proxy, src, ctm, &displ, offset)) {
176        return false;
177    }
178    if ((displ.config() != SkBitmap::kARGB_8888_Config) ||
179        (color.config() != SkBitmap::kARGB_8888_Config)) {
180        return false;
181    }
182
183    SkAutoLockPixels alp_displacement(displ), alp_color(color);
184    if (!displ.getPixels() || !color.getPixels()) {
185        return false;
186    }
187    dst->setConfig(displ.config(), displ.width(), displ.height());
188    dst->allocPixels();
189    if (!dst->getPixels()) {
190        return false;
191    }
192
193    computeDisplacement(fXChannelSelector, fYChannelSelector, fScale, dst, &displ, &color);
194
195    return true;
196}
197
198///////////////////////////////////////////////////////////////////////////////
199
200#if SK_SUPPORT_GPU
201class GrGLDisplacementMapEffect : public GrGLEffect {
202public:
203    GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
204                              const GrEffectRef& effect);
205    virtual ~GrGLDisplacementMapEffect();
206
207    virtual void emitCode(GrGLShaderBuilder*,
208                          const GrEffectStage&,
209                          EffectKey,
210                          const char* vertexCoords,
211                          const char* outputColor,
212                          const char* inputColor,
213                          const TextureSamplerArray&) SK_OVERRIDE;
214
215    static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
216
217    virtual void setData(const GrGLUniformManager&, const GrEffectStage&);
218
219private:
220    SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
221    SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
222    GrGLEffectMatrix fDisplacementEffectMatrix;
223    GrGLEffectMatrix fColorEffectMatrix;
224    GrGLUniformManager::UniformHandle fScaleUni;
225    GrGLUniformManager::UniformHandle fYSignColor;
226    GrGLUniformManager::UniformHandle fYSignDispl;
227
228    typedef GrGLEffect INHERITED;
229};
230
231///////////////////////////////////////////////////////////////////////////////
232
233class GrDisplacementMapEffect : public GrEffect {
234public:
235    static GrEffectRef* Create(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
236                               SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
237                               SkScalar scale, GrTexture* displacement, GrTexture* color) {
238        AutoEffectUnref effect(SkNEW_ARGS(GrDisplacementMapEffect, (xChannelSelector,
239                                                                    yChannelSelector,
240                                                                    scale,
241                                                                    displacement,
242                                                                    color)));
243        return CreateEffectRef(effect);
244    }
245
246    virtual ~GrDisplacementMapEffect();
247
248    const GrBackendEffectFactory& getFactory() const;
249    SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const
250        { return fXChannelSelector; }
251    SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const
252        { return fYChannelSelector; }
253    SkScalar scale() const { return fScale; }
254
255    typedef GrGLDisplacementMapEffect GLEffect;
256    static const char* Name() { return "DisplacementMap"; }
257
258    void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
259
260private:
261    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
262
263    GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
264                            SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
265                            SkScalar scale, GrTexture* displacement, GrTexture* color);
266
267    GR_DECLARE_EFFECT_TEST;
268
269    GrTextureAccess             fDisplacementAccess;
270    GrTextureAccess             fColorAccess;
271    SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
272    SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
273    SkScalar fScale;
274
275    typedef GrEffect INHERITED;
276};
277
278bool SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
279    SkBitmap colorBM;
280    if (!SkImageFilterUtils::GetInputResultGPU(getColorInput(), proxy, src, &colorBM)) {
281        return false;
282    }
283    GrTexture* color = (GrTexture*) colorBM.getTexture();
284    SkBitmap displacementBM;
285    if (!SkImageFilterUtils::GetInputResultGPU(getDisplacementInput(), proxy, src, &displacementBM)) {
286        return false;
287    }
288    GrTexture* displacement = (GrTexture*) displacementBM.getTexture();
289    GrContext* context = color->getContext();
290
291    GrTextureDesc desc;
292    desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
293    desc.fWidth = src.width();
294    desc.fHeight = src.height();
295    desc.fConfig = kSkia8888_GrPixelConfig;
296
297    GrAutoScratchTexture ast(context, desc);
298    SkAutoTUnref<GrTexture> dst(ast.detach());
299
300    GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
301
302    GrPaint paint;
303    paint.colorStage(0)->setEffect(
304        GrDisplacementMapEffect::Create(fXChannelSelector,
305                                        fYChannelSelector,
306                                        fScale,
307                                        displacement,
308                                        color))->unref();
309    SkRect srcRect;
310    src.getBounds(&srcRect);
311    context->drawRect(paint, srcRect);
312    return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result);
313}
314
315///////////////////////////////////////////////////////////////////////////////
316
317GrDisplacementMapEffect::GrDisplacementMapEffect(
318                             SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
319                             SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
320                             SkScalar scale,
321                             GrTexture* displacement,
322                             GrTexture* color)
323    : fDisplacementAccess(displacement)
324    , fColorAccess(color)
325    , fXChannelSelector(xChannelSelector)
326    , fYChannelSelector(yChannelSelector)
327    , fScale(scale) {
328    this->addTextureAccess(&fDisplacementAccess);
329    this->addTextureAccess(&fColorAccess);
330}
331
332GrDisplacementMapEffect::~GrDisplacementMapEffect() {
333}
334
335bool GrDisplacementMapEffect::onIsEqual(const GrEffect& sBase) const {
336    const GrDisplacementMapEffect& s = CastEffect<GrDisplacementMapEffect>(sBase);
337    return fDisplacementAccess.getTexture() == s.fDisplacementAccess.getTexture() &&
338           fColorAccess.getTexture() == s.fColorAccess.getTexture() &&
339           fXChannelSelector == s.fXChannelSelector &&
340           fYChannelSelector == s.fYChannelSelector &&
341           fScale == s.fScale;
342}
343
344const GrBackendEffectFactory& GrDisplacementMapEffect::getFactory() const {
345    return GrTBackendEffectFactory<GrDisplacementMapEffect>::getInstance();
346}
347
348void GrDisplacementMapEffect::getConstantColorComponents(GrColor* color,
349                                                         uint32_t* validFlags) const {
350    // Any displacement offset bringing a pixel out of bounds will output a color of (0,0,0,0),
351    // so the only way we'd get a constant alpha is if the input color image has a constant alpha
352    // and no displacement offset push any texture coordinates out of bounds OR if the constant
353    // alpha is 0. Since this isn't trivial to compute at this point, let's assume the output is
354    // not of constant color when a displacement effect is applied.
355    *validFlags = 0;
356}
357
358///////////////////////////////////////////////////////////////////////////////
359
360GR_DEFINE_EFFECT_TEST(GrDisplacementMapEffect);
361
362GrEffectRef* GrDisplacementMapEffect::TestCreate(SkRandom* random,
363                                                 GrContext* context,
364                                                 GrTexture* textures[]) {
365    int texIdxDispl = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
366                                           GrEffectUnitTest::kAlphaTextureIdx;
367    int texIdxColor = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
368                                           GrEffectUnitTest::kAlphaTextureIdx;
369    static const int kMaxComponent = 4;
370    SkDisplacementMapEffect::ChannelSelectorType xChannelSelector =
371        static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
372        random->nextRangeU(1, kMaxComponent));
373    SkDisplacementMapEffect::ChannelSelectorType yChannelSelector =
374        static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
375        random->nextRangeU(1, kMaxComponent));
376    SkScalar scale = random->nextUScalar1();
377
378    return GrDisplacementMapEffect::Create(xChannelSelector, yChannelSelector, scale,
379                                           textures[texIdxDispl], textures[texIdxColor]);
380}
381
382///////////////////////////////////////////////////////////////////////////////
383
384GrGLDisplacementMapEffect::GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
385                                                     const GrEffectRef& effect)
386    : INHERITED(factory)
387    , fXChannelSelector(CastEffect<GrDisplacementMapEffect>(effect).xChannelSelector())
388    , fYChannelSelector(CastEffect<GrDisplacementMapEffect>(effect).yChannelSelector()) {
389}
390
391GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() {
392}
393
394void GrGLDisplacementMapEffect::emitCode(GrGLShaderBuilder* builder,
395                               const GrEffectStage&,
396                               EffectKey key,
397                               const char* vertexCoords,
398                               const char* outputColor,
399                               const char* inputColor,
400                               const TextureSamplerArray& samplers) {
401    fScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
402                                    kVec2f_GrSLType, "Scale");
403    const char* scaleUni = builder->getUniformCStr(fScaleUni);
404
405    const char* dCoordsIn;
406    GrSLType dCoordsType = fDisplacementEffectMatrix.emitCode(
407                                builder, key, vertexCoords, &dCoordsIn, NULL, "DISPL");
408    const char* cCoordsIn;
409    GrSLType cCoordsType = fColorEffectMatrix.emitCode(
410                                builder, key, vertexCoords, &cCoordsIn, NULL, "COLOR");
411
412    SkString* code = &builder->fFSCode;
413    const char* dColor = "dColor";
414    const char* cCoords = "cCoords";
415    const char* nearZero = "1e-6"; // Since 6.10352eâ5 is the smallest half float, use
416                                   // a number smaller than that to approximate 0, but
417                                   // leave room for 32-bit float GPU rounding errors.
418
419    code->appendf("\t\tvec4 %s = ", dColor);
420    builder->appendTextureLookup(code, samplers[0], dCoordsIn, dCoordsType);
421    code->append(";\n");
422
423    // Unpremultiply the displacement
424    code->appendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
425                  dColor, dColor, nearZero, dColor, dColor);
426
427    code->appendf("\t\tvec2 %s = %s + %s*(%s.",
428                  cCoords, cCoordsIn, scaleUni, dColor);
429
430    switch (fXChannelSelector) {
431      case SkDisplacementMapEffect::kR_ChannelSelectorType:
432        code->append("r");
433        break;
434      case SkDisplacementMapEffect::kG_ChannelSelectorType:
435        code->append("g");
436        break;
437      case SkDisplacementMapEffect::kB_ChannelSelectorType:
438        code->append("b");
439        break;
440      case SkDisplacementMapEffect::kA_ChannelSelectorType:
441        code->append("a");
442        break;
443      case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
444      default:
445        SkASSERT(!"Unknown X channel selector");
446    }
447
448    switch (fYChannelSelector) {
449      case SkDisplacementMapEffect::kR_ChannelSelectorType:
450        code->append("r");
451        break;
452      case SkDisplacementMapEffect::kG_ChannelSelectorType:
453        code->append("g");
454        break;
455      case SkDisplacementMapEffect::kB_ChannelSelectorType:
456        code->append("b");
457        break;
458      case SkDisplacementMapEffect::kA_ChannelSelectorType:
459        code->append("a");
460        break;
461      case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
462      default:
463        SkASSERT(!"Unknown Y channel selector");
464    }
465    code->append("-vec2(0.5));\t\t");
466
467    // FIXME : This can be achieved with a "clamp to border" texture repeat mode and
468    //         a 0 border color instead of computing if cCoords is out of bounds here.
469    code->appendf(
470        "%s = any(greaterThan(vec4(vec2(0.0), %s), vec4(%s, vec2(1.0)))) ? vec4(0.0) : ",
471        outputColor, cCoords, cCoords);
472    builder->appendTextureLookup(code, samplers[1], cCoords, cCoordsType);
473    code->append(";\n");
474}
475
476void GrGLDisplacementMapEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
477    const GrDisplacementMapEffect& displacementMap = GetEffectFromStage<GrDisplacementMapEffect>(stage);
478    GrTexture* displTex = displacementMap.texture(0);
479    GrTexture* colorTex = displacementMap.texture(1);
480    fDisplacementEffectMatrix.setData(uman,
481                                     GrEffect::MakeDivByTextureWHMatrix(displTex),
482                                     stage.getCoordChangeMatrix(),
483                                     displTex);
484    fColorEffectMatrix.setData(uman,
485                               GrEffect::MakeDivByTextureWHMatrix(colorTex),
486                               stage.getCoordChangeMatrix(),
487                               colorTex);
488
489    uman.set2f(fScaleUni, SkScalarToFloat(displacementMap.scale()),
490                colorTex->origin() == kTopLeft_GrSurfaceOrigin ?
491                SkScalarToFloat(displacementMap.scale()) :
492                SkScalarToFloat(-displacementMap.scale()));
493}
494
495GrGLEffect::EffectKey GrGLDisplacementMapEffect::GenKey(const GrEffectStage& stage,
496                                                        const GrGLCaps&) {
497    const GrDisplacementMapEffect& displacementMap =
498        GetEffectFromStage<GrDisplacementMapEffect>(stage);
499
500    GrTexture* displTex = displacementMap.texture(0);
501    GrTexture* colorTex = displacementMap.texture(1);
502
503    EffectKey displKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(displTex),
504                                                  stage.getCoordChangeMatrix(),
505                                                  displTex);
506
507    EffectKey colorKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(colorTex),
508                                                  stage.getCoordChangeMatrix(),
509                                                  colorTex);
510
511    colorKey <<= GrGLEffectMatrix::kKeyBits;
512    EffectKey xKey = displacementMap.xChannelSelector() << (2 * GrGLEffectMatrix::kKeyBits);
513    EffectKey yKey = displacementMap.yChannelSelector() << (2 * GrGLEffectMatrix::kKeyBits +
514                                                            SkDisplacementMapEffect::kKeyBits);
515
516    return xKey | yKey | displKey | colorKey;
517}
518#endif
519