1 /* 2 * Copyright 2016 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 "SkSpecialImage.h" 9 #include "SkBitmap.h" 10 #include "SkImage.h" 11 #include "SkBitmapCache.h" 12 #include "SkCanvas.h" 13 #include "SkImage_Base.h" 14 #include "SkSpecialSurface.h" 15 #include "SkSurfacePriv.h" 16 #include <atomic> 17 18 #if SK_SUPPORT_GPU 19 #include "GrContext.h" 20 #include "GrContextPriv.h" 21 #include "GrProxyProvider.h" 22 #include "GrSurfaceContext.h" 23 #include "GrTextureProxy.h" 24 #include "SkImage_Gpu.h" 25 #endif 26 27 // Currently the raster imagefilters can only handle certain imageinfos. Call this to know if 28 // a given info is supported. 29 static bool valid_for_imagefilters(const SkImageInfo& info) { 30 // no support for other swizzles/depths yet 31 return info.colorType() == kN32_SkColorType; 32 } 33 34 /////////////////////////////////////////////////////////////////////////////// 35 class SkSpecialImage_Base : public SkSpecialImage { 36 public: 37 SkSpecialImage_Base(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps* props) 38 : INHERITED(subset, uniqueID, props) { 39 } 40 ~SkSpecialImage_Base() override { } 41 42 virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0; 43 44 virtual bool onGetROPixels(SkBitmap*) const = 0; 45 46 virtual GrContext* onGetContext() const { return nullptr; } 47 48 virtual SkColorSpace* onGetColorSpace() const = 0; 49 50 #if SK_SUPPORT_GPU 51 virtual sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext* context) const = 0; 52 #endif 53 54 virtual sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const = 0; 55 56 virtual sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps, 57 const SkISize& size, SkAlphaType at, 58 const SkSurfaceProps* = nullptr) const = 0; 59 60 virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0; 61 62 virtual sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps, 63 const SkISize& size, SkAlphaType at) const = 0; 64 65 private: 66 typedef SkSpecialImage INHERITED; 67 }; 68 69 /////////////////////////////////////////////////////////////////////////////// 70 static inline const SkSpecialImage_Base* as_SIB(const SkSpecialImage* image) { 71 return static_cast<const SkSpecialImage_Base*>(image); 72 } 73 74 SkSpecialImage::SkSpecialImage(const SkIRect& subset, 75 uint32_t uniqueID, 76 const SkSurfaceProps* props) 77 : fProps(SkSurfacePropsCopyOrDefault(props)) 78 , fSubset(subset) 79 , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) { 80 } 81 82 sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrContext* context) { 83 #if SK_SUPPORT_GPU 84 if (!context) { 85 return nullptr; 86 } 87 if (GrContext* curContext = as_SIB(this)->onGetContext()) { 88 return curContext == context ? sk_sp<SkSpecialImage>(SkRef(this)) : nullptr; 89 } 90 91 auto proxyProvider = context->contextPriv().proxyProvider(); 92 SkBitmap bmp; 93 // At this point, we are definitely not texture-backed, so we must be raster or generator 94 // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that 95 // we are strictly raster-backed (i.e. generator images become raster when they are specialized) 96 // in which case getROPixels could turn into peekPixels... 97 if (!this->getROPixels(&bmp)) { 98 return nullptr; 99 } 100 101 if (bmp.empty()) { 102 return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props()); 103 } 104 105 // TODO: this is a tight copy of 'bmp' but it doesn't have to be (given SkSpecialImage's 106 // semantics). Since this is cached though we would have to bake the fit into the cache key. 107 sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(proxyProvider, bmp); 108 if (!proxy) { 109 return nullptr; 110 } 111 112 const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height()); 113 114 // GrMakeCachedBitmapProxy has uploaded only the specified subset of 'bmp' so we need not 115 // bother with SkBitmap::getSubset 116 return SkSpecialImage::MakeDeferredFromGpu(context, 117 rect, 118 this->uniqueID(), 119 std::move(proxy), 120 sk_ref_sp(this->getColorSpace()), 121 &this->props(), 122 this->alphaType()); 123 #else 124 return nullptr; 125 #endif 126 } 127 128 void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const { 129 return as_SIB(this)->onDraw(canvas, x, y, paint); 130 } 131 132 bool SkSpecialImage::getROPixels(SkBitmap* bm) const { 133 return as_SIB(this)->onGetROPixels(bm); 134 } 135 136 bool SkSpecialImage::isTextureBacked() const { 137 return SkToBool(as_SIB(this)->onGetContext()); 138 } 139 140 GrContext* SkSpecialImage::getContext() const { 141 return as_SIB(this)->onGetContext(); 142 } 143 144 SkColorSpace* SkSpecialImage::getColorSpace() const { 145 return as_SIB(this)->onGetColorSpace(); 146 } 147 148 #if SK_SUPPORT_GPU 149 sk_sp<GrTextureProxy> SkSpecialImage::asTextureProxyRef(GrContext* context) const { 150 return as_SIB(this)->onAsTextureProxyRef(context); 151 } 152 #endif 153 154 sk_sp<SkSpecialSurface> SkSpecialImage::makeSurface(const SkImageFilter::OutputProperties& outProps, 155 const SkISize& size, SkAlphaType at, 156 const SkSurfaceProps* props) const { 157 return as_SIB(this)->onMakeSurface(outProps, size, at, props); 158 } 159 160 sk_sp<SkSurface> SkSpecialImage::makeTightSurface(const SkImageFilter::OutputProperties& outProps, 161 const SkISize& size, SkAlphaType at) const { 162 return as_SIB(this)->onMakeTightSurface(outProps, size, at); 163 } 164 165 sk_sp<SkSpecialImage> SkSpecialImage::makeSubset(const SkIRect& subset) const { 166 return as_SIB(this)->onMakeSubset(subset); 167 } 168 169 sk_sp<SkImage> SkSpecialImage::asImage(const SkIRect* subset) const { 170 return as_SIB(this)->onAsImage(subset); 171 } 172 173 #if defined(SK_DEBUG) || SK_SUPPORT_GPU 174 static bool rect_fits(const SkIRect& rect, int width, int height) { 175 if (0 == width && 0 == height) { 176 SkASSERT(0 == rect.fLeft && 0 == rect.fRight && 0 == rect.fTop && 0 == rect.fBottom); 177 return true; 178 } 179 180 return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight && 181 rect.fRight >= 0 && rect.fRight <= width && 182 rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom && 183 rect.fBottom >= 0 && rect.fBottom <= height; 184 } 185 #endif 186 187 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(GrContext* context, 188 const SkIRect& subset, 189 sk_sp<SkImage> image, 190 const SkSurfaceProps* props) { 191 SkASSERT(rect_fits(subset, image->width(), image->height())); 192 193 #if SK_SUPPORT_GPU 194 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef()) { 195 if (as_IB(image)->contextID() != context->contextPriv().contextID()) { 196 return nullptr; 197 } 198 199 return MakeDeferredFromGpu(context, subset, image->uniqueID(), std::move(proxy), 200 as_IB(image)->onImageInfo().refColorSpace(), props); 201 } else 202 #endif 203 { 204 SkBitmap bm; 205 if (as_IB(image)->getROPixels(&bm)) { 206 return MakeFromRaster(subset, bm, props); 207 } 208 } 209 return nullptr; 210 } 211 212 /////////////////////////////////////////////////////////////////////////////// 213 214 class SkSpecialImage_Raster : public SkSpecialImage_Base { 215 public: 216 SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm, const SkSurfaceProps* props) 217 : INHERITED(subset, bm.getGenerationID(), props) 218 , fBitmap(bm) 219 { 220 SkASSERT(bm.pixelRef()); 221 SkASSERT(fBitmap.getPixels()); 222 } 223 224 SkAlphaType alphaType() const override { return fBitmap.alphaType(); } 225 226 size_t getSize() const override { return fBitmap.computeByteSize(); } 227 228 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override { 229 SkRect dst = SkRect::MakeXYWH(x, y, 230 this->subset().width(), this->subset().height()); 231 232 canvas->drawBitmapRect(fBitmap, this->subset(), 233 dst, paint, SkCanvas::kStrict_SrcRectConstraint); 234 } 235 236 bool onGetROPixels(SkBitmap* bm) const override { 237 *bm = fBitmap; 238 return true; 239 } 240 241 SkColorSpace* onGetColorSpace() const override { 242 return fBitmap.colorSpace(); 243 } 244 245 #if SK_SUPPORT_GPU 246 sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext* context) const override { 247 if (context) { 248 return GrMakeCachedBitmapProxy(context->contextPriv().proxyProvider(), fBitmap); 249 } 250 251 return nullptr; 252 } 253 #endif 254 255 // TODO: The raster implementations of image filters all currently assume that the pixels are 256 // legacy N32. Until they actually check the format and operate on sRGB or F16 data appropriately, 257 // we can't enable this. (They will continue to produce incorrect results, but less-so). 258 #define RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16 0 259 260 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps, 261 const SkISize& size, SkAlphaType at, 262 const SkSurfaceProps* props) const override { 263 #if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16 264 SkColorSpace* colorSpace = outProps.colorSpace(); 265 #else 266 SkColorSpace* colorSpace = nullptr; 267 #endif 268 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear() 269 ? kRGBA_F16_SkColorType : kN32_SkColorType; 270 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at, 271 sk_ref_sp(colorSpace)); 272 return SkSpecialSurface::MakeRaster(info, props); 273 } 274 275 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override { 276 SkBitmap subsetBM; 277 278 if (!fBitmap.extractSubset(&subsetBM, subset)) { 279 return nullptr; 280 } 281 282 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(subset.width(), subset.height()), 283 subsetBM, 284 &this->props()); 285 } 286 287 sk_sp<SkImage> onAsImage(const SkIRect* subset) const override { 288 if (subset) { 289 SkBitmap subsetBM; 290 291 if (!fBitmap.extractSubset(&subsetBM, *subset)) { 292 return nullptr; 293 } 294 295 return SkImage::MakeFromBitmap(subsetBM); 296 } 297 298 return SkImage::MakeFromBitmap(fBitmap); 299 } 300 301 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps, 302 const SkISize& size, SkAlphaType at) const override { 303 #if RASTER_IMAGE_FILTERS_SUPPORT_SRGB_AND_F16 304 SkColorSpace* colorSpace = outProps.colorSpace(); 305 #else 306 SkColorSpace* colorSpace = nullptr; 307 #endif 308 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear() 309 ? kRGBA_F16_SkColorType : kN32_SkColorType; 310 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at, 311 sk_ref_sp(colorSpace)); 312 return SkSurface::MakeRaster(info); 313 } 314 315 private: 316 SkBitmap fBitmap; 317 318 typedef SkSpecialImage_Base INHERITED; 319 }; 320 321 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(const SkIRect& subset, 322 const SkBitmap& bm, 323 const SkSurfaceProps* props) { 324 SkASSERT(rect_fits(subset, bm.width(), bm.height())); 325 326 if (!bm.pixelRef()) { 327 return nullptr; 328 } 329 330 const SkBitmap* srcBM = &bm; 331 SkBitmap tmp; 332 // ImageFilters only handle N32 at the moment, so force our src to be that 333 if (!valid_for_imagefilters(bm.info())) { 334 if (!tmp.tryAllocPixels(bm.info().makeColorType(kN32_SkColorType)) || 335 !bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), 0, 0)) 336 { 337 return nullptr; 338 } 339 srcBM = &tmp; 340 } 341 return sk_make_sp<SkSpecialImage_Raster>(subset, *srcBM, props); 342 } 343 344 sk_sp<SkSpecialImage> SkSpecialImage::CopyFromRaster(const SkIRect& subset, 345 const SkBitmap& bm, 346 const SkSurfaceProps* props) { 347 SkASSERT(rect_fits(subset, bm.width(), bm.height())); 348 349 if (!bm.pixelRef()) { 350 return nullptr; 351 } 352 353 SkBitmap tmp; 354 if (!tmp.tryAllocPixels(bm.info().makeWH(subset.width(), subset.height()))) { 355 return nullptr; 356 } 357 if (!bm.readPixels(tmp.info(), tmp.getPixels(), tmp.rowBytes(), subset.x(), subset.y())) { 358 return nullptr; 359 } 360 return sk_make_sp<SkSpecialImage_Raster>(subset, tmp, props); 361 } 362 363 #if SK_SUPPORT_GPU 364 /////////////////////////////////////////////////////////////////////////////// 365 static sk_sp<SkImage> wrap_proxy_in_image(GrContext* context, sk_sp<GrTextureProxy> proxy, 366 SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) { 367 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, alphaType, 368 std::move(proxy), std::move(colorSpace)); 369 } 370 371 class SkSpecialImage_Gpu : public SkSpecialImage_Base { 372 public: 373 SkSpecialImage_Gpu(GrContext* context, const SkIRect& subset, 374 uint32_t uniqueID, sk_sp<GrTextureProxy> proxy, SkAlphaType at, 375 sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* props) 376 : INHERITED(subset, uniqueID, props) 377 , fContext(context) 378 , fTextureProxy(std::move(proxy)) 379 , fAlphaType(at) 380 , fColorSpace(std::move(colorSpace)) 381 , fAddedRasterVersionToCache(false) { 382 } 383 384 ~SkSpecialImage_Gpu() override { 385 if (fAddedRasterVersionToCache.load()) { 386 SkNotifyBitmapGenIDIsStale(this->uniqueID()); 387 } 388 } 389 390 SkAlphaType alphaType() const override { return fAlphaType; } 391 392 size_t getSize() const override { return fTextureProxy->gpuMemorySize(); } 393 394 void onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const override { 395 SkRect dst = SkRect::MakeXYWH(x, y, 396 this->subset().width(), this->subset().height()); 397 398 // TODO: In this instance we know we're going to draw a sub-portion of the backing 399 // texture into the canvas so it is okay to wrap it in an SkImage. This poses 400 // some problems for full deferral however in that when the deferred SkImage_Gpu 401 // instantiates itself it is going to have to either be okay with having a larger 402 // than expected backing texture (unlikely) or the 'fit' of the SurfaceProxy needs 403 // to be tightened (if it is deferred). 404 sk_sp<SkImage> img = 405 sk_sp<SkImage>(new SkImage_Gpu(sk_ref_sp(canvas->getGrContext()), this->uniqueID(), 406 fAlphaType, fTextureProxy, fColorSpace)); 407 408 canvas->drawImageRect(img, this->subset(), 409 dst, paint, SkCanvas::kStrict_SrcRectConstraint); 410 } 411 412 GrContext* onGetContext() const override { return fContext; } 413 414 sk_sp<GrTextureProxy> onAsTextureProxyRef(GrContext*) const override { 415 return fTextureProxy; 416 } 417 418 bool onGetROPixels(SkBitmap* dst) const override { 419 const auto desc = SkBitmapCacheDesc::Make(this->uniqueID(), this->subset()); 420 if (SkBitmapCache::Find(desc, dst)) { 421 SkASSERT(dst->getGenerationID() == this->uniqueID()); 422 SkASSERT(dst->isImmutable()); 423 SkASSERT(dst->getPixels()); 424 return true; 425 } 426 427 SkPixmap pmap; 428 SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(), 429 this->alphaType(), fColorSpace); 430 auto rec = SkBitmapCache::Alloc(desc, info, &pmap); 431 if (!rec) { 432 return false; 433 } 434 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext( 435 fTextureProxy, fColorSpace); 436 if (!sContext) { 437 return false; 438 } 439 440 if (!sContext->readPixels(info, pmap.writable_addr(), pmap.rowBytes(), 441 this->subset().left(), this->subset().top())) { 442 return false; 443 } 444 445 SkBitmapCache::Add(std::move(rec), dst); 446 fAddedRasterVersionToCache.store(true); 447 return true; 448 } 449 450 SkColorSpace* onGetColorSpace() const override { 451 return fColorSpace.get(); 452 } 453 454 sk_sp<SkSpecialSurface> onMakeSurface(const SkImageFilter::OutputProperties& outProps, 455 const SkISize& size, SkAlphaType at, 456 const SkSurfaceProps* props) const override { 457 if (!fContext) { 458 return nullptr; 459 } 460 461 GrBackendFormat format = 462 fContext->contextPriv().caps()->getBackendFormatFromColorType(outProps.colorType()); 463 464 return SkSpecialSurface::MakeRenderTarget( 465 fContext, format, size.width(), size.height(), 466 SkColorType2GrPixelConfig(outProps.colorType()), sk_ref_sp(outProps.colorSpace()), 467 props); 468 } 469 470 sk_sp<SkSpecialImage> onMakeSubset(const SkIRect& subset) const override { 471 return SkSpecialImage::MakeDeferredFromGpu(fContext, 472 subset, 473 this->uniqueID(), 474 fTextureProxy, 475 fColorSpace, 476 &this->props(), 477 fAlphaType); 478 } 479 480 // TODO: move all the logic here into the subset-flavor GrSurfaceProxy::copy? 481 sk_sp<SkImage> onAsImage(const SkIRect* subset) const override { 482 if (subset) { 483 // TODO: if this becomes a bottle neck we could base this logic on what the size 484 // will be when it is finally instantiated - but that is more fraught. 485 if (GrProxyProvider::IsFunctionallyExact(fTextureProxy.get()) && 486 0 == subset->fLeft && 0 == subset->fTop && 487 fTextureProxy->width() == subset->width() && 488 fTextureProxy->height() == subset->height()) { 489 fTextureProxy->priv().exactify(); 490 // The existing GrTexture is already tight so reuse it in the SkImage 491 return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace); 492 } 493 494 sk_sp<GrTextureProxy> subsetProxy( 495 GrSurfaceProxy::Copy(fContext, fTextureProxy.get(), GrMipMapped::kNo, *subset, 496 SkBackingFit::kExact, SkBudgeted::kYes)); 497 if (!subsetProxy) { 498 return nullptr; 499 } 500 501 SkASSERT(subsetProxy->priv().isExact()); 502 // MDB: this is acceptable (wrapping subsetProxy in an SkImage) bc Copy will 503 // return a kExact-backed proxy 504 return wrap_proxy_in_image(fContext, std::move(subsetProxy), fAlphaType, fColorSpace); 505 } 506 507 fTextureProxy->priv().exactify(); 508 509 return wrap_proxy_in_image(fContext, fTextureProxy, fAlphaType, fColorSpace); 510 } 511 512 sk_sp<SkSurface> onMakeTightSurface(const SkImageFilter::OutputProperties& outProps, 513 const SkISize& size, SkAlphaType at) const override { 514 SkColorSpace* colorSpace = outProps.colorSpace(); 515 SkColorType colorType = colorSpace && colorSpace->gammaIsLinear() 516 ? kRGBA_F16_SkColorType : kRGBA_8888_SkColorType; 517 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, at, 518 sk_ref_sp(colorSpace)); 519 return SkSurface::MakeRenderTarget(fContext, SkBudgeted::kYes, info); 520 } 521 522 private: 523 GrContext* fContext; 524 sk_sp<GrTextureProxy> fTextureProxy; 525 const SkAlphaType fAlphaType; 526 sk_sp<SkColorSpace> fColorSpace; 527 mutable std::atomic<bool> fAddedRasterVersionToCache; 528 529 typedef SkSpecialImage_Base INHERITED; 530 }; 531 532 sk_sp<SkSpecialImage> SkSpecialImage::MakeDeferredFromGpu(GrContext* context, 533 const SkIRect& subset, 534 uint32_t uniqueID, 535 sk_sp<GrTextureProxy> proxy, 536 sk_sp<SkColorSpace> colorSpace, 537 const SkSurfaceProps* props, 538 SkAlphaType at) { 539 if (!context || context->abandoned() || !proxy) { 540 return nullptr; 541 } 542 SkASSERT_RELEASE(rect_fits(subset, proxy->width(), proxy->height())); 543 return sk_make_sp<SkSpecialImage_Gpu>(context, subset, uniqueID, std::move(proxy), at, 544 std::move(colorSpace), props); 545 } 546 #endif 547