1 /* 2 * Copyright 2012 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 <cstddef> 9 #include <cstring> 10 #include <type_traits> 11 12 #include "SkAutoPixmapStorage.h" 13 #include "GrBackendSurface.h" 14 #include "GrBackendTextureImageGenerator.h" 15 #include "GrAHardwareBufferImageGenerator.h" 16 #include "GrBitmapTextureMaker.h" 17 #include "GrCaps.h" 18 #include "GrContext.h" 19 #include "GrContextPriv.h" 20 #include "GrGpu.h" 21 #include "GrImageTextureMaker.h" 22 #include "GrProxyProvider.h" 23 #include "GrRenderTargetContext.h" 24 #include "GrResourceProvider.h" 25 #include "GrSemaphore.h" 26 #include "GrSurfacePriv.h" 27 #include "GrTextureAdjuster.h" 28 #include "GrTexture.h" 29 #include "GrTexturePriv.h" 30 #include "GrTextureProxy.h" 31 #include "effects/GrNonlinearColorSpaceXformEffect.h" 32 #include "effects/GrYUVtoRGBEffect.h" 33 #include "SkCanvas.h" 34 #include "SkBitmapCache.h" 35 #include "SkGr.h" 36 #include "SkImage_Gpu.h" 37 #include "SkImageCacherator.h" 38 #include "SkImageInfoPriv.h" 39 #include "SkMipMap.h" 40 #include "SkPixelRef.h" 41 #include "SkReadPixelsRec.h" 42 #include "SkTraceEvent.h" 43 44 SkImage_Gpu::SkImage_Gpu(GrContext* context, uint32_t uniqueID, SkAlphaType at, 45 sk_sp<GrTextureProxy> proxy, 46 sk_sp<SkColorSpace> colorSpace, SkBudgeted budgeted) 47 : INHERITED(proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID) 48 , fContext(context) 49 , fProxy(std::move(proxy)) 50 , fAlphaType(at) 51 , fBudgeted(budgeted) 52 , fColorSpace(std::move(colorSpace)) 53 , fAddedRasterVersionToCache(false) { 54 } 55 56 SkImage_Gpu::~SkImage_Gpu() { 57 if (fAddedRasterVersionToCache.load()) { 58 SkNotifyBitmapGenIDIsStale(this->uniqueID()); 59 } 60 } 61 62 SkImageInfo SkImage_Gpu::onImageInfo() const { 63 SkColorType ct; 64 if (!GrPixelConfigToColorType(fProxy->config(), &ct)) { 65 ct = kUnknown_SkColorType; 66 } 67 return SkImageInfo::Make(fProxy->width(), fProxy->height(), ct, fAlphaType, fColorSpace); 68 } 69 70 bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const { 71 // The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap 72 // will be used. The client doesn't expect that we convert to that color space, it's intended 73 // for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly 74 // into that color space (to save the client some effort in whatever they're about to do), but 75 // that would make our use of the bitmap cache incorrect (or much less efficient, assuming we 76 // rolled the dstColorSpace into the key). 77 const auto desc = SkBitmapCacheDesc::Make(this); 78 if (SkBitmapCache::Find(desc, dst)) { 79 SkASSERT(dst->getGenerationID() == this->uniqueID()); 80 SkASSERT(dst->isImmutable()); 81 SkASSERT(dst->getPixels()); 82 return true; 83 } 84 85 SkBitmapCache::RecPtr rec = nullptr; 86 SkPixmap pmap; 87 if (kAllow_CachingHint == chint) { 88 rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap); 89 if (!rec) { 90 return false; 91 } 92 } else { 93 if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) { 94 return false; 95 } 96 } 97 98 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext( 99 fProxy, 100 fColorSpace); 101 if (!sContext) { 102 return false; 103 } 104 105 if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) { 106 return false; 107 } 108 109 if (rec) { 110 SkBitmapCache::Add(std::move(rec), dst); 111 fAddedRasterVersionToCache.store(true); 112 } 113 return true; 114 } 115 116 sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context, 117 const GrSamplerState& params, 118 SkColorSpace* dstColorSpace, 119 sk_sp<SkColorSpace>* texColorSpace, 120 SkScalar scaleAdjust[2]) const { 121 if (context != fContext) { 122 SkASSERT(0); 123 return nullptr; 124 } 125 126 GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->uniqueID(), 127 this->fColorSpace.get()); 128 return adjuster.refTextureProxyForParams(params, dstColorSpace, texColorSpace, scaleAdjust); 129 } 130 131 static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) { 132 switch (info.colorType()) { 133 case kRGBA_8888_SkColorType: 134 case kBGRA_8888_SkColorType: 135 break; 136 default: 137 return; // nothing to do 138 } 139 140 // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian, 141 // and in either case, the alpha-byte is always in the same place, so we can safely call 142 // SkPreMultiplyColor() 143 // 144 SkColor* row = (SkColor*)pixels; 145 for (int y = 0; y < info.height(); ++y) { 146 for (int x = 0; x < info.width(); ++x) { 147 row[x] = SkPreMultiplyColor(row[x]); 148 } 149 row = (SkColor*)((char*)(row) + rowBytes); 150 } 151 } 152 153 GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO, 154 GrSurfaceOrigin* origin) const { 155 SkASSERT(fProxy); 156 157 if (!fContext->contextPriv().resourceProvider() && !fProxy->priv().isInstantiated()) { 158 // This image was created with a DDL context and cannot be instantiated. Thus we return 0 159 // here which is considered invalid for all backends. 160 return 0; 161 } 162 163 if (GrSurfaceProxy::LazyState::kNot != fProxy->lazyInstantiationState()) { 164 SkASSERT(fContext->contextPriv().resourceProvider()); 165 fProxy->priv().doLazyInstantiation(fContext->contextPriv().resourceProvider()); 166 if (!fProxy->priv().isInstantiated()) { 167 // We failed to instantiate the lazy proxy. Thus we return 0 here which is considered 168 // invalid for all backends. 169 return 0; 170 } 171 } 172 173 if (!fProxy->instantiate(fContext->contextPriv().resourceProvider())) { 174 return 0; 175 } 176 177 GrTexture* texture = fProxy->priv().peekTexture(); 178 179 if (texture) { 180 if (flushPendingGrContextIO) { 181 fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get()); 182 } 183 if (origin) { 184 *origin = fProxy->origin(); 185 } 186 return texture->getTextureHandle(); 187 } 188 return 0; 189 } 190 191 GrTexture* SkImage_Gpu::onGetTexture() const { 192 GrTextureProxy* proxy = this->peekProxy(); 193 if (!proxy) { 194 return nullptr; 195 } 196 197 if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) { 198 return nullptr; 199 } 200 201 return proxy->priv().peekTexture(); 202 } 203 204 bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, 205 int srcX, int srcY, CachingHint) const { 206 if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) { 207 return false; 208 } 209 210 SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY); 211 if (!rec.trim(this->width(), this->height())) { 212 return false; 213 } 214 215 // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and 216 // GrRenderTargetContext::onReadPixels 217 uint32_t flags = 0; 218 if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) { 219 // let the GPU perform this transformation for us 220 flags = GrContextPriv::kUnpremul_PixelOpsFlag; 221 } 222 223 // This hack allows us to call makeNonTextureImage on images with arbitrary color spaces. 224 // Otherwise, we'll be unable to create a render target context. 225 // TODO: This shouldn't be necessary - we need more robust support for images (and surfaces) 226 // with arbitrary color spaces. Unfortunately, this is one spot where we go from image to 227 // surface (rather than the opposite), and our lenient image rules break our (currently) more 228 // strict surface rules. 229 // GrSurfaceContext::readPixels does not make use of the context's color space. However, we 230 // don't allow creating a surface context for a sRGB GrPixelConfig unless the color space has 231 // sRGB gamma. So we choose null for non-SRGB GrPixelConfigs and sRGB for sRGB GrPixelConfigs. 232 sk_sp<SkColorSpace> surfaceColorSpace = fColorSpace; 233 if (!flags) { 234 if (!dstInfo.colorSpace() || 235 SkColorSpace::Equals(fColorSpace.get(), dstInfo.colorSpace())) { 236 if (GrPixelConfigIsSRGB(fProxy->config())) { 237 surfaceColorSpace = SkColorSpace::MakeSRGB(); 238 } else { 239 surfaceColorSpace = nullptr; 240 } 241 } 242 } 243 244 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext( 245 fProxy, surfaceColorSpace); 246 if (!sContext) { 247 return false; 248 } 249 250 if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) { 251 return false; 252 } 253 254 // do we have to manually fix-up the alpha channel? 255 // src dst 256 // unpremul premul fix manually 257 // premul unpremul done by kUnpremul_PixelOpsFlag 258 // all other combos need to change. 259 // 260 // Should this be handled by Ganesh? todo:? 261 // 262 if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) { 263 apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes); 264 } 265 return true; 266 } 267 268 sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const { 269 GrSurfaceDesc desc; 270 desc.fOrigin = fProxy->origin(); 271 desc.fWidth = subset.width(); 272 desc.fHeight = subset.height(); 273 desc.fConfig = fProxy->config(); 274 275 sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext( 276 desc, 277 GrMipMapped::kNo, 278 SkBackingFit::kExact, 279 fBudgeted)); 280 if (!sContext) { 281 return nullptr; 282 } 283 284 if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) { 285 return nullptr; 286 } 287 288 // MDB: this call is okay bc we know 'sContext' was kExact 289 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, 290 fAlphaType, sContext->asTextureProxyRef(), 291 fColorSpace, fBudgeted); 292 } 293 294 /////////////////////////////////////////////////////////////////////////////////////////////////// 295 296 static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx, 297 const GrBackendTexture& backendTex, 298 GrSurfaceOrigin origin, 299 SkAlphaType at, sk_sp<SkColorSpace> colorSpace, 300 GrWrapOwnership ownership, 301 SkImage::TextureReleaseProc releaseProc, 302 SkImage::ReleaseContext releaseCtx) { 303 if (backendTex.width() <= 0 || backendTex.height() <= 0) { 304 return nullptr; 305 } 306 307 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider(); 308 sk_sp<GrTextureProxy> proxy = proxyProvider->createWrappedTextureProxy( 309 backendTex, origin, ownership, releaseProc, releaseCtx); 310 if (!proxy) { 311 return nullptr; 312 } 313 314 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID, 315 at, std::move(proxy), std::move(colorSpace), SkBudgeted::kNo); 316 } 317 318 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, 319 const GrBackendTexture& tex, GrSurfaceOrigin origin, 320 SkAlphaType at, sk_sp<SkColorSpace> cs, 321 TextureReleaseProc releaseP, ReleaseContext releaseC) { 322 if (!ctx) { 323 return nullptr; 324 } 325 return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kBorrow_GrWrapOwnership, 326 releaseP, releaseC); 327 } 328 329 bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config, 330 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs) { 331 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to 332 // create a fake image info here. 333 SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs); 334 if (!SkImageInfoIsValidAllowNumericalCS(info)) { 335 return false; 336 } 337 338 return ctx->caps()->validateBackendTexture(tex, ct, config); 339 } 340 341 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, 342 const GrBackendTexture& tex, GrSurfaceOrigin origin, 343 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs, 344 TextureReleaseProc releaseP, ReleaseContext releaseC) { 345 if (!ctx) { 346 return nullptr; 347 } 348 GrBackendTexture texCopy = tex; 349 if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) { 350 return nullptr; 351 } 352 return MakeFromTexture(ctx, texCopy, origin, at, cs, releaseP, releaseC); 353 } 354 355 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, 356 const GrBackendTexture& tex, GrSurfaceOrigin origin, 357 SkAlphaType at, sk_sp<SkColorSpace> cs) { 358 if (!ctx->contextPriv().resourceProvider()) { 359 // We have a DDL context and we don't support adopted textures for them. 360 return nullptr; 361 } 362 return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kAdopt_GrWrapOwnership, 363 nullptr, nullptr); 364 } 365 366 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, 367 const GrBackendTexture& tex, GrSurfaceOrigin origin, 368 SkColorType ct, SkAlphaType at, 369 sk_sp<SkColorSpace> cs) { 370 GrBackendTexture texCopy = tex; 371 if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) { 372 return nullptr; 373 } 374 return MakeFromAdoptedTexture(ctx, texCopy, origin, at, cs); 375 } 376 377 static GrBackendTexture make_backend_texture_from_handle(GrBackend backend, 378 int width, int height, 379 GrPixelConfig config, 380 GrBackendObject handle) { 381 switch (backend) { 382 case kOpenGL_GrBackend: { 383 const GrGLTextureInfo* glInfo = (const GrGLTextureInfo*)(handle); 384 return GrBackendTexture(width, height, config, *glInfo); 385 } 386 #ifdef SK_VULKAN 387 case kVulkan_GrBackend: { 388 const GrVkImageInfo* vkInfo = (const GrVkImageInfo*)(handle); 389 return GrBackendTexture(width, height, *vkInfo); 390 } 391 #endif 392 case kMock_GrBackend: { 393 const GrMockTextureInfo* mockInfo = (const GrMockTextureInfo*)(handle); 394 return GrBackendTexture(width, height, config, *mockInfo); 395 } 396 default: 397 return GrBackendTexture(); 398 } 399 } 400 401 static bool are_yuv_sizes_valid(const SkISize yuvSizes[], bool nv12) { 402 if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 || 403 yuvSizes[1].fWidth <= 0 || yuvSizes[1].fHeight <= 0) { 404 return false; 405 } 406 if (!nv12 && (yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0)) { 407 return false; 408 } 409 410 return true; 411 } 412 413 static sk_sp<SkImage> make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpace colorSpace, 414 bool nv12, 415 const GrBackendTexture yuvBackendTextures[], 416 const SkISize yuvSizes[], 417 GrSurfaceOrigin origin, 418 sk_sp<SkColorSpace> imageColorSpace) { 419 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider(); 420 421 if (!are_yuv_sizes_valid(yuvSizes, nv12)) { 422 return nullptr; 423 } 424 425 sk_sp<GrTextureProxy> yProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[0], 426 origin); 427 sk_sp<GrTextureProxy> uProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[1], 428 origin); 429 sk_sp<GrTextureProxy> vProxy; 430 431 if (nv12) { 432 vProxy = uProxy; 433 } else { 434 vProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[2], origin); 435 } 436 if (!yProxy || !uProxy || !vProxy) { 437 return nullptr; 438 } 439 440 const int width = yuvSizes[0].fWidth; 441 const int height = yuvSizes[0].fHeight; 442 443 // Needs to be a render target in order to draw to it for the yuv->rgb conversion. 444 sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext( 445 SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig, 446 std::move(imageColorSpace), 1, GrMipMapped::kNo, origin)); 447 if (!renderTargetContext) { 448 return nullptr; 449 } 450 451 GrPaint paint; 452 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 453 paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(yProxy, uProxy, vProxy, 454 yuvSizes, colorSpace, nv12)); 455 456 const SkRect rect = SkRect::MakeIWH(width, height); 457 458 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect); 459 460 if (!renderTargetContext->asSurfaceProxy()) { 461 return nullptr; 462 } 463 ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy()); 464 465 // MDB: this call is okay bc we know 'renderTargetContext' was exact 466 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID, kOpaque_SkAlphaType, 467 renderTargetContext->asTextureProxyRef(), 468 renderTargetContext->colorSpaceInfo().refColorSpace(), 469 SkBudgeted::kYes); 470 } 471 472 static sk_sp<SkImage> make_from_yuv_objects_copy(GrContext* ctx, SkYUVColorSpace colorSpace, 473 bool nv12, 474 const GrBackendObject yuvTextureHandles[], 475 const SkISize yuvSizes[], 476 GrSurfaceOrigin origin, 477 sk_sp<SkColorSpace> imageColorSpace) { 478 if (!are_yuv_sizes_valid(yuvSizes, nv12)) { 479 return nullptr; 480 } 481 482 GrBackendTexture backendTextures[3]; 483 484 const GrPixelConfig kConfig = nv12 ? kRGBA_8888_GrPixelConfig : kAlpha_8_GrPixelConfig; 485 486 GrBackend backend = ctx->contextPriv().getBackend(); 487 backendTextures[0] = make_backend_texture_from_handle(backend, 488 yuvSizes[0].fWidth, 489 yuvSizes[0].fHeight, 490 kConfig, 491 yuvTextureHandles[0]); 492 backendTextures[1] = make_backend_texture_from_handle(backend, 493 yuvSizes[1].fWidth, 494 yuvSizes[1].fHeight, 495 kConfig, 496 yuvTextureHandles[1]); 497 498 if (!nv12) { 499 backendTextures[2] = make_backend_texture_from_handle(backend, 500 yuvSizes[2].fWidth, 501 yuvSizes[2].fHeight, 502 kConfig, 503 yuvTextureHandles[2]); 504 } 505 506 return make_from_yuv_textures_copy(ctx, colorSpace, nv12, 507 backendTextures, yuvSizes, origin, 508 std::move(imageColorSpace)); 509 } 510 511 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace, 512 const GrBackendObject yuvTextureHandles[3], 513 const SkISize yuvSizes[3], GrSurfaceOrigin origin, 514 sk_sp<SkColorSpace> imageColorSpace) { 515 return make_from_yuv_objects_copy(ctx, colorSpace, false, yuvTextureHandles, yuvSizes, origin, 516 std::move(imageColorSpace)); 517 } 518 519 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace, 520 const GrBackendObject yuvTextureHandles[2], 521 const SkISize yuvSizes[2], 522 GrSurfaceOrigin origin, 523 sk_sp<SkColorSpace> imageColorSpace) { 524 return make_from_yuv_objects_copy(ctx, colorSpace, true, yuvTextureHandles, yuvSizes, origin, 525 std::move(imageColorSpace)); 526 } 527 528 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace, 529 const GrBackendTexture yuvBackendTextures[3], 530 const SkISize yuvSizes[3], GrSurfaceOrigin origin, 531 sk_sp<SkColorSpace> imageColorSpace) { 532 return make_from_yuv_textures_copy(ctx, colorSpace, false, yuvBackendTextures, yuvSizes, origin, 533 std::move(imageColorSpace)); 534 } 535 536 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace, 537 const GrBackendTexture yuvBackendTextures[2], 538 const SkISize yuvSizes[2], 539 GrSurfaceOrigin origin, 540 sk_sp<SkColorSpace> imageColorSpace) { 541 return make_from_yuv_textures_copy(ctx, colorSpace, true, yuvBackendTextures, yuvSizes, origin, 542 std::move(imageColorSpace)); 543 } 544 545 static sk_sp<SkImage> create_image_from_maker(GrContext* context, GrTextureMaker* maker, 546 SkAlphaType at, uint32_t id, 547 SkColorSpace* dstColorSpace) { 548 sk_sp<SkColorSpace> texColorSpace; 549 sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams( 550 GrSamplerState::ClampNearest(), dstColorSpace, &texColorSpace, nullptr)); 551 if (!proxy) { 552 return nullptr; 553 } 554 return sk_make_sp<SkImage_Gpu>(context, id, at, 555 std::move(proxy), std::move(texColorSpace), SkBudgeted::kNo); 556 } 557 558 sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const { 559 if (!context) { 560 return nullptr; 561 } 562 if (GrContext* incumbent = as_IB(this)->context()) { 563 return incumbent == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr; 564 } 565 566 if (this->isLazyGenerated()) { 567 GrImageTextureMaker maker(context, this, kDisallow_CachingHint); 568 return create_image_from_maker(context, &maker, this->alphaType(), 569 this->uniqueID(), dstColorSpace); 570 } 571 572 if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) { 573 GrBitmapTextureMaker maker(context, *bmp); 574 return create_image_from_maker(context, &maker, this->alphaType(), 575 this->uniqueID(), dstColorSpace); 576 } 577 return nullptr; 578 } 579 580 sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded, 581 bool buildMips, SkColorSpace* dstColorSpace) { 582 sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded)); 583 if (!codecImage) { 584 return nullptr; 585 } 586 587 // Some backends or drivers don't support (safely) moving resources between contexts 588 if (!context || !context->caps()->crossContextTextureSupport()) { 589 return codecImage; 590 } 591 592 // Turn the codec image into a GrTextureProxy 593 GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint); 594 sk_sp<SkColorSpace> texColorSpace; 595 GrSamplerState samplerState( 596 GrSamplerState::WrapMode::kClamp, 597 buildMips ? GrSamplerState::Filter::kMipMap : GrSamplerState::Filter::kBilerp); 598 sk_sp<GrTextureProxy> proxy( 599 maker.refTextureProxyForParams(samplerState, dstColorSpace, &texColorSpace, nullptr)); 600 if (!proxy) { 601 return codecImage; 602 } 603 604 if (!proxy->instantiate(context->contextPriv().resourceProvider())) { 605 return codecImage; 606 } 607 sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture()); 608 609 // Flush any writes or uploads 610 context->contextPriv().prepareSurfaceForExternalIO(proxy.get()); 611 612 GrGpu* gpu = context->contextPriv().getGpu(); 613 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get()); 614 615 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(), 616 std::move(sema), codecImage->alphaType(), 617 std::move(texColorSpace)); 618 return SkImage::MakeFromGenerator(std::move(gen)); 619 } 620 621 sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrContext* context, const SkPixmap& pixmap, 622 bool buildMips, SkColorSpace* dstColorSpace) { 623 // Some backends or drivers don't support (safely) moving resources between contexts 624 if (!context || !context->caps()->crossContextTextureSupport()) { 625 return SkImage::MakeRasterCopy(pixmap); 626 } 627 628 // If we don't have access to the resource provider and gpu (i.e. in a DDL context) we will not 629 // be able to make everything needed for a GPU CrossContext image. Thus return a raster copy 630 // instead. 631 if (!context->contextPriv().resourceProvider()) { 632 return SkImage::MakeRasterCopy(pixmap); 633 } 634 635 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 636 // Turn the pixmap into a GrTextureProxy 637 sk_sp<GrTextureProxy> proxy; 638 if (buildMips) { 639 SkBitmap bmp; 640 bmp.installPixels(pixmap); 641 proxy = proxyProvider->createMipMapProxyFromBitmap(bmp, dstColorSpace); 642 } else { 643 SkDestinationSurfaceColorMode colorMode = dstColorSpace 644 ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware 645 : SkDestinationSurfaceColorMode::kLegacy; 646 647 if (SkImageInfoIsValid(pixmap.info(), colorMode)) { 648 ATRACE_ANDROID_FRAMEWORK("Upload Texture [%ux%u]", pixmap.width(), pixmap.height()); 649 GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(pixmap.info(), *proxyProvider->caps()); 650 proxy = proxyProvider->createTextureProxy(desc, SkBudgeted::kYes, pixmap.addr(), 651 pixmap.rowBytes()); 652 } 653 } 654 655 if (!proxy) { 656 return SkImage::MakeRasterCopy(pixmap); 657 } 658 659 sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture()); 660 661 // Flush any writes or uploads 662 context->contextPriv().prepareSurfaceForExternalIO(proxy.get()); 663 GrGpu* gpu = context->contextPriv().getGpu(); 664 665 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get()); 666 667 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(), 668 std::move(sema), pixmap.alphaType(), 669 pixmap.info().refColorSpace()); 670 return SkImage::MakeFromGenerator(std::move(gen)); 671 } 672 673 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26 674 sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at, 675 sk_sp<SkColorSpace> cs) { 676 auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs); 677 return SkImage::MakeFromGenerator(std::move(gen)); 678 } 679 #endif 680 681 /////////////////////////////////////////////////////////////////////////////////////////////////// 682 683 bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx, 684 sk_sp<SkImage> image, 685 GrBackendTexture* backendTexture, 686 BackendTextureReleaseProc* releaseProc) { 687 if (!image || !ctx || !backendTexture || !releaseProc) { 688 return false; 689 } 690 691 // Ensure we have a texture backed image. 692 if (!image->isTextureBacked()) { 693 image = image->makeTextureImage(ctx, nullptr); 694 if (!image) { 695 return false; 696 } 697 } 698 GrTexture* texture = image->getTexture(); 699 if (!texture) { 700 // In context-loss cases, we may not have a texture. 701 return false; 702 } 703 704 // If the image's context doesn't match the provided context, fail. 705 if (texture->getContext() != ctx) { 706 return false; 707 } 708 709 // Flush any pending IO on the texture. 710 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy()); 711 SkASSERT(!texture->surfacePriv().hasPendingIO()); 712 713 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the 714 // image is not unique, or if the texture wraps an external object. 715 if (!image->unique() || !texture->surfacePriv().hasUniqueRef() || 716 texture->resourcePriv().refsWrappedObjects()) { 717 // onMakeSubset will always copy the image. 718 image = as_IB(image)->onMakeSubset(image->bounds()); 719 if (!image) { 720 return false; 721 } 722 723 texture = image->getTexture(); 724 if (!texture) { 725 return false; 726 } 727 728 // Flush to ensure that the copy is completed before we return the texture. 729 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy()); 730 SkASSERT(!texture->surfacePriv().hasPendingIO()); 731 } 732 733 SkASSERT(!texture->resourcePriv().refsWrappedObjects()); 734 SkASSERT(texture->surfacePriv().hasUniqueRef()); 735 SkASSERT(image->unique()); 736 737 // Take a reference to the GrTexture and release the image. 738 sk_sp<GrTexture> textureRef(SkSafeRef(texture)); 739 image = nullptr; 740 741 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process. 742 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc); 743 } 744 745 /////////////////////////////////////////////////////////////////////////////////////////////////// 746 747 sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> target, SkColorType, 748 SkTransferFunctionBehavior premulBehavior) const { 749 if (SkTransferFunctionBehavior::kRespect == premulBehavior) { 750 // TODO: Implement this. 751 return nullptr; 752 } 753 754 sk_sp<SkColorSpace> srcSpace = fColorSpace; 755 if (!fColorSpace) { 756 if (target->isSRGB()) { 757 return sk_ref_sp(const_cast<SkImage*>((SkImage*)this)); 758 } 759 760 srcSpace = SkColorSpace::MakeSRGB(); 761 } 762 763 auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), target.get()); 764 if (!xform) { 765 return sk_ref_sp(const_cast<SkImage_Gpu*>(this)); 766 } 767 768 sk_sp<GrRenderTargetContext> renderTargetContext(fContext->makeDeferredRenderTargetContext( 769 SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig, nullptr)); 770 if (!renderTargetContext) { 771 return nullptr; 772 } 773 774 GrPaint paint; 775 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 776 paint.addColorTextureProcessor(fProxy, SkMatrix::I()); 777 paint.addColorFragmentProcessor(std::move(xform)); 778 779 const SkRect rect = SkRect::MakeIWH(this->width(), this->height()); 780 781 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect); 782 783 if (!renderTargetContext->asTextureProxy()) { 784 return nullptr; 785 } 786 787 // MDB: this call is okay bc we know 'renderTargetContext' was exact 788 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, 789 fAlphaType, renderTargetContext->asTextureProxyRef(), 790 std::move(target), fBudgeted); 791 792 } 793 794 bool SkImage_Gpu::onIsValid(GrContext* context) const { 795 // The base class has already checked that context isn't abandoned (if it's not nullptr) 796 if (fContext->abandoned()) { 797 return false; 798 } 799 800 if (context && context != fContext) { 801 return false; 802 } 803 804 return true; 805 } 806