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 "GrAHardwareBufferImageGenerator.h" 13 #include "GrBackendSurface.h" 14 #include "GrBackendTextureImageGenerator.h" 15 #include "GrBitmapTextureMaker.h" 16 #include "GrCaps.h" 17 #include "GrClip.h" 18 #include "GrColorSpaceXform.h" 19 #include "GrContext.h" 20 #include "GrContextPriv.h" 21 #include "GrGpu.h" 22 #include "GrImageTextureMaker.h" 23 #include "GrProxyProvider.h" 24 #include "GrRenderTargetContext.h" 25 #include "GrResourceProvider.h" 26 #include "GrResourceProviderPriv.h" 27 #include "GrSemaphore.h" 28 #include "GrSurfacePriv.h" 29 #include "GrTexture.h" 30 #include "GrTextureAdjuster.h" 31 #include "GrTexturePriv.h" 32 #include "GrTextureProxy.h" 33 #include "GrTextureProxyPriv.h" 34 #include "SkAutoPixmapStorage.h" 35 #include "SkBitmapCache.h" 36 #include "SkCanvas.h" 37 #include "SkGr.h" 38 #include "SkImageInfoPriv.h" 39 #include "SkImage_Gpu.h" 40 #include "SkMipMap.h" 41 #include "SkScopeExit.h" 42 #include "SkTraceEvent.h" 43 #include "effects/GrYUVtoRGBEffect.h" 44 #include "gl/GrGLTexture.h" 45 46 SkImage_Gpu::SkImage_Gpu(sk_sp<GrContext> context, uint32_t uniqueID, SkAlphaType at, 47 sk_sp<GrTextureProxy> proxy, sk_sp<SkColorSpace> colorSpace) 48 : INHERITED(std::move(context), proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID, 49 at, colorSpace) 50 , fProxy(std::move(proxy)) {} 51 52 SkImage_Gpu::~SkImage_Gpu() {} 53 54 SkImageInfo SkImage_Gpu::onImageInfo() const { 55 SkColorType colorType; 56 if (!GrPixelConfigToColorType(fProxy->config(), &colorType)) { 57 colorType = kUnknown_SkColorType; 58 } 59 60 return SkImageInfo::Make(fProxy->width(), fProxy->height(), colorType, fAlphaType, fColorSpace); 61 } 62 63 sk_sp<SkImage> SkImage_Gpu::onMakeColorTypeAndColorSpace(SkColorType targetCT, 64 sk_sp<SkColorSpace> targetCS) const { 65 auto xform = GrColorSpaceXformEffect::Make(fColorSpace.get(), fAlphaType, 66 targetCS.get(), fAlphaType); 67 SkASSERT(xform || targetCT != this->colorType()); 68 69 sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef(); 70 71 GrBackendFormat format = proxy->backendFormat().makeTexture2D(); 72 if (!format.isValid()) { 73 return nullptr; 74 } 75 76 sk_sp<GrRenderTargetContext> renderTargetContext( 77 fContext->contextPriv().makeDeferredRenderTargetContextWithFallback( 78 format, SkBackingFit::kExact, this->width(), this->height(), 79 SkColorType2GrPixelConfig(targetCT), nullptr)); 80 if (!renderTargetContext) { 81 return nullptr; 82 } 83 84 GrPaint paint; 85 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 86 paint.addColorTextureProcessor(std::move(proxy), SkMatrix::I()); 87 if (xform) { 88 paint.addColorFragmentProcessor(std::move(xform)); 89 } 90 91 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), 92 SkRect::MakeIWH(this->width(), this->height())); 93 if (!renderTargetContext->asTextureProxy()) { 94 return nullptr; 95 } 96 97 // MDB: this call is okay bc we know 'renderTargetContext' was exact 98 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, fAlphaType, 99 renderTargetContext->asTextureProxyRef(), std::move(targetCS)); 100 } 101 102 /////////////////////////////////////////////////////////////////////////////////////////////////// 103 104 static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx, 105 const GrBackendTexture& backendTex, 106 GrSurfaceOrigin origin, 107 SkAlphaType at, sk_sp<SkColorSpace> colorSpace, 108 GrWrapOwnership ownership, 109 SkImage::TextureReleaseProc releaseProc, 110 SkImage::ReleaseContext releaseCtx) { 111 if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) { 112 return nullptr; 113 } 114 115 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider(); 116 sk_sp<GrTextureProxy> proxy = 117 proxyProvider->wrapBackendTexture(backendTex, origin, ownership, GrWrapCacheable::kNo, 118 kRead_GrIOType, releaseProc, releaseCtx); 119 if (!proxy) { 120 return nullptr; 121 } 122 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, at, std::move(proxy), 123 std::move(colorSpace)); 124 } 125 126 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, 127 const GrBackendTexture& tex, GrSurfaceOrigin origin, 128 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs, 129 TextureReleaseProc releaseP, ReleaseContext releaseC) { 130 if (!ctx) { 131 return nullptr; 132 } 133 GrBackendTexture texCopy = tex; 134 if (!SkImage_GpuBase::ValidateBackendTexture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) { 135 return nullptr; 136 } 137 return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs), 138 kBorrow_GrWrapOwnership, releaseP, releaseC); 139 } 140 141 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, 142 const GrBackendTexture& tex, GrSurfaceOrigin origin, 143 SkColorType ct, SkAlphaType at, 144 sk_sp<SkColorSpace> cs) { 145 if (!ctx || !ctx->contextPriv().resourceProvider()) { 146 // We have a DDL context and we don't support adopted textures for them. 147 return nullptr; 148 } 149 GrBackendTexture texCopy = tex; 150 if (!SkImage_GpuBase::ValidateBackendTexture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) { 151 return nullptr; 152 } 153 return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs), 154 kAdopt_GrWrapOwnership, nullptr, nullptr); 155 } 156 157 sk_sp<SkImage> SkImage::MakeFromCompressed(GrContext* context, sk_sp<SkData> data, 158 int width, int height, CompressionType type) { 159 // create the backing texture 160 GrSurfaceDesc desc; 161 desc.fFlags = kNone_GrSurfaceFlags; 162 desc.fWidth = width; 163 desc.fHeight = height; 164 switch (type) { 165 case kETC1_CompressionType: 166 desc.fConfig = kRGB_ETC1_GrPixelConfig; 167 break; 168 default: 169 desc.fConfig = kUnknown_GrPixelConfig; 170 break; 171 } 172 desc.fSampleCnt = 1; 173 174 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 175 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(std::move(data), desc); 176 177 if (!proxy) { 178 return nullptr; 179 } 180 181 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, kOpaque_SkAlphaType, 182 std::move(proxy), nullptr); 183 } 184 185 sk_sp<SkImage> SkImage_Gpu::ConvertYUVATexturesToRGB(GrContext* ctx, SkYUVColorSpace yuvColorSpace, 186 const GrBackendTexture yuvaTextures[], 187 const SkYUVAIndex yuvaIndices[4], SkISize size, 188 GrSurfaceOrigin origin, 189 GrRenderTargetContext* renderTargetContext) { 190 SkASSERT(renderTargetContext); 191 192 int numTextures; 193 if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) { 194 return nullptr; 195 } 196 197 sk_sp<GrTextureProxy> tempTextureProxies[4]; 198 if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, yuvaIndices, 199 origin, tempTextureProxies)) { 200 return nullptr; 201 } 202 203 const SkRect rect = SkRect::MakeIWH(size.width(), size.height()); 204 if (!RenderYUVAToRGBA(ctx, renderTargetContext, rect, yuvColorSpace, 205 tempTextureProxies, yuvaIndices)) { 206 return nullptr; 207 } 208 209 SkAlphaType at = GetAlphaTypeFromYUVAIndices(yuvaIndices); 210 // MDB: this call is okay bc we know 'renderTargetContext' was exact 211 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, at, 212 renderTargetContext->asTextureProxyRef(), 213 renderTargetContext->colorSpaceInfo().refColorSpace()); 214 } 215 216 sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopy(GrContext* ctx, 217 SkYUVColorSpace yuvColorSpace, 218 const GrBackendTexture yuvaTextures[], 219 const SkYUVAIndex yuvaIndices[4], 220 SkISize imageSize, 221 GrSurfaceOrigin imageOrigin, 222 sk_sp<SkColorSpace> imageColorSpace) { 223 const int width = imageSize.width(); 224 const int height = imageSize.height(); 225 226 const GrBackendFormat format = 227 ctx->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType); 228 229 // Needs to create a render target in order to draw to it for the yuv->rgb conversion. 230 sk_sp<GrRenderTargetContext> renderTargetContext( 231 ctx->contextPriv().makeDeferredRenderTargetContext( 232 format, SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig, 233 std::move(imageColorSpace), 1, GrMipMapped::kNo, imageOrigin)); 234 if (!renderTargetContext) { 235 return nullptr; 236 } 237 238 return SkImage_Gpu::ConvertYUVATexturesToRGB(ctx, yuvColorSpace, yuvaTextures, yuvaIndices, 239 imageSize, imageOrigin, renderTargetContext.get()); 240 } 241 242 sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopyWithExternalBackend( 243 GrContext* ctx, 244 SkYUVColorSpace yuvColorSpace, 245 const GrBackendTexture yuvaTextures[], 246 const SkYUVAIndex yuvaIndices[4], 247 SkISize imageSize, 248 GrSurfaceOrigin imageOrigin, 249 const GrBackendTexture& backendTexture, 250 sk_sp<SkColorSpace> imageColorSpace) { 251 GrBackendTexture backendTextureCopy = backendTexture; 252 253 SkAlphaType at = SkImage_GpuBase::GetAlphaTypeFromYUVAIndices(yuvaIndices); 254 if (!SkImage_Gpu::ValidateBackendTexture(ctx, backendTextureCopy, &backendTextureCopy.fConfig, 255 kRGBA_8888_SkColorType, at, nullptr)) { 256 return nullptr; 257 } 258 259 // Needs to create a render target with external texture 260 // in order to draw to it for the yuv->rgb conversion. 261 sk_sp<GrRenderTargetContext> renderTargetContext( 262 ctx->contextPriv().makeBackendTextureRenderTargetContext(backendTextureCopy, 263 imageOrigin, 1, 264 std::move(imageColorSpace))); 265 266 if (!renderTargetContext) { 267 return nullptr; 268 } 269 270 return SkImage_Gpu::ConvertYUVATexturesToRGB(ctx, yuvColorSpace, yuvaTextures, yuvaIndices, 271 imageSize, imageOrigin, renderTargetContext.get()); 272 } 273 274 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace yuvColorSpace, 275 const GrBackendTexture yuvTextures[3], 276 GrSurfaceOrigin imageOrigin, 277 sk_sp<SkColorSpace> imageColorSpace) { 278 // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future. 279 SkYUVAIndex yuvaIndices[4] = { 280 SkYUVAIndex{0, SkColorChannel::kR}, 281 SkYUVAIndex{1, SkColorChannel::kR}, 282 SkYUVAIndex{2, SkColorChannel::kR}, 283 SkYUVAIndex{-1, SkColorChannel::kA}}; 284 SkISize size{yuvTextures[0].width(), yuvTextures[0].height()}; 285 return SkImage_Gpu::MakeFromYUVATexturesCopy(ctx, yuvColorSpace, yuvTextures, yuvaIndices, 286 size, imageOrigin, std::move(imageColorSpace)); 287 } 288 289 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopyWithExternalBackend( 290 GrContext* ctx, SkYUVColorSpace yuvColorSpace, const GrBackendTexture yuvTextures[3], 291 GrSurfaceOrigin imageOrigin, const GrBackendTexture& backendTexture, 292 sk_sp<SkColorSpace> imageColorSpace) { 293 SkYUVAIndex yuvaIndices[4] = { 294 SkYUVAIndex{0, SkColorChannel::kR}, 295 SkYUVAIndex{1, SkColorChannel::kR}, 296 SkYUVAIndex{2, SkColorChannel::kR}, 297 SkYUVAIndex{-1, SkColorChannel::kA}}; 298 SkISize size{yuvTextures[0].width(), yuvTextures[0].height()}; 299 return SkImage_Gpu::MakeFromYUVATexturesCopyWithExternalBackend( 300 ctx, yuvColorSpace, yuvTextures, yuvaIndices, size, imageOrigin, backendTexture, 301 std::move(imageColorSpace)); 302 } 303 304 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace yuvColorSpace, 305 const GrBackendTexture nv12Textures[2], 306 GrSurfaceOrigin imageOrigin, 307 sk_sp<SkColorSpace> imageColorSpace) { 308 // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future. 309 SkYUVAIndex yuvaIndices[4] = { 310 SkYUVAIndex{0, SkColorChannel::kR}, 311 SkYUVAIndex{1, SkColorChannel::kR}, 312 SkYUVAIndex{1, SkColorChannel::kG}, 313 SkYUVAIndex{-1, SkColorChannel::kA}}; 314 SkISize size{nv12Textures[0].width(), nv12Textures[0].height()}; 315 return SkImage_Gpu::MakeFromYUVATexturesCopy(ctx, yuvColorSpace, nv12Textures, yuvaIndices, 316 size, imageOrigin, std::move(imageColorSpace)); 317 } 318 319 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopyWithExternalBackend( 320 GrContext* ctx, 321 SkYUVColorSpace yuvColorSpace, 322 const GrBackendTexture nv12Textures[2], 323 GrSurfaceOrigin imageOrigin, 324 const GrBackendTexture& backendTexture, 325 sk_sp<SkColorSpace> imageColorSpace) { 326 SkYUVAIndex yuvaIndices[4] = { 327 SkYUVAIndex{0, SkColorChannel::kR}, 328 SkYUVAIndex{1, SkColorChannel::kR}, 329 SkYUVAIndex{1, SkColorChannel::kG}, 330 SkYUVAIndex{-1, SkColorChannel::kA}}; 331 SkISize size{nv12Textures[0].width(), nv12Textures[0].height()}; 332 return SkImage_Gpu::MakeFromYUVATexturesCopyWithExternalBackend( 333 ctx, yuvColorSpace, nv12Textures, yuvaIndices, size, imageOrigin, backendTexture, 334 std::move(imageColorSpace)); 335 } 336 337 static sk_sp<SkImage> create_image_from_producer(GrContext* context, GrTextureProducer* producer, 338 SkAlphaType at, uint32_t id, 339 GrMipMapped mipMapped) { 340 sk_sp<GrTextureProxy> proxy(producer->refTextureProxy(mipMapped)); 341 if (!proxy) { 342 return nullptr; 343 } 344 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), id, at, std::move(proxy), 345 sk_ref_sp(producer->colorSpace())); 346 } 347 348 sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace, 349 GrMipMapped mipMapped) const { 350 if (!context) { 351 return nullptr; 352 } 353 if (uint32_t incumbentID = as_IB(this)->contextID()) { 354 if (incumbentID != context->contextPriv().contextID()) { 355 return nullptr; 356 } 357 sk_sp<GrTextureProxy> proxy = as_IB(this)->asTextureProxyRef(); 358 SkASSERT(proxy); 359 if (GrMipMapped::kNo == mipMapped || proxy->mipMapped() == mipMapped) { 360 return sk_ref_sp(const_cast<SkImage*>(this)); 361 } 362 GrTextureAdjuster adjuster(context, std::move(proxy), this->alphaType(), 363 this->uniqueID(), this->colorSpace()); 364 return create_image_from_producer(context, &adjuster, this->alphaType(), 365 this->uniqueID(), mipMapped); 366 } 367 368 if (this->isLazyGenerated()) { 369 GrImageTextureMaker maker(context, this, kDisallow_CachingHint); 370 return create_image_from_producer(context, &maker, this->alphaType(), 371 this->uniqueID(), mipMapped); 372 } 373 374 if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) { 375 GrBitmapTextureMaker maker(context, *bmp); 376 return create_image_from_producer(context, &maker, this->alphaType(), 377 this->uniqueID(), mipMapped); 378 } 379 return nullptr; 380 } 381 382 /////////////////////////////////////////////////////////////////////////////////////////////////// 383 384 sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context, 385 const GrBackendFormat& backendFormat, 386 int width, 387 int height, 388 GrMipMapped mipMapped, 389 GrSurfaceOrigin origin, 390 SkColorType colorType, 391 SkAlphaType alphaType, 392 sk_sp<SkColorSpace> colorSpace, 393 PromiseImageTextureFulfillProc textureFulfillProc, 394 PromiseImageTextureReleaseProc textureReleaseProc, 395 PromiseImageTextureDoneProc textureDoneProc, 396 PromiseImageTextureContext textureContext, 397 DelayReleaseCallback delayReleaseCallback) { 398 // The contract here is that if 'promiseDoneProc' is passed in it should always be called, 399 // even if creation of the SkImage fails. Once we call MakePromiseImageLazyProxy it takes 400 // responsibility for calling the done proc. 401 if (!textureDoneProc) { 402 return nullptr; 403 } 404 SkScopeExit callDone([textureDoneProc, textureContext]() { textureDoneProc(textureContext); }); 405 406 SkImageInfo info = SkImageInfo::Make(width, height, colorType, alphaType, colorSpace); 407 if (!SkImageInfoIsValid(info)) { 408 return nullptr; 409 } 410 411 if (!context) { 412 return nullptr; 413 } 414 415 if (width <= 0 || height <= 0) { 416 return nullptr; 417 } 418 419 GrPixelConfig config = 420 context->contextPriv().caps()->getConfigFromBackendFormat(backendFormat, colorType); 421 if (config == kUnknown_GrPixelConfig) { 422 return nullptr; 423 } 424 425 callDone.clear(); 426 auto proxy = MakePromiseImageLazyProxy(context, width, height, origin, config, backendFormat, 427 mipMapped, textureFulfillProc, textureReleaseProc, 428 textureDoneProc, textureContext, delayReleaseCallback); 429 if (!proxy) { 430 return nullptr; 431 } 432 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, alphaType, 433 std::move(proxy), std::move(colorSpace)); 434 } 435 436 /////////////////////////////////////////////////////////////////////////////////////////////////// 437 438 sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded, 439 bool buildMips, SkColorSpace* dstColorSpace, 440 bool limitToMaxTextureSize) { 441 sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded)); 442 if (!codecImage) { 443 return nullptr; 444 } 445 446 // Some backends or drivers don't support (safely) moving resources between contexts 447 if (!context || !context->contextPriv().caps()->crossContextTextureSupport()) { 448 return codecImage; 449 } 450 451 auto maxTextureSize = context->contextPriv().caps()->maxTextureSize(); 452 if (limitToMaxTextureSize && 453 (codecImage->width() > maxTextureSize || codecImage->height() > maxTextureSize)) { 454 SkAutoPixmapStorage pmap; 455 SkImageInfo info = as_IB(codecImage)->onImageInfo(); 456 if (!dstColorSpace) { 457 info = info.makeColorSpace(nullptr); 458 } 459 if (!pmap.tryAlloc(info) || !codecImage->readPixels(pmap, 0, 0, kDisallow_CachingHint)) { 460 return nullptr; 461 } 462 return MakeCrossContextFromPixmap(context, pmap, buildMips, dstColorSpace, true); 463 } 464 465 // Turn the codec image into a GrTextureProxy 466 GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint); 467 GrSamplerState samplerState( 468 GrSamplerState::WrapMode::kClamp, 469 buildMips ? GrSamplerState::Filter::kMipMap : GrSamplerState::Filter::kBilerp); 470 sk_sp<GrTextureProxy> proxy(maker.refTextureProxyForParams(samplerState, nullptr)); 471 if (!proxy) { 472 return codecImage; 473 } 474 475 if (!proxy->instantiate(context->contextPriv().resourceProvider())) { 476 return codecImage; 477 } 478 sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture()); 479 480 // Flush any writes or uploads 481 context->contextPriv().prepareSurfaceForExternalIO(proxy.get()); 482 483 GrGpu* gpu = context->contextPriv().getGpu(); 484 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get()); 485 486 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(), 487 std::move(sema), 488 as_IB(codecImage)->onImageInfo().colorType(), 489 codecImage->alphaType(), 490 codecImage->refColorSpace()); 491 return SkImage::MakeFromGenerator(std::move(gen)); 492 } 493 494 sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrContext* context, 495 const SkPixmap& originalPixmap, bool buildMips, 496 SkColorSpace* dstColorSpace, 497 bool limitToMaxTextureSize) { 498 // Some backends or drivers don't support (safely) moving resources between contexts 499 if (!context || !context->contextPriv().caps()->crossContextTextureSupport()) { 500 return SkImage::MakeRasterCopy(originalPixmap); 501 } 502 503 // If we don't have access to the resource provider and gpu (i.e. in a DDL context) we will not 504 // be able to make everything needed for a GPU CrossContext image. Thus return a raster copy 505 // instead. 506 if (!context->contextPriv().resourceProvider()) { 507 return SkImage::MakeRasterCopy(originalPixmap); 508 } 509 510 const SkPixmap* pixmap = &originalPixmap; 511 SkAutoPixmapStorage resized; 512 int maxTextureSize = context->contextPriv().caps()->maxTextureSize(); 513 int maxDim = SkTMax(originalPixmap.width(), originalPixmap.height()); 514 if (limitToMaxTextureSize && maxDim > maxTextureSize) { 515 float scale = static_cast<float>(maxTextureSize) / maxDim; 516 int newWidth = SkTMin(static_cast<int>(originalPixmap.width() * scale), maxTextureSize); 517 int newHeight = SkTMin(static_cast<int>(originalPixmap.height() * scale), maxTextureSize); 518 SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight); 519 if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, kLow_SkFilterQuality)) { 520 return nullptr; 521 } 522 pixmap = &resized; 523 } 524 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 525 // Turn the pixmap into a GrTextureProxy 526 sk_sp<GrTextureProxy> proxy; 527 if (buildMips) { 528 SkBitmap bmp; 529 bmp.installPixels(*pixmap); 530 proxy = proxyProvider->createMipMapProxyFromBitmap(bmp); 531 } else { 532 if (SkImageInfoIsValid(pixmap->info())) { 533 ATRACE_ANDROID_FRAMEWORK("Upload Texture [%ux%u]", pixmap->width(), pixmap->height()); 534 // We don't need a release proc on the data in pixmap since we know we are in a 535 // GrContext that has a resource provider. Thus the createTextureProxy call will 536 // immediately upload the data. 537 sk_sp<SkImage> image = SkImage::MakeFromRaster(*pixmap, nullptr, nullptr); 538 proxy = proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1, 539 SkBudgeted::kYes, SkBackingFit::kExact); 540 } 541 } 542 543 if (!proxy) { 544 return SkImage::MakeRasterCopy(*pixmap); 545 } 546 547 sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture()); 548 549 // Flush any writes or uploads 550 context->contextPriv().prepareSurfaceForExternalIO(proxy.get()); 551 GrGpu* gpu = context->contextPriv().getGpu(); 552 553 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get()); 554 555 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(), 556 std::move(sema), pixmap->colorType(), 557 pixmap->alphaType(), 558 pixmap->info().refColorSpace()); 559 return SkImage::MakeFromGenerator(std::move(gen)); 560 } 561 562 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26 563 sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at, 564 sk_sp<SkColorSpace> cs, 565 GrSurfaceOrigin surfaceOrigin) { 566 auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs, surfaceOrigin); 567 return SkImage::MakeFromGenerator(std::move(gen)); 568 } 569 #endif 570 571 /////////////////////////////////////////////////////////////////////////////////////////////////// 572 573 bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx, 574 sk_sp<SkImage> image, 575 GrBackendTexture* backendTexture, 576 BackendTextureReleaseProc* releaseProc) { 577 if (!image || !ctx || !backendTexture || !releaseProc) { 578 return false; 579 } 580 581 // Ensure we have a texture backed image. 582 if (!image->isTextureBacked()) { 583 image = image->makeTextureImage(ctx, nullptr); 584 if (!image) { 585 return false; 586 } 587 } 588 GrTexture* texture = image->getTexture(); 589 if (!texture) { 590 // In context-loss cases, we may not have a texture. 591 return false; 592 } 593 594 // If the image's context doesn't match the provided context, fail. 595 if (texture->getContext() != ctx) { 596 return false; 597 } 598 599 // Flush any pending IO on the texture. 600 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy()); 601 SkASSERT(!texture->surfacePriv().hasPendingIO()); 602 603 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the 604 // image is not unique, or if the texture wraps an external object. 605 if (!image->unique() || !texture->surfacePriv().hasUniqueRef() || 606 texture->resourcePriv().refsWrappedObjects()) { 607 // onMakeSubset will always copy the image. 608 image = as_IB(image)->onMakeSubset(image->bounds()); 609 if (!image) { 610 return false; 611 } 612 613 texture = image->getTexture(); 614 if (!texture) { 615 return false; 616 } 617 618 // Flush to ensure that the copy is completed before we return the texture. 619 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy()); 620 SkASSERT(!texture->surfacePriv().hasPendingIO()); 621 } 622 623 SkASSERT(!texture->resourcePriv().refsWrappedObjects()); 624 SkASSERT(texture->surfacePriv().hasUniqueRef()); 625 SkASSERT(image->unique()); 626 627 // Take a reference to the GrTexture and release the image. 628 sk_sp<GrTexture> textureRef(SkSafeRef(texture)); 629 image = nullptr; 630 631 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process. 632 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc); 633 } 634