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