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