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 */ 23static 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 34SkImageShader::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 41sk_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 53void 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 60bool SkImageShader::isOpaque() const { 61 return fImage->isOpaque(); 62} 63 64bool 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 87bool 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 93SkShaderBase::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 100SkImage* 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 112bool 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 132static 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 142sk_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 152void 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 174static 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 187std::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 245sk_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 252SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShaderBase) 253SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader) 254SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 255 256bool 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