Home | History | Annotate | Download | only in shaders
      1 /*
      2  * Copyright 2015 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 "SkArenaAlloc.h"
      9 #include "SkBitmapController.h"
     10 #include "SkBitmapProcShader.h"
     11 #include "SkBitmapProvider.h"
     12 #include "SkEmptyShader.h"
     13 #include "SkImage_Base.h"
     14 #include "SkImageShader.h"
     15 #include "SkPM4fPriv.h"
     16 #include "SkReadBuffer.h"
     17 #include "SkWriteBuffer.h"
     18 #include "../jumper/SkJumper.h"
     19 
     20 /**
     21  *  We are faster in clamp, so always use that tiling when we can.
     22  */
     23 static SkShader::TileMode optimize(SkShader::TileMode tm, int dimension) {
     24     SkASSERT(dimension > 0);
     25 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
     26     // need to update frameworks/base/libs/hwui/tests/unit/SkiaBehaviorTests.cpp:55 to allow
     27     // for transforming to clamp.
     28     return tm;
     29 #else
     30     return dimension == 1 ? SkShader::kClamp_TileMode : tm;
     31 #endif
     32 }
     33 
     34 SkImageShader::SkImageShader(sk_sp<SkImage> img, TileMode tmx, TileMode tmy, const SkMatrix* matrix)
     35     : INHERITED(matrix)
     36     , fImage(std::move(img))
     37     , fTileModeX(optimize(tmx, fImage->width()))
     38     , fTileModeY(optimize(tmy, fImage->height()))
     39 {}
     40 
     41 sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
     42     const TileMode tx = (TileMode)buffer.readUInt();
     43     const TileMode ty = (TileMode)buffer.readUInt();
     44     SkMatrix matrix;
     45     buffer.readMatrix(&matrix);
     46     sk_sp<SkImage> img = buffer.readImage();
     47     if (!img) {
     48         return nullptr;
     49     }
     50     return SkImageShader::Make(std::move(img), tx, ty, &matrix);
     51 }
     52 
     53 void SkImageShader::flatten(SkWriteBuffer& buffer) const {
     54     buffer.writeUInt(fTileModeX);
     55     buffer.writeUInt(fTileModeY);
     56     buffer.writeMatrix(this->getLocalMatrix());
     57     buffer.writeImage(fImage.get());
     58 }
     59 
     60 bool SkImageShader::isOpaque() const {
     61     return fImage->isOpaque();
     62 }
     63 
     64 bool SkImageShader::IsRasterPipelineOnly(SkColorType ct, SkShader::TileMode tx,
     65                                          SkShader::TileMode ty) {
     66     if (ct != kN32_SkColorType) {
     67         return true;
     68     }
     69 #ifndef SK_SUPPORT_LEGACY_TILED_BITMAPS
     70     if (tx != ty) {
     71         return true;
     72     }
     73 #endif
     74     return false;
     75 }
     76 
     77 bool SkImageShader::onIsRasterPipelineOnly() const {
     78     SkBitmapProvider provider(fImage.get(), nullptr);
     79     return IsRasterPipelineOnly(provider.info().colorType(), fTileModeX, fTileModeY);
     80 }
     81 
     82 SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec,
     83                                                     SkArenaAlloc* alloc) const {
     84     return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY,
     85                                                  SkBitmapProvider(fImage.get(), rec.fDstColorSpace),
     86                                                  rec, alloc);
     87 }
     88 
     89 SkImage* SkImageShader::onIsAImage(SkMatrix* texM, TileMode xy[]) const {
     90     if (texM) {
     91         *texM = this->getLocalMatrix();
     92     }
     93     if (xy) {
     94         xy[0] = (TileMode)fTileModeX;
     95         xy[1] = (TileMode)fTileModeY;
     96     }
     97     return const_cast<SkImage*>(fImage.get());
     98 }
     99 
    100 #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
    101 bool SkImageShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
    102     const SkBitmap* bm = as_IB(fImage)->onPeekBitmap();
    103     if (!bm) {
    104         return false;
    105     }
    106 
    107     if (texture) {
    108         *texture = *bm;
    109     }
    110     if (texM) {
    111         *texM = this->getLocalMatrix();
    112     }
    113     if (xy) {
    114         xy[0] = (TileMode)fTileModeX;
    115         xy[1] = (TileMode)fTileModeY;
    116     }
    117     return true;
    118 }
    119 #endif
    120 
    121 static bool bitmap_is_too_big(int w, int h) {
    122     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
    123     // communicates between its matrix-proc and its sampler-proc. Until we can
    124     // widen that, we have to reject bitmaps that are larger.
    125     //
    126     static const int kMaxSize = 65535;
    127 
    128     return w > kMaxSize || h > kMaxSize;
    129 }
    130 
    131 sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, TileMode tx, TileMode ty,
    132                                     const SkMatrix* localMatrix) {
    133     if (!image || bitmap_is_too_big(image->width(), image->height())) {
    134         return sk_make_sp<SkEmptyShader>();
    135     } else {
    136         return sk_make_sp<SkImageShader>(image, tx, ty, localMatrix);
    137     }
    138 }
    139 
    140 #ifndef SK_IGNORE_TO_STRING
    141 void SkImageShader::toString(SkString* str) const {
    142     const char* gTileModeName[SkShader::kTileModeCount] = {
    143         "clamp", "repeat", "mirror"
    144     };
    145 
    146     str->appendf("ImageShader: ((%s %s) ", gTileModeName[fTileModeX], gTileModeName[fTileModeY]);
    147     fImage->toString(str);
    148     this->INHERITED::toString(str);
    149     str->append(")");
    150 }
    151 #endif
    152 
    153 ///////////////////////////////////////////////////////////////////////////////////////////////////
    154 
    155 #if SK_SUPPORT_GPU
    156 
    157 #include "SkGr.h"
    158 #include "GrContext.h"
    159 #include "effects/GrSimpleTextureEffect.h"
    160 #include "effects/GrBicubicEffect.h"
    161 #include "effects/GrSimpleTextureEffect.h"
    162 
    163 sk_sp<GrFragmentProcessor> SkImageShader::asFragmentProcessor(const AsFPArgs& args) const {
    164 
    165     SkMatrix lmInverse;
    166     if (!this->getLocalMatrix().invert(&lmInverse)) {
    167         return nullptr;
    168     }
    169     if (args.fLocalMatrix) {
    170         SkMatrix inv;
    171         if (!args.fLocalMatrix->invert(&inv)) {
    172             return nullptr;
    173         }
    174         lmInverse.postConcat(inv);
    175     }
    176 
    177     SkShader::TileMode tm[] = { fTileModeX, fTileModeY };
    178 
    179     // Must set wrap and filter on the sampler before requesting a texture. In two places below
    180     // we check the matrix scale factors to determine how to interpret the filter quality setting.
    181     // This completely ignores the complexity of the drawVertices case where explicit local coords
    182     // are provided by the caller.
    183     bool doBicubic;
    184     GrSamplerParams::FilterMode textureFilterMode =
    185     GrSkFilterQualityToGrFilterMode(args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(),
    186                                     &doBicubic);
    187     GrSamplerParams params(tm, textureFilterMode);
    188     sk_sp<SkColorSpace> texColorSpace;
    189     SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
    190     sk_sp<GrTextureProxy> proxy(as_IB(fImage)->asTextureProxyRef(args.fContext, params,
    191                                                                  args.fDstColorSpace,
    192                                                                  &texColorSpace, scaleAdjust));
    193     if (!proxy) {
    194         return nullptr;
    195     }
    196 
    197     bool isAlphaOnly = GrPixelConfigIsAlphaOnly(proxy->config());
    198 
    199     lmInverse.postScale(scaleAdjust[0], scaleAdjust[1]);
    200 
    201     sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(),
    202                                                                        args.fDstColorSpace);
    203     sk_sp<GrFragmentProcessor> inner;
    204     if (doBicubic) {
    205         inner = GrBicubicEffect::Make(std::move(proxy),
    206                                       std::move(colorSpaceXform), lmInverse, tm);
    207     } else {
    208         inner = GrSimpleTextureEffect::Make(std::move(proxy),
    209                                             std::move(colorSpaceXform), lmInverse, params);
    210     }
    211 
    212     if (isAlphaOnly) {
    213         return inner;
    214     }
    215     return sk_sp<GrFragmentProcessor>(GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)));
    216 }
    217 
    218 #endif
    219 
    220 ///////////////////////////////////////////////////////////////////////////////////////////////////
    221 #include "SkImagePriv.h"
    222 
    223 sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
    224                                    SkShader::TileMode tmy, const SkMatrix* localMatrix,
    225                                    SkCopyPixelsMode cpm) {
    226     return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, cpm),
    227                                tmx, tmy, localMatrix);
    228 }
    229 
    230 static sk_sp<SkFlattenable> SkBitmapProcShader_CreateProc(SkReadBuffer& buffer) {
    231     SkMatrix lm;
    232     buffer.readMatrix(&lm);
    233     sk_sp<SkImage> image = buffer.readBitmapAsImage();
    234     SkShader::TileMode mx = (SkShader::TileMode)buffer.readUInt();
    235     SkShader::TileMode my = (SkShader::TileMode)buffer.readUInt();
    236     return image ? image->makeShader(mx, my, &lm) : nullptr;
    237 }
    238 
    239 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShaderBase)
    240 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader)
    241 SkFlattenable::Register("SkBitmapProcShader", SkBitmapProcShader_CreateProc, kSkShaderBase_Type);
    242 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
    243 
    244 
    245 bool SkImageShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* dstCS, SkArenaAlloc* alloc,
    246                                    const SkMatrix& ctm, const SkPaint& paint,
    247                                    const SkMatrix* localM) const {
    248     auto matrix = SkMatrix::Concat(ctm, this->getLocalMatrix());
    249     if (localM) {
    250         matrix.preConcat(*localM);
    251     }
    252 
    253     if (!matrix.invert(&matrix)) {
    254         return false;
    255     }
    256     auto quality = paint.getFilterQuality();
    257 
    258     SkBitmapProvider provider(fImage.get(), dstCS);
    259     SkDefaultBitmapController controller(SkDefaultBitmapController::CanShadeHQ::kYes);
    260     std::unique_ptr<SkBitmapController::State> state {
    261         controller.requestBitmap(provider, matrix, quality)
    262     };
    263     if (!state) {
    264         return false;
    265     }
    266 
    267     const SkPixmap& pm = state->pixmap();
    268     matrix  = state->invMatrix();
    269     quality = state->quality();
    270     auto info = pm.info();
    271 
    272     // When the matrix is just an integer translate, bilerp == nearest neighbor.
    273     if (quality == kLow_SkFilterQuality &&
    274         matrix.getType() <= SkMatrix::kTranslate_Mask &&
    275         matrix.getTranslateX() == (int)matrix.getTranslateX() &&
    276         matrix.getTranslateY() == (int)matrix.getTranslateY()) {
    277         quality = kNone_SkFilterQuality;
    278     }
    279 
    280     // See skia:4649 and the GM image_scale_aligned.
    281     if (quality == kNone_SkFilterQuality) {
    282         if (matrix.getScaleX() >= 0) {
    283             matrix.setTranslateX(nextafterf(matrix.getTranslateX(),
    284                                             floorf(matrix.getTranslateX())));
    285         }
    286         if (matrix.getScaleY() >= 0) {
    287             matrix.setTranslateY(nextafterf(matrix.getTranslateY(),
    288                                             floorf(matrix.getTranslateY())));
    289         }
    290     }
    291 
    292     p->append(SkRasterPipeline::seed_shader);
    293 
    294     struct MiscCtx {
    295         std::unique_ptr<SkBitmapController::State> state;
    296         SkColor4f paint_color;
    297     };
    298     auto misc = alloc->make<MiscCtx>();
    299     misc->state       = std::move(state);  // Extend lifetime to match the pipeline's.
    300     misc->paint_color = SkColor4f_from_SkColor(paint.getColor(), dstCS);
    301     p->append_matrix(alloc, matrix);
    302 
    303     auto gather = alloc->make<SkJumper_MemoryCtx>();
    304     gather->pixels = pm.writable_addr();  // Don't worry, we won't write to it.
    305     gather->stride = pm.rowBytesAsPixels();
    306 
    307     auto limit_x = alloc->make<SkJumper_TileCtx>(),
    308          limit_y = alloc->make<SkJumper_TileCtx>();
    309     limit_x->scale = pm.width();
    310     limit_x->invScale = 1.0f / pm.width();
    311     limit_y->scale = pm.height();
    312     limit_y->invScale = 1.0f / pm.height();
    313 
    314     auto append_tiling_and_gather = [&] {
    315         switch (fTileModeX) {
    316             case kClamp_TileMode:  p->append(SkRasterPipeline::clamp_x,  limit_x); break;
    317             case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, limit_x); break;
    318             case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, limit_x); break;
    319         }
    320         switch (fTileModeY) {
    321             case kClamp_TileMode:  p->append(SkRasterPipeline::clamp_y,  limit_y); break;
    322             case kMirror_TileMode: p->append(SkRasterPipeline::mirror_y, limit_y); break;
    323             case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_y, limit_y); break;
    324         }
    325         switch (info.colorType()) {
    326             case kAlpha_8_SkColorType:   p->append(SkRasterPipeline::gather_a8,   gather); break;
    327             case kGray_8_SkColorType:    p->append(SkRasterPipeline::gather_g8,   gather); break;
    328             case kRGB_565_SkColorType:   p->append(SkRasterPipeline::gather_565,  gather); break;
    329             case kARGB_4444_SkColorType: p->append(SkRasterPipeline::gather_4444, gather); break;
    330             case kBGRA_8888_SkColorType: p->append(SkRasterPipeline::gather_bgra, gather); break;
    331             case kRGBA_8888_SkColorType: p->append(SkRasterPipeline::gather_8888, gather); break;
    332             case kRGBA_F16_SkColorType:  p->append(SkRasterPipeline::gather_f16,  gather); break;
    333             default: SkASSERT(false);
    334         }
    335         if (dstCS && (!info.colorSpace() || info.gammaCloseToSRGB())) {
    336             p->append_from_srgb(info.alphaType());
    337         }
    338     };
    339 
    340     SkJumper_SamplerCtx* sampler = nullptr;
    341     if (quality != kNone_SkFilterQuality) {
    342         sampler = alloc->make<SkJumper_SamplerCtx>();
    343     }
    344 
    345     auto sample = [&](SkRasterPipeline::StockStage setup_x,
    346                       SkRasterPipeline::StockStage setup_y) {
    347         p->append(setup_x, sampler);
    348         p->append(setup_y, sampler);
    349         append_tiling_and_gather();
    350         p->append(SkRasterPipeline::accumulate, sampler);
    351     };
    352 
    353     if (quality == kNone_SkFilterQuality) {
    354         append_tiling_and_gather();
    355     } else if (quality == kLow_SkFilterQuality) {
    356         p->append(SkRasterPipeline::save_xy, sampler);
    357 
    358         sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_ny);
    359         sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_ny);
    360         sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_py);
    361         sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_py);
    362 
    363         p->append(SkRasterPipeline::move_dst_src);
    364     } else {
    365         p->append(SkRasterPipeline::save_xy, sampler);
    366 
    367         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n3y);
    368         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n3y);
    369         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n3y);
    370         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n3y);
    371 
    372         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n1y);
    373         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n1y);
    374         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n1y);
    375         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n1y);
    376 
    377         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p1y);
    378         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p1y);
    379         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p1y);
    380         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p1y);
    381 
    382         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p3y);
    383         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p3y);
    384         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p3y);
    385         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p3y);
    386 
    387         p->append(SkRasterPipeline::move_dst_src);
    388     }
    389 
    390     if (info.colorType() == kAlpha_8_SkColorType) {
    391         p->append(SkRasterPipeline::set_rgb, &misc->paint_color);
    392     }
    393     if (info.colorType() == kAlpha_8_SkColorType || info.alphaType() == kUnpremul_SkAlphaType) {
    394         p->append(SkRasterPipeline::premul);
    395     }
    396     if (quality > kLow_SkFilterQuality) {
    397         // Bicubic filtering naturally produces out of range values on both sides.
    398         p->append(SkRasterPipeline::clamp_0);
    399         p->append(SkRasterPipeline::clamp_a);
    400     }
    401     append_gamut_transform(p, alloc, info.colorSpace(), dstCS, kPremul_SkAlphaType);
    402     return true;
    403 }
    404