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 43 SkImage_Gpu::SkImage_Gpu(GrContext* context, uint32_t uniqueID, SkAlphaType at, 44 sk_sp<GrTextureProxy> proxy, 45 sk_sp<SkColorSpace> colorSpace, SkBudgeted budgeted) 46 : INHERITED(proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID) 47 , fContext(context) 48 , fProxy(std::move(proxy)) 49 , fAlphaType(at) 50 , fBudgeted(budgeted) 51 , fColorSpace(std::move(colorSpace)) 52 , fAddedRasterVersionToCache(false) { 53 } 54 55 SkImage_Gpu::~SkImage_Gpu() { 56 if (fAddedRasterVersionToCache.load()) { 57 SkNotifyBitmapGenIDIsStale(this->uniqueID()); 58 } 59 } 60 61 SkImageInfo SkImage_Gpu::onImageInfo() const { 62 SkColorType ct; 63 if (!GrPixelConfigToColorType(fProxy->config(), &ct)) { 64 ct = kUnknown_SkColorType; 65 } 66 return SkImageInfo::Make(fProxy->width(), fProxy->height(), ct, fAlphaType, fColorSpace); 67 } 68 69 bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const { 70 // The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap 71 // will be used. The client doesn't expect that we convert to that color space, it's intended 72 // for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly 73 // into that color space (to save the client some effort in whatever they're about to do), but 74 // that would make our use of the bitmap cache incorrect (or much less efficient, assuming we 75 // rolled the dstColorSpace into the key). 76 const auto desc = SkBitmapCacheDesc::Make(this); 77 if (SkBitmapCache::Find(desc, dst)) { 78 SkASSERT(dst->getGenerationID() == this->uniqueID()); 79 SkASSERT(dst->isImmutable()); 80 SkASSERT(dst->getPixels()); 81 return true; 82 } 83 84 SkBitmapCache::RecPtr rec = nullptr; 85 SkPixmap pmap; 86 if (kAllow_CachingHint == chint) { 87 rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap); 88 if (!rec) { 89 return false; 90 } 91 } else { 92 if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) { 93 return false; 94 } 95 } 96 97 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext( 98 fProxy, 99 fColorSpace); 100 if (!sContext) { 101 return false; 102 } 103 104 if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) { 105 return false; 106 } 107 108 if (rec) { 109 SkBitmapCache::Add(std::move(rec), dst); 110 fAddedRasterVersionToCache.store(true); 111 } 112 return true; 113 } 114 115 sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context, 116 const GrSamplerState& params, 117 SkColorSpace* dstColorSpace, 118 sk_sp<SkColorSpace>* texColorSpace, 119 SkScalar scaleAdjust[2]) const { 120 if (context != fContext) { 121 SkASSERT(0); 122 return nullptr; 123 } 124 125 if (texColorSpace) { 126 *texColorSpace = this->fColorSpace; 127 } 128 129 GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->uniqueID(), 130 this->fColorSpace.get()); 131 return adjuster.refTextureProxySafeForParams(params, scaleAdjust); 132 } 133 134 static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) { 135 switch (info.colorType()) { 136 case kRGBA_8888_SkColorType: 137 case kBGRA_8888_SkColorType: 138 break; 139 default: 140 return; // nothing to do 141 } 142 143 // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian, 144 // and in either case, the alpha-byte is always in the same place, so we can safely call 145 // SkPreMultiplyColor() 146 // 147 SkColor* row = (SkColor*)pixels; 148 for (int y = 0; y < info.height(); ++y) { 149 for (int x = 0; x < info.width(); ++x) { 150 row[x] = SkPreMultiplyColor(row[x]); 151 } 152 } 153 } 154 155 GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO, 156 GrSurfaceOrigin* origin) const { 157 SkASSERT(fProxy); 158 159 if (!fContext->contextPriv().resourceProvider() && !fProxy->priv().isInstantiated()) { 160 // This image was created with a DDL context and cannot be instantiated. Thus we return 0 161 // here which is considered invalid for all backends. 162 return 0; 163 } 164 165 if (GrSurfaceProxy::LazyState::kNot != fProxy->lazyInstantiationState()) { 166 SkASSERT(fContext->contextPriv().resourceProvider()); 167 fProxy->priv().doLazyInstantiation(fContext->contextPriv().resourceProvider()); 168 if (!fProxy->priv().isInstantiated()) { 169 // We failed to instantiate the lazy proxy. Thus we return 0 here which is considered 170 // invalid for all backends. 171 return 0; 172 } 173 } 174 175 if (!fProxy->instantiate(fContext->contextPriv().resourceProvider())) { 176 return 0; 177 } 178 179 GrTexture* texture = fProxy->priv().peekTexture(); 180 181 if (texture) { 182 if (flushPendingGrContextIO) { 183 fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get()); 184 } 185 if (origin) { 186 *origin = fProxy->origin(); 187 } 188 return texture->getTextureHandle(); 189 } 190 return 0; 191 } 192 193 GrTexture* SkImage_Gpu::onGetTexture() const { 194 GrTextureProxy* proxy = this->peekProxy(); 195 if (!proxy) { 196 return nullptr; 197 } 198 199 if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) { 200 return nullptr; 201 } 202 203 return proxy->priv().peekTexture(); 204 } 205 206 bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, 207 int srcX, int srcY, CachingHint) const { 208 if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) { 209 return false; 210 } 211 212 SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY); 213 if (!rec.trim(this->width(), this->height())) { 214 return false; 215 } 216 217 // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and 218 // GrRenderTargetContext::onReadPixels 219 uint32_t flags = 0; 220 if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) { 221 // let the GPU perform this transformation for us 222 flags = GrContextPriv::kUnpremul_PixelOpsFlag; 223 } 224 225 // This hack allows us to call makeNonTextureImage on images with arbitrary color spaces. 226 // Otherwise, we'll be unable to create a render target context. 227 // TODO: This shouldn't be necessary - we need more robust support for images (and surfaces) 228 // with arbitrary color spaces. Unfortunately, this is one spot where we go from image to 229 // surface (rather than the opposite), and our lenient image rules break our (currently) more 230 // strict surface rules. 231 // We treat null-dst color space as always equal to fColorSpace for this kind of read-back. 232 sk_sp<SkColorSpace> surfaceColorSpace = fColorSpace; 233 if (!flags) { 234 if (!dstInfo.colorSpace() || 235 SkColorSpace::Equals(fColorSpace.get(), dstInfo.colorSpace())) { 236 surfaceColorSpace = nullptr; 237 } 238 } 239 240 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext( 241 fProxy, surfaceColorSpace); 242 if (!sContext) { 243 return false; 244 } 245 246 if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) { 247 return false; 248 } 249 250 // do we have to manually fix-up the alpha channel? 251 // src dst 252 // unpremul premul fix manually 253 // premul unpremul done by kUnpremul_PixelOpsFlag 254 // all other combos need to change. 255 // 256 // Should this be handled by Ganesh? todo:? 257 // 258 if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) { 259 apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes); 260 } 261 return true; 262 } 263 264 sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const { 265 GrSurfaceDesc desc; 266 desc.fOrigin = fProxy->origin(); 267 desc.fWidth = subset.width(); 268 desc.fHeight = subset.height(); 269 desc.fConfig = fProxy->config(); 270 271 sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext( 272 desc, 273 GrMipMapped::kNo, 274 SkBackingFit::kExact, 275 fBudgeted)); 276 if (!sContext) { 277 return nullptr; 278 } 279 280 if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) { 281 return nullptr; 282 } 283 284 // MDB: this call is okay bc we know 'sContext' was kExact 285 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, 286 fAlphaType, sContext->asTextureProxyRef(), 287 fColorSpace, fBudgeted); 288 } 289 290 /////////////////////////////////////////////////////////////////////////////////////////////////// 291 292 static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx, 293 const GrBackendTexture& backendTex, 294 GrSurfaceOrigin origin, 295 SkAlphaType at, sk_sp<SkColorSpace> colorSpace, 296 GrWrapOwnership ownership, 297 SkImage::TextureReleaseProc releaseProc, 298 SkImage::ReleaseContext releaseCtx) { 299 if (backendTex.width() <= 0 || backendTex.height() <= 0) { 300 return nullptr; 301 } 302 303 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider(); 304 sk_sp<GrTextureProxy> proxy = proxyProvider->createWrappedTextureProxy( 305 backendTex, origin, ownership, releaseProc, releaseCtx); 306 if (!proxy) { 307 return nullptr; 308 } 309 310 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID, 311 at, std::move(proxy), std::move(colorSpace), SkBudgeted::kNo); 312 } 313 314 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, 315 const GrBackendTexture& tex, GrSurfaceOrigin origin, 316 SkAlphaType at, sk_sp<SkColorSpace> cs, 317 TextureReleaseProc releaseP, ReleaseContext releaseC) { 318 if (!ctx) { 319 return nullptr; 320 } 321 return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kBorrow_GrWrapOwnership, 322 releaseP, releaseC); 323 } 324 325 bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config, 326 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs) { 327 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to 328 // create a fake image info here. 329 SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs); 330 if (!SkImageInfoIsValidAllowNumericalCS(info)) { 331 return false; 332 } 333 334 return ctx->caps()->validateBackendTexture(tex, ct, config); 335 } 336 337 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, 338 const GrBackendTexture& tex, GrSurfaceOrigin origin, 339 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs, 340 TextureReleaseProc releaseP, ReleaseContext releaseC) { 341 if (!ctx) { 342 return nullptr; 343 } 344 GrBackendTexture texCopy = tex; 345 if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) { 346 return nullptr; 347 } 348 return MakeFromTexture(ctx, texCopy, origin, at, cs, releaseP, releaseC); 349 } 350 351 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, 352 const GrBackendTexture& tex, GrSurfaceOrigin origin, 353 SkAlphaType at, sk_sp<SkColorSpace> cs) { 354 if (!ctx->contextPriv().resourceProvider()) { 355 // We have a DDL context and we don't support adopted textures for them. 356 return nullptr; 357 } 358 return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kAdopt_GrWrapOwnership, 359 nullptr, nullptr); 360 } 361 362 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, 363 const GrBackendTexture& tex, GrSurfaceOrigin origin, 364 SkColorType ct, SkAlphaType at, 365 sk_sp<SkColorSpace> cs) { 366 GrBackendTexture texCopy = tex; 367 if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) { 368 return nullptr; 369 } 370 return MakeFromAdoptedTexture(ctx, texCopy, origin, at, cs); 371 } 372 373 static GrBackendTexture make_backend_texture_from_handle(GrBackend backend, 374 int width, int height, 375 GrPixelConfig config, 376 GrBackendObject handle) { 377 switch (backend) { 378 case kOpenGL_GrBackend: { 379 const GrGLTextureInfo* glInfo = (const GrGLTextureInfo*)(handle); 380 return GrBackendTexture(width, height, config, *glInfo); 381 } 382 #ifdef SK_VULKAN 383 case kVulkan_GrBackend: { 384 const GrVkImageInfo* vkInfo = (const GrVkImageInfo*)(handle); 385 return GrBackendTexture(width, height, *vkInfo); 386 } 387 #endif 388 case kMock_GrBackend: { 389 const GrMockTextureInfo* mockInfo = (const GrMockTextureInfo*)(handle); 390 return GrBackendTexture(width, height, config, *mockInfo); 391 } 392 default: 393 return GrBackendTexture(); 394 } 395 } 396 397 static bool are_yuv_sizes_valid(const SkISize yuvSizes[], bool nv12) { 398 if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 || 399 yuvSizes[1].fWidth <= 0 || yuvSizes[1].fHeight <= 0) { 400 return false; 401 } 402 if (!nv12 && (yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0)) { 403 return false; 404 } 405 406 return true; 407 } 408 409 static sk_sp<SkImage> make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpace colorSpace, 410 bool nv12, 411 const GrBackendTexture yuvBackendTextures[], 412 const SkISize yuvSizes[], 413 GrSurfaceOrigin origin, 414 sk_sp<SkColorSpace> imageColorSpace) { 415 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider(); 416 417 if (!are_yuv_sizes_valid(yuvSizes, nv12)) { 418 return nullptr; 419 } 420 421 sk_sp<GrTextureProxy> yProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[0], 422 origin); 423 sk_sp<GrTextureProxy> uProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[1], 424 origin); 425 sk_sp<GrTextureProxy> vProxy; 426 427 if (nv12) { 428 vProxy = uProxy; 429 } else { 430 vProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[2], origin); 431 } 432 if (!yProxy || !uProxy || !vProxy) { 433 return nullptr; 434 } 435 436 const int width = yuvSizes[0].fWidth; 437 const int height = yuvSizes[0].fHeight; 438 439 // Needs to be a render target in order to draw to it for the yuv->rgb conversion. 440 sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext( 441 SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig, 442 std::move(imageColorSpace), 1, GrMipMapped::kNo, origin)); 443 if (!renderTargetContext) { 444 return nullptr; 445 } 446 447 GrPaint paint; 448 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 449 paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(yProxy, uProxy, vProxy, 450 yuvSizes, colorSpace, nv12)); 451 452 const SkRect rect = SkRect::MakeIWH(width, height); 453 454 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect); 455 456 if (!renderTargetContext->asSurfaceProxy()) { 457 return nullptr; 458 } 459 ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy()); 460 461 // MDB: this call is okay bc we know 'renderTargetContext' was exact 462 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID, kOpaque_SkAlphaType, 463 renderTargetContext->asTextureProxyRef(), 464 renderTargetContext->colorSpaceInfo().refColorSpace(), 465 SkBudgeted::kYes); 466 } 467 468 static sk_sp<SkImage> make_from_yuv_objects_copy(GrContext* ctx, SkYUVColorSpace colorSpace, 469 bool nv12, 470 const GrBackendObject yuvTextureHandles[], 471 const SkISize yuvSizes[], 472 GrSurfaceOrigin origin, 473 sk_sp<SkColorSpace> imageColorSpace) { 474 if (!are_yuv_sizes_valid(yuvSizes, nv12)) { 475 return nullptr; 476 } 477 478 GrBackendTexture backendTextures[3]; 479 480 const GrPixelConfig kConfig = nv12 ? kRGBA_8888_GrPixelConfig : kAlpha_8_GrPixelConfig; 481 482 GrBackend backend = ctx->contextPriv().getBackend(); 483 backendTextures[0] = make_backend_texture_from_handle(backend, 484 yuvSizes[0].fWidth, 485 yuvSizes[0].fHeight, 486 kConfig, 487 yuvTextureHandles[0]); 488 backendTextures[1] = make_backend_texture_from_handle(backend, 489 yuvSizes[1].fWidth, 490 yuvSizes[1].fHeight, 491 kConfig, 492 yuvTextureHandles[1]); 493 494 if (!nv12) { 495 backendTextures[2] = make_backend_texture_from_handle(backend, 496 yuvSizes[2].fWidth, 497 yuvSizes[2].fHeight, 498 kConfig, 499 yuvTextureHandles[2]); 500 } 501 502 return make_from_yuv_textures_copy(ctx, colorSpace, nv12, 503 backendTextures, yuvSizes, origin, 504 std::move(imageColorSpace)); 505 } 506 507 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace, 508 const GrBackendObject yuvTextureHandles[3], 509 const SkISize yuvSizes[3], GrSurfaceOrigin origin, 510 sk_sp<SkColorSpace> imageColorSpace) { 511 return make_from_yuv_objects_copy(ctx, colorSpace, false, yuvTextureHandles, yuvSizes, origin, 512 std::move(imageColorSpace)); 513 } 514 515 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace, 516 const GrBackendObject yuvTextureHandles[2], 517 const SkISize yuvSizes[2], 518 GrSurfaceOrigin origin, 519 sk_sp<SkColorSpace> imageColorSpace) { 520 return make_from_yuv_objects_copy(ctx, colorSpace, true, yuvTextureHandles, yuvSizes, origin, 521 std::move(imageColorSpace)); 522 } 523 524 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace, 525 const GrBackendTexture yuvBackendTextures[3], 526 const SkISize yuvSizes[3], GrSurfaceOrigin origin, 527 sk_sp<SkColorSpace> imageColorSpace) { 528 return make_from_yuv_textures_copy(ctx, colorSpace, false, yuvBackendTextures, yuvSizes, origin, 529 std::move(imageColorSpace)); 530 } 531 532 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace, 533 const GrBackendTexture yuvBackendTextures[2], 534 const SkISize yuvSizes[2], 535 GrSurfaceOrigin origin, 536 sk_sp<SkColorSpace> imageColorSpace) { 537 return make_from_yuv_textures_copy(ctx, colorSpace, true, yuvBackendTextures, yuvSizes, origin, 538 std::move(imageColorSpace)); 539 } 540 541 static sk_sp<SkImage> create_image_from_maker(GrContext* context, GrTextureMaker* maker, 542 SkAlphaType at, uint32_t id, 543 SkColorSpace* dstColorSpace) { 544 sk_sp<SkColorSpace> texColorSpace; 545 sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams( 546 GrSamplerState::ClampNearest(), dstColorSpace, &texColorSpace, nullptr)); 547 if (!proxy) { 548 return nullptr; 549 } 550 return sk_make_sp<SkImage_Gpu>(context, id, at, 551 std::move(proxy), std::move(texColorSpace), SkBudgeted::kNo); 552 } 553 554 sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const { 555 if (!context) { 556 return nullptr; 557 } 558 if (GrContext* incumbent = as_IB(this)->context()) { 559 return incumbent == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr; 560 } 561 562 if (this->isLazyGenerated()) { 563 GrImageTextureMaker maker(context, this, kDisallow_CachingHint); 564 return create_image_from_maker(context, &maker, this->alphaType(), 565 this->uniqueID(), dstColorSpace); 566 } 567 568 if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) { 569 GrBitmapTextureMaker maker(context, *bmp); 570 return create_image_from_maker(context, &maker, this->alphaType(), 571 this->uniqueID(), dstColorSpace); 572 } 573 return nullptr; 574 } 575 576 sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded, 577 bool buildMips, SkColorSpace* dstColorSpace) { 578 sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded)); 579 if (!codecImage) { 580 return nullptr; 581 } 582 583 // Some backends or drivers don't support (safely) moving resources between contexts 584 if (!context || !context->caps()->crossContextTextureSupport()) { 585 return codecImage; 586 } 587 588 // Turn the codec image into a GrTextureProxy 589 GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint); 590 sk_sp<SkColorSpace> texColorSpace; 591 GrSamplerState samplerState( 592 GrSamplerState::WrapMode::kClamp, 593 buildMips ? GrSamplerState::Filter::kMipMap : GrSamplerState::Filter::kBilerp); 594 sk_sp<GrTextureProxy> proxy( 595 maker.refTextureProxyForParams(samplerState, dstColorSpace, &texColorSpace, nullptr)); 596 if (!proxy) { 597 return codecImage; 598 } 599 600 if (!proxy->instantiate(context->contextPriv().resourceProvider())) { 601 return codecImage; 602 } 603 sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture()); 604 605 // Flush any writes or uploads 606 context->contextPriv().prepareSurfaceForExternalIO(proxy.get()); 607 608 GrGpu* gpu = context->contextPriv().getGpu(); 609 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get()); 610 611 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(), 612 std::move(sema), codecImage->alphaType(), 613 std::move(texColorSpace)); 614 return SkImage::MakeFromGenerator(std::move(gen)); 615 } 616 617 sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrContext* context, const SkPixmap& pixmap, 618 bool buildMips, SkColorSpace* dstColorSpace) { 619 // Some backends or drivers don't support (safely) moving resources between contexts 620 if (!context || !context->caps()->crossContextTextureSupport()) { 621 return SkImage::MakeRasterCopy(pixmap); 622 } 623 624 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 625 // Turn the pixmap into a GrTextureProxy 626 sk_sp<GrTextureProxy> proxy; 627 if (buildMips) { 628 SkBitmap bmp; 629 bmp.installPixels(pixmap); 630 proxy = GrGenerateMipMapsAndUploadToTextureProxy(proxyProvider, bmp, dstColorSpace); 631 } else { 632 proxy = GrUploadPixmapToTextureProxy(proxyProvider, pixmap, SkBudgeted::kYes, 633 dstColorSpace); 634 } 635 636 if (!proxy) { 637 return SkImage::MakeRasterCopy(pixmap); 638 } 639 640 sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture()); 641 642 // Flush any writes or uploads 643 context->contextPriv().prepareSurfaceForExternalIO(proxy.get()); 644 GrGpu* gpu = context->contextPriv().getGpu(); 645 646 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get()); 647 648 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(), 649 std::move(sema), pixmap.alphaType(), 650 pixmap.info().refColorSpace()); 651 return SkImage::MakeFromGenerator(std::move(gen)); 652 } 653 654 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26 655 sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at, 656 sk_sp<SkColorSpace> cs) { 657 auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs); 658 return SkImage::MakeFromGenerator(std::move(gen)); 659 } 660 #endif 661 662 /////////////////////////////////////////////////////////////////////////////////////////////////// 663 664 namespace { 665 struct MipMapLevelData { 666 void* fPixelData; 667 size_t fRowBytes; 668 }; 669 670 struct DeferredTextureImage { 671 uint32_t fContextUniqueID; 672 // Right now, the destination color mode is only considered when generating mipmaps 673 SkDestinationSurfaceColorMode fColorMode; 674 // We don't store a SkImageInfo because it contains a ref-counted SkColorSpace. 675 int fWidth; 676 int fHeight; 677 SkColorType fColorType; 678 SkAlphaType fAlphaType; 679 void* fColorSpace; 680 size_t fColorSpaceSize; 681 int fMipMapLevelCount; 682 // The fMipMapLevelData array may contain more than 1 element. 683 // It contains fMipMapLevelCount elements. 684 // That means this struct's size is not known at compile-time. 685 MipMapLevelData fMipMapLevelData[1]; 686 }; 687 } // anonymous namespace 688 689 static bool should_use_mip_maps(const SkImage::DeferredTextureImageUsageParams & param) { 690 // There is a bug in the mipmap pre-generation logic in use in getDeferredTextureImageData. 691 // This can cause runaway memory leaks, so we are disabling this path until we can 692 // investigate further. crbug.com/669775 693 return false; 694 } 695 696 namespace { 697 698 class DTIBufferFiller 699 { 700 public: 701 explicit DTIBufferFiller(char* bufferAsCharPtr) 702 : bufferAsCharPtr_(bufferAsCharPtr) {} 703 704 void fillMember(const void* source, size_t memberOffset, size_t size) { 705 memcpy(bufferAsCharPtr_ + memberOffset, source, size); 706 } 707 708 private: 709 710 char* bufferAsCharPtr_; 711 }; 712 } 713 714 #define FILL_MEMBER(bufferFiller, member, source) \ 715 bufferFiller.fillMember(source, \ 716 offsetof(DeferredTextureImage, member), \ 717 sizeof(DeferredTextureImage::member)); 718 719 static bool SupportsColorSpace(SkColorType colorType) { 720 switch (colorType) { 721 case kRGBA_8888_SkColorType: 722 case kBGRA_8888_SkColorType: 723 case kRGBA_F16_SkColorType: 724 return true; 725 default: 726 return false; 727 } 728 } 729 730 size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy, 731 const DeferredTextureImageUsageParams params[], 732 int paramCnt, void* buffer, 733 SkColorSpace* dstColorSpace, 734 SkColorType dstColorType) const { 735 // Some quick-rejects where is makes no sense to return CPU data 736 // e.g. 737 // - texture backed 738 // - picture backed 739 // 740 if (this->isTextureBacked()) { 741 return 0; 742 } 743 if (as_IB(this)->onCanLazyGenerateOnGPU()) { 744 return 0; 745 } 746 747 bool supportsColorSpace = SupportsColorSpace(dstColorType); 748 // Quick reject if the caller requests a color space with an unsupported color type. 749 if (SkToBool(dstColorSpace) && !supportsColorSpace) { 750 return 0; 751 } 752 753 // Extract relevant min/max values from the params array. 754 int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel; 755 SkFilterQuality highestFilterQuality = params[0].fQuality; 756 bool useMipMaps = should_use_mip_maps(params[0]); 757 for (int i = 1; i < paramCnt; ++i) { 758 if (lowestPreScaleMipLevel > params[i].fPreScaleMipLevel) 759 lowestPreScaleMipLevel = params[i].fPreScaleMipLevel; 760 if (highestFilterQuality < params[i].fQuality) 761 highestFilterQuality = params[i].fQuality; 762 useMipMaps |= should_use_mip_maps(params[i]); 763 } 764 765 const bool fillMode = SkToBool(buffer); 766 if (fillMode && !SkIsAlign8(reinterpret_cast<intptr_t>(buffer))) { 767 return 0; 768 } 769 770 // Calculate scaling parameters. 771 bool isScaled = lowestPreScaleMipLevel != 0; 772 773 SkISize scaledSize; 774 if (isScaled) { 775 // SkMipMap::ComputeLevelSize takes an index into an SkMipMap. SkMipMaps don't contain the 776 // base level, so to get an SkMipMap index we must subtract one from the GL MipMap level. 777 scaledSize = SkMipMap::ComputeLevelSize(this->width(), this->height(), 778 lowestPreScaleMipLevel - 1); 779 } else { 780 scaledSize = SkISize::Make(this->width(), this->height()); 781 } 782 783 // We never want to scale at higher than SW medium quality, as SW medium matches GPU high. 784 SkFilterQuality scaleFilterQuality = highestFilterQuality; 785 if (scaleFilterQuality > kMedium_SkFilterQuality) { 786 scaleFilterQuality = kMedium_SkFilterQuality; 787 } 788 789 const int maxTextureSize = proxy.fCaps->maxTextureSize(); 790 if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) { 791 return 0; 792 } 793 794 SkAutoPixmapStorage pixmap; 795 SkImageInfo info; 796 size_t pixelSize = 0; 797 if (!isScaled && this->peekPixels(&pixmap) && pixmap.info().colorType() == dstColorType) { 798 info = pixmap.info(); 799 pixelSize = SkAlign8(pixmap.computeByteSize()); 800 if (!dstColorSpace) { 801 pixmap.setColorSpace(nullptr); 802 info = info.makeColorSpace(nullptr); 803 } 804 } else { 805 if (!this->isLazyGenerated() && !this->peekPixels(nullptr)) { 806 return 0; 807 } 808 if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) { 809 // Generator backed image. Tweak info to trigger correct kind of decode. 810 SkImageCacherator::CachedFormat cacheFormat = cacher->chooseCacheFormat( 811 dstColorSpace, proxy.fCaps.get()); 812 info = cacher->buildCacheInfo(cacheFormat).makeWH(scaledSize.width(), 813 scaledSize.height()); 814 } else { 815 info = as_IB(this)->onImageInfo().makeWH(scaledSize.width(), scaledSize.height()); 816 if (!dstColorSpace) { 817 info = info.makeColorSpace(nullptr); 818 } 819 } 820 // Force color type to be the requested type. 821 info = info.makeColorType(dstColorType); 822 pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr)); 823 if (fillMode) { 824 // Always decode to N32 and convert to the requested type if necessary. 825 SkImageInfo decodeInfo = info.makeColorType(kN32_SkColorType); 826 SkAutoPixmapStorage decodePixmap; 827 decodePixmap.alloc(decodeInfo); 828 829 if (isScaled) { 830 if (!this->scalePixels(decodePixmap, scaleFilterQuality, 831 SkImage::kDisallow_CachingHint)) { 832 return 0; 833 } 834 } else { 835 if (!this->readPixels(decodePixmap, 0, 0, SkImage::kDisallow_CachingHint)) { 836 return 0; 837 } 838 } 839 840 if (decodeInfo.colorType() != info.colorType()) { 841 pixmap.alloc(info); 842 // Convert and copy the decoded pixmap to the target pixmap. 843 decodePixmap.readPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(), 0, 844 0); 845 } else { 846 pixmap = std::move(decodePixmap); 847 } 848 } 849 } 850 int mipMapLevelCount = 1; 851 if (useMipMaps) { 852 // SkMipMap only deals with the mipmap levels it generates, which does 853 // not include the base level. 854 // That means it generates and holds levels 1-x instead of 0-x. 855 // So the total mipmap level count is 1 more than what 856 // SkMipMap::ComputeLevelCount returns. 857 mipMapLevelCount = SkMipMap::ComputeLevelCount(scaledSize.width(), scaledSize.height()) + 1; 858 859 // We already initialized pixelSize to the size of the base level. 860 // SkMipMap will generate the extra mipmap levels. Their sizes need to 861 // be added to the total. 862 // Index 0 here does not refer to the base mipmap level -- it is 863 // SkMipMap's first generated mipmap level (level 1). 864 for (int currentMipMapLevelIndex = mipMapLevelCount - 2; currentMipMapLevelIndex >= 0; 865 currentMipMapLevelIndex--) { 866 SkISize mipSize = SkMipMap::ComputeLevelSize(scaledSize.width(), scaledSize.height(), 867 currentMipMapLevelIndex); 868 SkImageInfo mipInfo = info.makeWH(mipSize.fWidth, mipSize.fHeight); 869 pixelSize += SkAlign8(SkAutoPixmapStorage::AllocSize(mipInfo, nullptr)); 870 } 871 } 872 size_t size = 0; 873 size_t dtiSize = SkAlign8(sizeof(DeferredTextureImage)); 874 size += dtiSize; 875 size += (mipMapLevelCount - 1) * sizeof(MipMapLevelData); 876 // We subtract 1 because DeferredTextureImage already includes the base 877 // level in its size 878 size_t pixelOffset = size; 879 size += pixelSize; 880 size_t colorSpaceOffset = 0; 881 size_t colorSpaceSize = 0; 882 SkColorSpaceTransferFn fn; 883 if (info.colorSpace()) { 884 SkASSERT(dstColorSpace); 885 SkASSERT(supportsColorSpace); 886 colorSpaceOffset = size; 887 colorSpaceSize = info.colorSpace()->writeToMemory(nullptr); 888 size += colorSpaceSize; 889 } else if (supportsColorSpace && this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn)) { 890 // In legacy mode, preserve the color space tag on the SkImage. This is only 891 // supported if the color space has a parametric transfer function. 892 SkASSERT(!dstColorSpace); 893 colorSpaceOffset = size; 894 colorSpaceSize = this->colorSpace()->writeToMemory(nullptr); 895 size += colorSpaceSize; 896 } 897 if (!fillMode) { 898 return size; 899 } 900 char* bufferAsCharPtr = reinterpret_cast<char*>(buffer); 901 char* pixelsAsCharPtr = bufferAsCharPtr + pixelOffset; 902 void* pixels = pixelsAsCharPtr; 903 904 memcpy(reinterpret_cast<void*>(SkAlign8(reinterpret_cast<uintptr_t>(pixelsAsCharPtr))), 905 pixmap.addr(), pixmap.computeByteSize()); 906 907 // If the context has sRGB support, and we're intending to render to a surface with an attached 908 // color space, and the image has an sRGB-like color space attached, then use our gamma (sRGB) 909 // aware mip-mapping. 910 SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy; 911 if (proxy.fCaps->srgbSupport() && SkToBool(dstColorSpace) && 912 info.colorSpace() && info.colorSpace()->gammaCloseToSRGB()) { 913 SkASSERT(supportsColorSpace); 914 colorMode = SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware; 915 } 916 917 SkASSERT(info == pixmap.info()); 918 size_t rowBytes = pixmap.rowBytes(); 919 static_assert(std::is_standard_layout<DeferredTextureImage>::value, 920 "offsetof, which we use below, requires the type have standard layout"); 921 auto dtiBufferFiller = DTIBufferFiller{bufferAsCharPtr}; 922 FILL_MEMBER(dtiBufferFiller, fColorMode, &colorMode); 923 FILL_MEMBER(dtiBufferFiller, fContextUniqueID, &proxy.fContextUniqueID); 924 int width = info.width(); 925 FILL_MEMBER(dtiBufferFiller, fWidth, &width); 926 int height = info.height(); 927 FILL_MEMBER(dtiBufferFiller, fHeight, &height); 928 SkColorType colorType = info.colorType(); 929 FILL_MEMBER(dtiBufferFiller, fColorType, &colorType); 930 SkAlphaType alphaType = info.alphaType(); 931 FILL_MEMBER(dtiBufferFiller, fAlphaType, &alphaType); 932 FILL_MEMBER(dtiBufferFiller, fMipMapLevelCount, &mipMapLevelCount); 933 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fPixelData), 934 &pixels, sizeof(pixels)); 935 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fRowBytes), 936 &rowBytes, sizeof(rowBytes)); 937 if (colorSpaceSize) { 938 void* colorSpace = bufferAsCharPtr + colorSpaceOffset; 939 FILL_MEMBER(dtiBufferFiller, fColorSpace, &colorSpace); 940 FILL_MEMBER(dtiBufferFiller, fColorSpaceSize, &colorSpaceSize); 941 if (info.colorSpace()) { 942 info.colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset); 943 } else { 944 SkASSERT(this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn)); 945 SkASSERT(!dstColorSpace); 946 this->colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset); 947 } 948 } else { 949 memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpace), 950 0, sizeof(DeferredTextureImage::fColorSpace)); 951 memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpaceSize), 952 0, sizeof(DeferredTextureImage::fColorSpaceSize)); 953 } 954 955 // Fill in the mipmap levels if they exist 956 char* mipLevelPtr = pixelsAsCharPtr + SkAlign8(pixmap.computeByteSize()); 957 958 if (useMipMaps) { 959 static_assert(std::is_standard_layout<MipMapLevelData>::value, 960 "offsetof, which we use below, requires the type have a standard layout"); 961 962 std::unique_ptr<SkMipMap> mipmaps(SkMipMap::Build(pixmap, colorMode, nullptr)); 963 // SkMipMap holds only the mipmap levels it generates. 964 // A programmer can use the data they provided to SkMipMap::Build as level 0. 965 // So the SkMipMap provides levels 1-x but it stores them in its own 966 // range 0-(x-1). 967 for (int generatedMipLevelIndex = 0; generatedMipLevelIndex < mipMapLevelCount - 1; 968 generatedMipLevelIndex++) { 969 SkMipMap::Level mipLevel; 970 mipmaps->getLevel(generatedMipLevelIndex, &mipLevel); 971 972 // Make sure the mipmap data is after the start of the buffer 973 SkASSERT(mipLevelPtr > bufferAsCharPtr); 974 // Make sure the mipmap data starts before the end of the buffer 975 SkASSERT(mipLevelPtr < bufferAsCharPtr + pixelOffset + pixelSize); 976 // Make sure the mipmap data ends before the end of the buffer 977 SkASSERT(mipLevelPtr + mipLevel.fPixmap.computeByteSize() <= 978 bufferAsCharPtr + pixelOffset + pixelSize); 979 980 memcpy(mipLevelPtr, mipLevel.fPixmap.addr(), mipLevel.fPixmap.computeByteSize()); 981 982 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) + 983 sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) + 984 offsetof(MipMapLevelData, fPixelData), &mipLevelPtr, sizeof(void*)); 985 size_t rowBytes = mipLevel.fPixmap.rowBytes(); 986 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) + 987 sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) + 988 offsetof(MipMapLevelData, fRowBytes), &rowBytes, sizeof(rowBytes)); 989 990 mipLevelPtr += SkAlign8(mipLevel.fPixmap.computeByteSize()); 991 } 992 } 993 return size; 994 } 995 996 sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void* data, 997 SkBudgeted budgeted) { 998 if (!data) { 999 return nullptr; 1000 } 1001 const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImage*>(data); 1002 1003 if (!context || context->uniqueID() != dti->fContextUniqueID || context->abandoned()) { 1004 return nullptr; 1005 } 1006 int mipLevelCount = dti->fMipMapLevelCount; 1007 SkASSERT(mipLevelCount >= 1); 1008 sk_sp<SkColorSpace> colorSpace; 1009 if (dti->fColorSpaceSize) { 1010 colorSpace = SkColorSpace::Deserialize(dti->fColorSpace, dti->fColorSpaceSize); 1011 } 1012 SkImageInfo info = SkImageInfo::Make(dti->fWidth, dti->fHeight, 1013 dti->fColorType, dti->fAlphaType, colorSpace); 1014 if (mipLevelCount == 1) { 1015 SkPixmap pixmap; 1016 pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData, dti->fMipMapLevelData[0].fRowBytes); 1017 1018 // Pass nullptr for the |dstColorSpace|. This opts in to more lenient color space 1019 // verification. This is ok because we've already verified the color space in 1020 // getDeferredTextureImageData(). 1021 sk_sp<GrTextureProxy> proxy(GrUploadPixmapToTextureProxy( 1022 context->contextPriv().proxyProvider(), pixmap, budgeted, nullptr)); 1023 if (!proxy) { 1024 return nullptr; 1025 } 1026 return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, pixmap.alphaType(), 1027 std::move(proxy), std::move(colorSpace), budgeted); 1028 } else { 1029 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]); 1030 for (int i = 0; i < mipLevelCount; i++) { 1031 texels[i].fPixels = dti->fMipMapLevelData[i].fPixelData; 1032 texels[i].fRowBytes = dti->fMipMapLevelData[i].fRowBytes; 1033 } 1034 1035 return SkImage::MakeTextureFromMipMap(context, info, texels.get(), 1036 mipLevelCount, SkBudgeted::kYes, 1037 dti->fColorMode); 1038 } 1039 } 1040 1041 /////////////////////////////////////////////////////////////////////////////////////////////////// 1042 1043 bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx, 1044 sk_sp<SkImage> image, 1045 GrBackendTexture* backendTexture, 1046 BackendTextureReleaseProc* releaseProc) { 1047 if (!image || !ctx || !backendTexture || !releaseProc) { 1048 return false; 1049 } 1050 1051 // Ensure we have a texture backed image. 1052 if (!image->isTextureBacked()) { 1053 image = image->makeTextureImage(ctx, nullptr); 1054 if (!image) { 1055 return false; 1056 } 1057 } 1058 GrTexture* texture = image->getTexture(); 1059 if (!texture) { 1060 // In context-loss cases, we may not have a texture. 1061 return false; 1062 } 1063 1064 // If the image's context doesn't match the provided context, fail. 1065 if (texture->getContext() != ctx) { 1066 return false; 1067 } 1068 1069 // Flush any pending IO on the texture. 1070 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy()); 1071 SkASSERT(!texture->surfacePriv().hasPendingIO()); 1072 1073 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the 1074 // image is not unique, or if the texture wraps an external object. 1075 if (!image->unique() || !texture->surfacePriv().hasUniqueRef() || 1076 texture->resourcePriv().refsWrappedObjects()) { 1077 // onMakeSubset will always copy the image. 1078 image = as_IB(image)->onMakeSubset(image->bounds()); 1079 if (!image) { 1080 return false; 1081 } 1082 1083 texture = image->getTexture(); 1084 if (!texture) { 1085 return false; 1086 } 1087 1088 // Flush to ensure that the copy is completed before we return the texture. 1089 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy()); 1090 SkASSERT(!texture->surfacePriv().hasPendingIO()); 1091 } 1092 1093 SkASSERT(!texture->resourcePriv().refsWrappedObjects()); 1094 SkASSERT(texture->surfacePriv().hasUniqueRef()); 1095 SkASSERT(image->unique()); 1096 1097 // Take a reference to the GrTexture and release the image. 1098 sk_sp<GrTexture> textureRef(SkSafeRef(texture)); 1099 image = nullptr; 1100 1101 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process. 1102 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc); 1103 } 1104 1105 /////////////////////////////////////////////////////////////////////////////////////////////////// 1106 1107 sk_sp<SkImage> SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo& info, 1108 const GrMipLevel texels[], int mipLevelCount, 1109 SkBudgeted budgeted, 1110 SkDestinationSurfaceColorMode colorMode) { 1111 SkASSERT(mipLevelCount >= 1); 1112 if (!ctx) { 1113 return nullptr; 1114 } 1115 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider(); 1116 1117 // For images where the client is passing the mip data we require that all the mip levels have 1118 // valid data. 1119 for (int i = 0; i < mipLevelCount; ++i) { 1120 if (!texels[i].fPixels) { 1121 return nullptr; 1122 } 1123 } 1124 sk_sp<GrTextureProxy> proxy(GrUploadMipMapToTextureProxy(proxyProvider, info, 1125 texels, mipLevelCount, colorMode)); 1126 if (!proxy) { 1127 return nullptr; 1128 } 1129 1130 SkASSERT(proxy->priv().isExact()); 1131 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID, 1132 info.alphaType(), std::move(proxy), 1133 info.refColorSpace(), budgeted); 1134 } 1135 1136 sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> target, SkColorType, 1137 SkTransferFunctionBehavior premulBehavior) const { 1138 if (SkTransferFunctionBehavior::kRespect == premulBehavior) { 1139 // TODO: Implement this. 1140 return nullptr; 1141 } 1142 1143 sk_sp<SkColorSpace> srcSpace = fColorSpace; 1144 if (!fColorSpace) { 1145 if (target->isSRGB()) { 1146 return sk_ref_sp(const_cast<SkImage*>((SkImage*)this)); 1147 } 1148 1149 srcSpace = SkColorSpace::MakeSRGB(); 1150 } 1151 1152 auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), target.get()); 1153 if (!xform) { 1154 return sk_ref_sp(const_cast<SkImage_Gpu*>(this)); 1155 } 1156 1157 sk_sp<GrRenderTargetContext> renderTargetContext(fContext->makeDeferredRenderTargetContext( 1158 SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig, nullptr)); 1159 if (!renderTargetContext) { 1160 return nullptr; 1161 } 1162 1163 GrPaint paint; 1164 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 1165 paint.addColorTextureProcessor(fProxy, SkMatrix::I()); 1166 paint.addColorFragmentProcessor(std::move(xform)); 1167 1168 const SkRect rect = SkRect::MakeIWH(this->width(), this->height()); 1169 1170 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect); 1171 1172 if (!renderTargetContext->asTextureProxy()) { 1173 return nullptr; 1174 } 1175 1176 // MDB: this call is okay bc we know 'renderTargetContext' was exact 1177 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, 1178 fAlphaType, renderTargetContext->asTextureProxyRef(), 1179 std::move(target), fBudgeted); 1180 1181 } 1182 1183 bool SkImage_Gpu::onIsValid(GrContext* context) const { 1184 // The base class has already checked that context isn't abandoned (if it's not nullptr) 1185 if (fContext->abandoned()) { 1186 return false; 1187 } 1188 1189 if (context && context != fContext) { 1190 return false; 1191 } 1192 1193 return true; 1194 } 1195