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