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