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