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(const SkMatrix& ctm, SkColorType ct, SkAlphaType at,
     65                                          SkShader::TileMode tx, SkShader::TileMode ty,
     66                                          const SkMatrix& localM) {
     67     if (ct != kN32_SkColorType) {
     68         return true;
     69     }
     70     if (at == kUnpremul_SkAlphaType) {
     71         return true;
     72     }
     73 #ifndef SK_SUPPORT_LEGACY_TILED_BITMAPS
     74     if (tx != ty) {
     75         return true;
     76     }
     77 #endif
     78     if (!ctm.isScaleTranslate()) {
     79         return true;
     80     }
     81     if (!localM.isScaleTranslate()) {
     82         return true;
     83     }
     84     return false;
     85 }
     86 
     87 bool SkImageShader::onIsRasterPipelineOnly(const SkMatrix& ctm) const {
     88     SkBitmapProvider provider(fImage.get(), nullptr);
     89     return IsRasterPipelineOnly(ctm, provider.info().colorType(), provider.info().alphaType(),
     90                                 fTileModeX, fTileModeY, this->getLocalMatrix());
     91 }
     92 
     93 SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec,
     94                                                     SkArenaAlloc* alloc) const {
     95     return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY,
     96                                                  SkBitmapProvider(fImage.get(), rec.fDstColorSpace),
     97                                                  rec, alloc);
     98 }
     99 
    100 SkImage* SkImageShader::onIsAImage(SkMatrix* texM, TileMode xy[]) const {
    101     if (texM) {
    102         *texM = this->getLocalMatrix();
    103     }
    104     if (xy) {
    105         xy[0] = (TileMode)fTileModeX;
    106         xy[1] = (TileMode)fTileModeY;
    107     }
    108     return const_cast<SkImage*>(fImage.get());
    109 }
    110 
    111 #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
    112 bool SkImageShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
    113     const SkBitmap* bm = as_IB(fImage)->onPeekBitmap();
    114     if (!bm) {
    115         return false;
    116     }
    117 
    118     if (texture) {
    119         *texture = *bm;
    120     }
    121     if (texM) {
    122         *texM = this->getLocalMatrix();
    123     }
    124     if (xy) {
    125         xy[0] = (TileMode)fTileModeX;
    126         xy[1] = (TileMode)fTileModeY;
    127     }
    128     return true;
    129 }
    130 #endif
    131 
    132 static bool bitmap_is_too_big(int w, int h) {
    133     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
    134     // communicates between its matrix-proc and its sampler-proc. Until we can
    135     // widen that, we have to reject bitmaps that are larger.
    136     //
    137     static const int kMaxSize = 65535;
    138 
    139     return w > kMaxSize || h > kMaxSize;
    140 }
    141 
    142 sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, TileMode tx, TileMode ty,
    143                                     const SkMatrix* localMatrix) {
    144     if (!image || bitmap_is_too_big(image->width(), image->height())) {
    145         return sk_make_sp<SkEmptyShader>();
    146     } else {
    147         return sk_make_sp<SkImageShader>(image, tx, ty, localMatrix);
    148     }
    149 }
    150 
    151 #ifndef SK_IGNORE_TO_STRING
    152 void SkImageShader::toString(SkString* str) const {
    153     const char* gTileModeName[SkShader::kTileModeCount] = {
    154         "clamp", "repeat", "mirror"
    155     };
    156 
    157     str->appendf("ImageShader: ((%s %s) ", gTileModeName[fTileModeX], gTileModeName[fTileModeY]);
    158     fImage->toString(str);
    159     this->INHERITED::toString(str);
    160     str->append(")");
    161 }
    162 #endif
    163 
    164 ///////////////////////////////////////////////////////////////////////////////////////////////////
    165 
    166 #if SK_SUPPORT_GPU
    167 
    168 #include "GrColorSpaceInfo.h"
    169 #include "GrContext.h"
    170 #include "SkGr.h"
    171 #include "effects/GrBicubicEffect.h"
    172 #include "effects/GrSimpleTextureEffect.h"
    173 
    174 static GrSamplerState::WrapMode tile_mode_to_wrap_mode(const SkShader::TileMode tileMode) {
    175     switch (tileMode) {
    176         case SkShader::TileMode::kClamp_TileMode:
    177             return GrSamplerState::WrapMode::kClamp;
    178         case SkShader::TileMode::kRepeat_TileMode:
    179             return GrSamplerState::WrapMode::kRepeat;
    180         case SkShader::TileMode::kMirror_TileMode:
    181             return GrSamplerState::WrapMode::kMirrorRepeat;
    182     }
    183     SK_ABORT("Unknown tile mode.");
    184     return GrSamplerState::WrapMode::kClamp;
    185 }
    186 
    187 std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
    188         const GrFPArgs& args) const {
    189     SkMatrix lmInverse;
    190     if (!this->getLocalMatrix().invert(&lmInverse)) {
    191         return nullptr;
    192     }
    193     if (args.fLocalMatrix) {
    194         SkMatrix inv;
    195         if (!args.fLocalMatrix->invert(&inv)) {
    196             return nullptr;
    197         }
    198         lmInverse.postConcat(inv);
    199     }
    200 
    201     GrSamplerState::WrapMode wrapModes[] = {tile_mode_to_wrap_mode(fTileModeX),
    202                                             tile_mode_to_wrap_mode(fTileModeY)};
    203 
    204     // Must set wrap and filter on the sampler before requesting a texture. In two places below
    205     // we check the matrix scale factors to determine how to interpret the filter quality setting.
    206     // This completely ignores the complexity of the drawVertices case where explicit local coords
    207     // are provided by the caller.
    208     bool doBicubic;
    209     GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode(
    210             args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(), &doBicubic);
    211     GrSamplerState samplerState(wrapModes, textureFilterMode);
    212     sk_sp<SkColorSpace> texColorSpace;
    213     SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
    214     sk_sp<GrTextureProxy> proxy(as_IB(fImage)->asTextureProxyRef(
    215             args.fContext, samplerState, args.fDstColorSpaceInfo->colorSpace(), &texColorSpace,
    216             scaleAdjust));
    217     if (!proxy) {
    218         return nullptr;
    219     }
    220 
    221     GrPixelConfig config = proxy->config();
    222     bool isAlphaOnly = GrPixelConfigIsAlphaOnly(config);
    223 
    224     lmInverse.postScale(scaleAdjust[0], scaleAdjust[1]);
    225 
    226     std::unique_ptr<GrFragmentProcessor> inner;
    227     if (doBicubic) {
    228         inner = GrBicubicEffect::Make(std::move(proxy), lmInverse, wrapModes);
    229     } else {
    230         inner = GrSimpleTextureEffect::Make(std::move(proxy), lmInverse, samplerState);
    231     }
    232     inner = GrColorSpaceXformEffect::Make(std::move(inner), texColorSpace.get(), config,
    233                                           args.fDstColorSpaceInfo->colorSpace());
    234     if (isAlphaOnly) {
    235         return inner;
    236     }
    237     return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
    238 }
    239 
    240 #endif
    241 
    242 ///////////////////////////////////////////////////////////////////////////////////////////////////
    243 #include "SkImagePriv.h"
    244 
    245 sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
    246                                    SkShader::TileMode tmy, const SkMatrix* localMatrix,
    247                                    SkCopyPixelsMode cpm) {
    248     return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, cpm),
    249                                tmx, tmy, localMatrix);
    250 }
    251 
    252 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShaderBase)
    253 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader)
    254 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
    255 
    256 bool SkImageShader::onAppendStages(const StageRec& rec) const {
    257     SkRasterPipeline* p = rec.fPipeline;
    258     SkArenaAlloc* alloc = rec.fAlloc;
    259 
    260     auto matrix = SkMatrix::Concat(rec.fCTM, this->getLocalMatrix());
    261     if (rec.fLocalM) {
    262         matrix.preConcat(*rec.fLocalM);
    263     }
    264 
    265     if (!matrix.invert(&matrix)) {
    266         return false;
    267     }
    268     auto quality = rec.fPaint.getFilterQuality();
    269 
    270     SkBitmapProvider provider(fImage.get(), rec.fDstCS);
    271     SkDefaultBitmapController controller;
    272     std::unique_ptr<SkBitmapController::State> state {
    273         controller.requestBitmap(provider, matrix, quality)
    274     };
    275     if (!state) {
    276         return false;
    277     }
    278 
    279     const SkPixmap& pm = state->pixmap();
    280     matrix  = state->invMatrix();
    281     quality = state->quality();
    282     auto info = pm.info();
    283 
    284     // When the matrix is just an integer translate, bilerp == nearest neighbor.
    285     if (quality == kLow_SkFilterQuality &&
    286         matrix.getType() <= SkMatrix::kTranslate_Mask &&
    287         matrix.getTranslateX() == (int)matrix.getTranslateX() &&
    288         matrix.getTranslateY() == (int)matrix.getTranslateY()) {
    289         quality = kNone_SkFilterQuality;
    290     }
    291 
    292     // See skia:4649 and the GM image_scale_aligned.
    293     if (quality == kNone_SkFilterQuality) {
    294         if (matrix.getScaleX() >= 0) {
    295             matrix.setTranslateX(nextafterf(matrix.getTranslateX(),
    296                                             floorf(matrix.getTranslateX())));
    297         }
    298         if (matrix.getScaleY() >= 0) {
    299             matrix.setTranslateY(nextafterf(matrix.getTranslateY(),
    300                                             floorf(matrix.getTranslateY())));
    301         }
    302     }
    303 
    304     p->append_seed_shader();
    305 
    306     struct MiscCtx {
    307         std::unique_ptr<SkBitmapController::State> state;
    308         SkColor4f paint_color;
    309     };
    310     auto misc = alloc->make<MiscCtx>();
    311     misc->state       = std::move(state);  // Extend lifetime to match the pipeline's.
    312     misc->paint_color = SkColor4f_from_SkColor(rec.fPaint.getColor(), rec.fDstCS);
    313     p->append_matrix(alloc, matrix);
    314 
    315     auto gather = alloc->make<SkJumper_GatherCtx>();
    316     gather->pixels = pm.addr();
    317     gather->stride = pm.rowBytesAsPixels();
    318     gather->width  = pm.width();
    319     gather->height = pm.height();
    320 
    321     auto limit_x = alloc->make<SkJumper_TileCtx>(),
    322          limit_y = alloc->make<SkJumper_TileCtx>();
    323     limit_x->scale = pm.width();
    324     limit_x->invScale = 1.0f / pm.width();
    325     limit_y->scale = pm.height();
    326     limit_y->invScale = 1.0f / pm.height();
    327 
    328     bool is_srgb = rec.fDstCS && (!info.colorSpace() || info.gammaCloseToSRGB());
    329 
    330     auto append_tiling_and_gather = [&] {
    331         switch (fTileModeX) {
    332             case kClamp_TileMode:  /* The gather_xxx stage will clamp for us. */   break;
    333             case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, limit_x); break;
    334             case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, limit_x); break;
    335         }
    336         switch (fTileModeY) {
    337             case kClamp_TileMode:  /* The gather_xxx stage will clamp for us. */   break;
    338             case kMirror_TileMode: p->append(SkRasterPipeline::mirror_y, limit_y); break;
    339             case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_y, limit_y); break;
    340         }
    341         void* ctx = gather;
    342         switch (info.colorType()) {
    343             case kAlpha_8_SkColorType:      p->append(SkRasterPipeline::gather_a8,      ctx); break;
    344             case kGray_8_SkColorType:       p->append(SkRasterPipeline::gather_g8,      ctx); break;
    345             case kRGB_565_SkColorType:      p->append(SkRasterPipeline::gather_565,     ctx); break;
    346             case kARGB_4444_SkColorType:    p->append(SkRasterPipeline::gather_4444,    ctx); break;
    347             case kBGRA_8888_SkColorType:    p->append(SkRasterPipeline::gather_bgra,    ctx); break;
    348             case kRGBA_8888_SkColorType:    p->append(SkRasterPipeline::gather_8888,    ctx); break;
    349             case kRGBA_1010102_SkColorType: p->append(SkRasterPipeline::gather_1010102, ctx); break;
    350             case kRGBA_F16_SkColorType:     p->append(SkRasterPipeline::gather_f16,     ctx); break;
    351 
    352             case kRGB_888x_SkColorType:     p->append(SkRasterPipeline::gather_8888,    ctx);
    353                                             p->append(SkRasterPipeline::force_opaque       ); break;
    354             case kRGB_101010x_SkColorType:  p->append(SkRasterPipeline::gather_1010102, ctx);
    355                                             p->append(SkRasterPipeline::force_opaque       ); break;
    356 
    357             default: SkASSERT(false);
    358         }
    359         if (is_srgb) {
    360             p->append(SkRasterPipeline::from_srgb);
    361         }
    362     };
    363 
    364     auto append_misc = [&] {
    365         if (info.colorType() == kAlpha_8_SkColorType) {
    366             p->append(SkRasterPipeline::set_rgb, &misc->paint_color);
    367         }
    368         if (info.colorType() == kAlpha_8_SkColorType ||
    369             info.alphaType() == kUnpremul_SkAlphaType) {
    370             p->append(SkRasterPipeline::premul);
    371         }
    372 #if defined(SK_LEGACY_HIGH_QUALITY_SCALING_CLAMP)
    373         if (quality > kLow_SkFilterQuality) {
    374             // Bicubic filtering naturally produces out of range values on both sides.
    375             p->append(SkRasterPipeline::clamp_0);
    376             p->append(SkRasterPipeline::clamp_a);
    377         }
    378 #endif
    379         append_gamut_transform(p, alloc, info.colorSpace(), rec.fDstCS, kPremul_SkAlphaType);
    380         return true;
    381     };
    382 
    383     if (quality == kLow_SkFilterQuality            &&
    384         info.colorType() == kRGBA_8888_SkColorType &&
    385         fTileModeX == SkShader::kClamp_TileMode    &&
    386         fTileModeY == SkShader::kClamp_TileMode    &&
    387         !is_srgb) {
    388 
    389         p->append(SkRasterPipeline::bilerp_clamp_8888, gather);
    390         return append_misc();
    391     }
    392 
    393     SkJumper_SamplerCtx* sampler = nullptr;
    394     if (quality != kNone_SkFilterQuality) {
    395         sampler = alloc->make<SkJumper_SamplerCtx>();
    396     }
    397 
    398     auto sample = [&](SkRasterPipeline::StockStage setup_x,
    399                       SkRasterPipeline::StockStage setup_y) {
    400         p->append(setup_x, sampler);
    401         p->append(setup_y, sampler);
    402         append_tiling_and_gather();
    403         p->append(SkRasterPipeline::accumulate, sampler);
    404     };
    405 
    406     if (quality == kNone_SkFilterQuality) {
    407         append_tiling_and_gather();
    408 
    409     } else if (quality == kLow_SkFilterQuality) {
    410         p->append(SkRasterPipeline::save_xy, sampler);
    411 
    412         sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_ny);
    413         sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_ny);
    414         sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_py);
    415         sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_py);
    416 
    417         p->append(SkRasterPipeline::move_dst_src);
    418 
    419     } else {
    420         p->append(SkRasterPipeline::save_xy, sampler);
    421 
    422         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n3y);
    423         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n3y);
    424         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n3y);
    425         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n3y);
    426 
    427         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n1y);
    428         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n1y);
    429         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n1y);
    430         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n1y);
    431 
    432         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p1y);
    433         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p1y);
    434         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p1y);
    435         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p1y);
    436 
    437         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p3y);
    438         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p3y);
    439         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p3y);
    440         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p3y);
    441 
    442         p->append(SkRasterPipeline::move_dst_src);
    443     }
    444 
    445     return append_misc();
    446 }
    447