Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2013 The Android Open Source Project
      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 "SkBicubicImageFilter.h"
      9 #include "SkBitmap.h"
     10 #include "SkColorPriv.h"
     11 #include "SkFlattenableBuffers.h"
     12 #include "SkMatrix.h"
     13 #include "SkRect.h"
     14 #include "SkUnPreMultiply.h"
     15 
     16 #if SK_SUPPORT_GPU
     17 #include "gl/GrGLEffectMatrix.h"
     18 #include "effects/GrSingleTextureEffect.h"
     19 #include "GrTBackendEffectFactory.h"
     20 #include "GrContext.h"
     21 #include "GrTexture.h"
     22 #include "SkImageFilterUtils.h"
     23 #endif
     24 
     25 SkBicubicImageFilter::SkBicubicImageFilter(const SkSize& scale, const SkScalar coefficients[16], SkImageFilter* input)
     26   : INHERITED(input),
     27     fScale(scale) {
     28     memcpy(fCoefficients, coefficients, sizeof(fCoefficients));
     29 }
     30 
     31 #define DS(x) SkDoubleToScalar(x)
     32 
     33 SkBicubicImageFilter* SkBicubicImageFilter::CreateMitchell(const SkSize& scale,
     34                                                            SkImageFilter* input) {
     35     static const SkScalar coefficients[16] = {
     36         DS( 1.0 / 18.0), DS(-9.0 / 18.0), DS( 15.0 / 18.0), DS( -7.0 / 18.0),
     37         DS(16.0 / 18.0), DS( 0.0 / 18.0), DS(-36.0 / 18.0), DS( 21.0 / 18.0),
     38         DS( 1.0 / 18.0), DS( 9.0 / 18.0), DS( 27.0 / 18.0), DS(-21.0 / 18.0),
     39         DS( 0.0 / 18.0), DS( 0.0 / 18.0), DS( -6.0 / 18.0), DS(  7.0 / 18.0),
     40     };
     41     return SkNEW_ARGS(SkBicubicImageFilter, (scale, coefficients, input));
     42 }
     43 
     44 SkBicubicImageFilter::SkBicubicImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
     45     SkDEBUGCODE(uint32_t readSize =) buffer.readScalarArray(fCoefficients);
     46     SkASSERT(readSize == 16);
     47     fScale.fWidth = buffer.readScalar();
     48     fScale.fHeight = buffer.readScalar();
     49 }
     50 
     51 void SkBicubicImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
     52     this->INHERITED::flatten(buffer);
     53     buffer.writeScalarArray(fCoefficients, 16);
     54     buffer.writeScalar(fScale.fWidth);
     55     buffer.writeScalar(fScale.fHeight);
     56 }
     57 
     58 SkBicubicImageFilter::~SkBicubicImageFilter() {
     59 }
     60 
     61 inline SkPMColor cubicBlend(const SkScalar c[16], SkScalar t, SkPMColor c0, SkPMColor c1, SkPMColor c2, SkPMColor c3) {
     62     SkScalar t2 = t * t, t3 = t2 * t;
     63     SkScalar cc[4];
     64     // FIXME:  For the fractx case, this should be refactored out of this function.
     65     cc[0] = c[0]  + SkScalarMul(c[1], t) + SkScalarMul(c[2], t2) + SkScalarMul(c[3], t3);
     66     cc[1] = c[4]  + SkScalarMul(c[5], t) + SkScalarMul(c[6], t2) + SkScalarMul(c[7], t3);
     67     cc[2] = c[8]  + SkScalarMul(c[9], t) + SkScalarMul(c[10], t2) + SkScalarMul(c[11], t3);
     68     cc[3] = c[12] + SkScalarMul(c[13], t) + SkScalarMul(c[14], t2) + SkScalarMul(c[15], t3);
     69     SkScalar a = SkScalarClampMax(SkScalarMul(cc[0], SkGetPackedA32(c0)) + SkScalarMul(cc[1], SkGetPackedA32(c1)) + SkScalarMul(cc[2], SkGetPackedA32(c2)) + SkScalarMul(cc[3], SkGetPackedA32(c3)), 255);
     70     SkScalar r = SkScalarMul(cc[0], SkGetPackedR32(c0)) + SkScalarMul(cc[1], SkGetPackedR32(c1)) + SkScalarMul(cc[2], SkGetPackedR32(c2)) + SkScalarMul(cc[3], SkGetPackedR32(c3));
     71     SkScalar g = SkScalarMul(cc[0], SkGetPackedG32(c0)) + SkScalarMul(cc[1], SkGetPackedG32(c1)) + SkScalarMul(cc[2], SkGetPackedG32(c2)) + SkScalarMul(cc[3], SkGetPackedG32(c3));
     72     SkScalar b = SkScalarMul(cc[0], SkGetPackedB32(c0)) + SkScalarMul(cc[1], SkGetPackedB32(c1)) + SkScalarMul(cc[2], SkGetPackedB32(c2)) + SkScalarMul(cc[3], SkGetPackedB32(c3));
     73     return SkPackARGB32(SkScalarRoundToInt(a),
     74                         SkScalarRoundToInt(SkScalarClampMax(r, a)),
     75                         SkScalarRoundToInt(SkScalarClampMax(g, a)),
     76                         SkScalarRoundToInt(SkScalarClampMax(b, a)));
     77 }
     78 
     79 bool SkBicubicImageFilter::onFilterImage(Proxy* proxy,
     80                                          const SkBitmap& source,
     81                                          const SkMatrix& matrix,
     82                                          SkBitmap* result,
     83                                          SkIPoint* loc) {
     84     SkBitmap src = source;
     85     if (getInput(0) && !getInput(0)->filterImage(proxy, source, matrix, &src, loc)) {
     86         return false;
     87     }
     88 
     89     if (src.config() != SkBitmap::kARGB_8888_Config) {
     90         return false;
     91     }
     92 
     93     SkAutoLockPixels alp(src);
     94     if (!src.getPixels()) {
     95         return false;
     96     }
     97 
     98     SkRect dstRect = SkRect::MakeWH(SkScalarMul(SkIntToScalar(src.width()), fScale.fWidth),
     99                                     SkScalarMul(SkIntToScalar(src.height()), fScale.fHeight));
    100     SkIRect dstIRect;
    101     dstRect.roundOut(&dstIRect);
    102     result->setConfig(src.config(), dstIRect.width(), dstIRect.height());
    103     result->allocPixels();
    104     if (!result->getPixels()) {
    105         return false;
    106     }
    107 
    108     SkRect srcRect;
    109     src.getBounds(&srcRect);
    110     SkMatrix inverse;
    111     inverse.setRectToRect(dstRect, srcRect, SkMatrix::kFill_ScaleToFit);
    112     inverse.postTranslate(SkFloatToScalar(-0.5f), SkFloatToScalar(-0.5f));
    113 
    114     for (int y = dstIRect.fTop; y < dstIRect.fBottom; ++y) {
    115         SkPMColor* dptr = result->getAddr32(dstIRect.fLeft, y);
    116         for (int x = dstIRect.fLeft; x < dstIRect.fRight; ++x) {
    117             SkPoint srcPt, dstPt = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
    118             inverse.mapPoints(&srcPt, &dstPt, 1);
    119             SkScalar fractx = srcPt.fX - SkScalarFloorToScalar(srcPt.fX);
    120             SkScalar fracty = srcPt.fY - SkScalarFloorToScalar(srcPt.fY);
    121             int sx = SkScalarFloorToInt(srcPt.fX);
    122             int sy = SkScalarFloorToInt(srcPt.fY);
    123             int x0 = SkClampMax(sx - 1, src.width() - 1);
    124             int x1 = SkClampMax(sx    , src.width() - 1);
    125             int x2 = SkClampMax(sx + 1, src.width() - 1);
    126             int x3 = SkClampMax(sx + 2, src.width() - 1);
    127             int y0 = SkClampMax(sy - 1, src.height() - 1);
    128             int y1 = SkClampMax(sy    , src.height() - 1);
    129             int y2 = SkClampMax(sy + 1, src.height() - 1);
    130             int y3 = SkClampMax(sy + 2, src.height() - 1);
    131             SkPMColor s00 = *src.getAddr32(x0, y0);
    132             SkPMColor s10 = *src.getAddr32(x1, y0);
    133             SkPMColor s20 = *src.getAddr32(x2, y0);
    134             SkPMColor s30 = *src.getAddr32(x3, y0);
    135             SkPMColor s0 = cubicBlend(fCoefficients, fractx, s00, s10, s20, s30);
    136             SkPMColor s01 = *src.getAddr32(x0, y1);
    137             SkPMColor s11 = *src.getAddr32(x1, y1);
    138             SkPMColor s21 = *src.getAddr32(x2, y1);
    139             SkPMColor s31 = *src.getAddr32(x3, y1);
    140             SkPMColor s1 = cubicBlend(fCoefficients, fractx, s01, s11, s21, s31);
    141             SkPMColor s02 = *src.getAddr32(x0, y2);
    142             SkPMColor s12 = *src.getAddr32(x1, y2);
    143             SkPMColor s22 = *src.getAddr32(x2, y2);
    144             SkPMColor s32 = *src.getAddr32(x3, y2);
    145             SkPMColor s2 = cubicBlend(fCoefficients, fractx, s02, s12, s22, s32);
    146             SkPMColor s03 = *src.getAddr32(x0, y3);
    147             SkPMColor s13 = *src.getAddr32(x1, y3);
    148             SkPMColor s23 = *src.getAddr32(x2, y3);
    149             SkPMColor s33 = *src.getAddr32(x3, y3);
    150             SkPMColor s3 = cubicBlend(fCoefficients, fractx, s03, s13, s23, s33);
    151             *dptr++ = cubicBlend(fCoefficients, fracty, s0, s1, s2, s3);
    152         }
    153     }
    154     return true;
    155 }
    156 
    157 ///////////////////////////////////////////////////////////////////////////////
    158 
    159 #if SK_SUPPORT_GPU
    160 class GrGLBicubicEffect;
    161 
    162 class GrBicubicEffect : public GrSingleTextureEffect {
    163 public:
    164     virtual ~GrBicubicEffect();
    165 
    166     static const char* Name() { return "Bicubic"; }
    167     const float* coefficients() const { return fCoefficients; }
    168 
    169     typedef GrGLBicubicEffect GLEffect;
    170 
    171     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
    172     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
    173 
    174     static GrEffectRef* Create(GrTexture* tex, const SkScalar coefficients[16]) {
    175         AutoEffectUnref effect(SkNEW_ARGS(GrBicubicEffect, (tex, coefficients)));
    176         return CreateEffectRef(effect);
    177     }
    178 
    179 private:
    180     GrBicubicEffect(GrTexture*, const SkScalar coefficients[16]);
    181     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
    182     float    fCoefficients[16];
    183 
    184     GR_DECLARE_EFFECT_TEST;
    185 
    186     typedef GrSingleTextureEffect INHERITED;
    187 };
    188 
    189 class GrGLBicubicEffect : public GrGLEffect {
    190 public:
    191     GrGLBicubicEffect(const GrBackendEffectFactory& factory,
    192                       const GrDrawEffect&);
    193     virtual void emitCode(GrGLShaderBuilder*,
    194                           const GrDrawEffect&,
    195                           EffectKey,
    196                           const char* outputColor,
    197                           const char* inputColor,
    198                           const TextureSamplerArray&) SK_OVERRIDE;
    199 
    200     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
    201 
    202     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
    203 
    204 private:
    205     typedef GrGLUniformManager::UniformHandle        UniformHandle;
    206 
    207     UniformHandle       fCoefficientsUni;
    208     UniformHandle       fImageIncrementUni;
    209 
    210     GrGLEffectMatrix    fEffectMatrix;
    211 
    212     typedef GrGLEffect INHERITED;
    213 };
    214 
    215 GrGLBicubicEffect::GrGLBicubicEffect(const GrBackendEffectFactory& factory,
    216                                      const GrDrawEffect& drawEffect)
    217     : INHERITED(factory)
    218     , fCoefficientsUni(GrGLUniformManager::kInvalidUniformHandle)
    219     , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle)
    220     , fEffectMatrix(drawEffect.castEffect<GrBicubicEffect>().coordsType()) {
    221 }
    222 
    223 void GrGLBicubicEffect::emitCode(GrGLShaderBuilder* builder,
    224                                  const GrDrawEffect&,
    225                                  EffectKey key,
    226                                  const char* outputColor,
    227                                  const char* inputColor,
    228                                  const TextureSamplerArray& samplers) {
    229     const char* coords;
    230     fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
    231     fCoefficientsUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
    232                                            kMat44f_GrSLType, "Coefficients");
    233     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
    234                                              kVec2f_GrSLType, "ImageIncrement");
    235 
    236     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
    237     const char* coeff = builder->getUniformCStr(fCoefficientsUni);
    238 
    239     SkString cubicBlendName;
    240 
    241     static const GrGLShaderVar gCubicBlendArgs[] = {
    242         GrGLShaderVar("coefficients",  kMat44f_GrSLType),
    243         GrGLShaderVar("t",             kFloat_GrSLType),
    244         GrGLShaderVar("c0",            kVec4f_GrSLType),
    245         GrGLShaderVar("c1",            kVec4f_GrSLType),
    246         GrGLShaderVar("c2",            kVec4f_GrSLType),
    247         GrGLShaderVar("c3",            kVec4f_GrSLType),
    248     };
    249     builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
    250                           kVec4f_GrSLType,
    251                           "cubicBlend",
    252                           SK_ARRAY_COUNT(gCubicBlendArgs),
    253                           gCubicBlendArgs,
    254                           "\tvec4 ts = vec4(1.0, t, t * t, t * t * t);\n"
    255                           "\tvec4 c = coefficients * ts;\n"
    256                           "\treturn c.x * c0 + c.y * c1 + c.z * c2 + c.w * c3;\n",
    257                           &cubicBlendName);
    258     builder->fsCodeAppendf("\tvec2 coord = %s - %s * vec2(0.5, 0.5);\n", coords, imgInc);
    259     builder->fsCodeAppendf("\tvec2 f = fract(coord / %s);\n", imgInc);
    260     for (int y = 0; y < 4; ++y) {
    261         for (int x = 0; x < 4; ++x) {
    262             SkString coord;
    263             coord.printf("coord + %s * vec2(%d, %d)", imgInc, x - 1, y - 1);
    264             builder->fsCodeAppendf("\tvec4 s%d%d = ", x, y);
    265             builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
    266                                          samplers[0],
    267                                          coord.c_str());
    268             builder->fsCodeAppend(";\n");
    269         }
    270         builder->fsCodeAppendf("\tvec4 s%d = %s(%s, f.x, s0%d, s1%d, s2%d, s3%d);\n", y, cubicBlendName.c_str(), coeff, y, y, y, y);
    271     }
    272     builder->fsCodeAppendf("\t%s = %s(%s, f.y, s0, s1, s2, s3);\n", outputColor, cubicBlendName.c_str(), coeff);
    273 }
    274 
    275 GrGLEffect::EffectKey GrGLBicubicEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
    276     const GrBicubicEffect& bicubic = drawEffect.castEffect<GrBicubicEffect>();
    277     EffectKey matrixKey = GrGLEffectMatrix::GenKey(bicubic.getMatrix(),
    278                                                    drawEffect,
    279                                                    bicubic.coordsType(),
    280                                                    bicubic.texture(0));
    281     return matrixKey;
    282 }
    283 
    284 void GrGLBicubicEffect::setData(const GrGLUniformManager& uman,
    285                                 const GrDrawEffect& drawEffect) {
    286     const GrBicubicEffect& effect = drawEffect.castEffect<GrBicubicEffect>();
    287     GrTexture& texture = *effect.texture(0);
    288     float imageIncrement[2];
    289     imageIncrement[0] = 1.0f / texture.width();
    290     imageIncrement[1] = 1.0f / texture.height();
    291     uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
    292     uman.setMatrix4f(fCoefficientsUni, effect.coefficients());
    293     fEffectMatrix.setData(uman,
    294                           effect.getMatrix(),
    295                           drawEffect,
    296                           effect.texture(0));
    297 }
    298 
    299 GrBicubicEffect::GrBicubicEffect(GrTexture* texture,
    300                                  const SkScalar coefficients[16])
    301   : INHERITED(texture, MakeDivByTextureWHMatrix(texture)) {
    302     for (int y = 0; y < 4; y++) {
    303         for (int x = 0; x < 4; x++) {
    304             // Convert from row-major scalars to column-major floats.
    305             fCoefficients[x * 4 + y] = SkScalarToFloat(coefficients[y * 4 + x]);
    306         }
    307     }
    308 }
    309 
    310 GrBicubicEffect::~GrBicubicEffect() {
    311 }
    312 
    313 const GrBackendEffectFactory& GrBicubicEffect::getFactory() const {
    314     return GrTBackendEffectFactory<GrBicubicEffect>::getInstance();
    315 }
    316 
    317 bool GrBicubicEffect::onIsEqual(const GrEffect& sBase) const {
    318     const GrBicubicEffect& s = CastEffect<GrBicubicEffect>(sBase);
    319     return this->texture(0) == s.texture(0) &&
    320            !memcmp(fCoefficients, s.coefficients(), 16);
    321 }
    322 
    323 void GrBicubicEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
    324     // FIXME:  Perhaps we can do better.
    325     *validFlags = 0;
    326     return;
    327 }
    328 
    329 GR_DEFINE_EFFECT_TEST(GrBicubicEffect);
    330 
    331 GrEffectRef* GrBicubicEffect::TestCreate(SkMWCRandom* random,
    332                                          GrContext* context,
    333                                          const GrDrawTargetCaps&,
    334                                          GrTexture* textures[]) {
    335     int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
    336                                       GrEffectUnitTest::kAlphaTextureIdx;
    337     SkScalar coefficients[16];
    338     for (int i = 0; i < 16; i++) {
    339         coefficients[i] = random->nextSScalar1();
    340     }
    341     return GrBicubicEffect::Create(textures[texIdx], coefficients);
    342 }
    343 
    344 bool SkBicubicImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm,
    345                                           SkBitmap* result, SkIPoint* offset) {
    346     SkBitmap srcBM;
    347     if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &srcBM, offset)) {
    348         return false;
    349     }
    350     GrTexture* srcTexture = srcBM.getTexture();
    351     GrContext* context = srcTexture->getContext();
    352 
    353     SkRect dstRect = SkRect::MakeWH(srcBM.width() * fScale.fWidth,
    354                                     srcBM.height() * fScale.fHeight);
    355 
    356     GrTextureDesc desc;
    357     desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
    358     desc.fWidth = SkScalarCeilToInt(dstRect.width());
    359     desc.fHeight = SkScalarCeilToInt(dstRect.height());
    360     desc.fConfig = kSkia8888_GrPixelConfig;
    361 
    362     GrAutoScratchTexture ast(context, desc);
    363     SkAutoTUnref<GrTexture> dst(ast.detach());
    364     if (!dst) {
    365         return false;
    366     }
    367     GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
    368     GrPaint paint;
    369     paint.addColorEffect(GrBicubicEffect::Create(srcTexture, fCoefficients))->unref();
    370     SkRect srcRect;
    371     srcBM.getBounds(&srcRect);
    372     context->drawRectToRect(paint, dstRect, srcRect);
    373     return SkImageFilterUtils::WrapTexture(dst, desc.fWidth, desc.fHeight, result);
    374 }
    375 #endif
    376 
    377 ///////////////////////////////////////////////////////////////////////////////
    378