1 /* 2 * Copyright 2015 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 "SkBitmap.h" 9 #include "SkBitmapCache.h" 10 #include "SkColorSpace_Base.h" 11 #include "SkImage_Base.h" 12 #include "SkImageCacherator.h" 13 #include "SkMallocPixelRef.h" 14 #include "SkNextID.h" 15 #include "SkPixelRef.h" 16 #include "SkResourceCache.h" 17 18 #if SK_SUPPORT_GPU 19 #include "GrContext.h" 20 #include "GrContextPriv.h" 21 #include "GrGpuResourcePriv.h" 22 #include "GrImageTextureMaker.h" 23 #include "GrResourceKey.h" 24 #include "GrResourceProvider.h" 25 #include "GrSamplerParams.h" 26 #include "GrYUVProvider.h" 27 #include "SkGr.h" 28 #endif 29 30 // Until we actually have codecs/etc. that can contain/support a GPU texture format 31 // skip this step, since for some generators, returning their encoded data as a SkData 32 // can be somewhat expensive, and this call doesn't indicate to the generator that we're 33 // only interested in GPU datas... 34 // see skbug.com/ 4971, 5128, ... 35 //#define SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR 36 37 // Helper for exclusive access to a shared generator. 38 class SkImageCacherator::ScopedGenerator { 39 public: 40 ScopedGenerator(const sk_sp<SharedGenerator>& gen) 41 : fSharedGenerator(gen) 42 , fAutoAquire(gen->fMutex) {} 43 44 SkImageGenerator* operator->() const { 45 fSharedGenerator->fMutex.assertHeld(); 46 return fSharedGenerator->fGenerator.get(); 47 } 48 49 operator SkImageGenerator*() const { 50 fSharedGenerator->fMutex.assertHeld(); 51 return fSharedGenerator->fGenerator.get(); 52 } 53 54 private: 55 const sk_sp<SharedGenerator>& fSharedGenerator; 56 SkAutoExclusive fAutoAquire; 57 }; 58 59 SkImageCacherator::Validator::Validator(sk_sp<SharedGenerator> gen, const SkIRect* subset) 60 : fSharedGenerator(std::move(gen)) { 61 62 if (!fSharedGenerator) { 63 return; 64 } 65 66 // The following generator accessors are safe without acquiring the mutex (const getters). 67 // TODO: refactor to use a ScopedGenerator instead, for clarity. 68 const SkImageInfo& info = fSharedGenerator->fGenerator->getInfo(); 69 if (info.isEmpty()) { 70 fSharedGenerator.reset(); 71 return; 72 } 73 74 fUniqueID = fSharedGenerator->fGenerator->uniqueID(); 75 const SkIRect bounds = SkIRect::MakeWH(info.width(), info.height()); 76 if (subset) { 77 if (!bounds.contains(*subset)) { 78 fSharedGenerator.reset(); 79 return; 80 } 81 if (*subset != bounds) { 82 // we need a different uniqueID since we really are a subset of the raw generator 83 fUniqueID = SkNextID::ImageID(); 84 } 85 } else { 86 subset = &bounds; 87 } 88 89 fInfo = info.makeWH(subset->width(), subset->height()); 90 fOrigin = SkIPoint::Make(subset->x(), subset->y()); 91 92 // If the encoded data is in a strange color space (it's not an XYZ matrix space), we won't be 93 // able to preserve the gamut of the encoded data when we decode it. Instead, we'll have to 94 // decode to a known color space (linear sRGB is a good choice). But we need to adjust the 95 // stored color space, because drawing code will ask the SkImage for its color space, which 96 // will in turn ask the cacherator. If we return the A2B color space, then we will be unable to 97 // construct a source-to-dest gamut transformation matrix. 98 if (fInfo.colorSpace() && 99 SkColorSpace_Base::Type::kXYZ != as_CSB(fInfo.colorSpace())->type()) { 100 fInfo = fInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear()); 101 } 102 } 103 104 SkImageCacherator* SkImageCacherator::NewFromGenerator(std::unique_ptr<SkImageGenerator> gen, 105 const SkIRect* subset) { 106 Validator validator(SharedGenerator::Make(std::move(gen)), subset); 107 108 return validator ? new SkImageCacherator(&validator) : nullptr; 109 } 110 111 SkImageCacherator::SkImageCacherator(Validator* validator) 112 : fSharedGenerator(std::move(validator->fSharedGenerator)) // we take ownership 113 , fInfo(validator->fInfo) 114 , fOrigin(validator->fOrigin) 115 { 116 fUniqueIDs[kLegacy_CachedFormat] = validator->fUniqueID; 117 for (int i = 1; i < kNumCachedFormats; ++i) { 118 // We lazily allocate IDs for non-default caching cases 119 fUniqueIDs[i] = kNeedNewImageUniqueID; 120 } 121 SkASSERT(fSharedGenerator); 122 } 123 124 SkImageCacherator::~SkImageCacherator() {} 125 126 SkData* SkImageCacherator::refEncoded(GrContext* ctx) { 127 ScopedGenerator generator(fSharedGenerator); 128 return generator->refEncodedData(ctx); 129 } 130 131 static bool check_output_bitmap(const SkBitmap& bitmap, uint32_t expectedID) { 132 SkASSERT(bitmap.getGenerationID() == expectedID); 133 SkASSERT(bitmap.isImmutable()); 134 SkASSERT(bitmap.getPixels()); 135 return true; 136 } 137 138 // Note, this returns a new, mutable, bitmap, with a new genID. 139 // If you want the immutable bitmap with the same ID as our cacherator, call tryLockAsBitmap() 140 // 141 bool SkImageCacherator::generateBitmap(SkBitmap* bitmap, const SkImageInfo& decodeInfo) { 142 SkBitmap::Allocator* allocator = SkResourceCache::GetAllocator(); 143 144 ScopedGenerator generator(fSharedGenerator); 145 const SkImageInfo& genInfo = generator->getInfo(); 146 if (decodeInfo.dimensions() == genInfo.dimensions()) { 147 SkASSERT(fOrigin.x() == 0 && fOrigin.y() == 0); 148 // fast-case, no copy needed 149 return generator->tryGenerateBitmap(bitmap, decodeInfo, allocator); 150 } else { 151 // need to handle subsetting, so we first generate the full size version, and then 152 // "read" from it to get our subset. See https://bug.skia.org/4213 153 154 SkBitmap full; 155 if (!generator->tryGenerateBitmap(&full, 156 decodeInfo.makeWH(genInfo.width(), genInfo.height()), 157 allocator)) { 158 return false; 159 } 160 if (!bitmap->tryAllocPixels(decodeInfo, nullptr, full.getColorTable())) { 161 return false; 162 } 163 return full.readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 164 fOrigin.x(), fOrigin.y()); 165 } 166 } 167 168 bool SkImageCacherator::directGeneratePixels(const SkImageInfo& info, void* pixels, size_t rb, 169 int srcX, int srcY) { 170 ScopedGenerator generator(fSharedGenerator); 171 const SkImageInfo& genInfo = generator->getInfo(); 172 // Currently generators do not natively handle subsets, so check that first. 173 if (srcX || srcY || genInfo.width() != info.width() || genInfo.height() != info.height()) { 174 return false; 175 } 176 return generator->getPixels(info, pixels, rb); 177 } 178 179 ////////////////////////////////////////////////////////////////////////////////////////////////// 180 181 bool SkImageCacherator::lockAsBitmapOnlyIfAlreadyCached(SkBitmap* bitmap, CachedFormat format) { 182 return kNeedNewImageUniqueID != fUniqueIDs[format] && 183 SkBitmapCache::Find(SkBitmapCacheDesc::Make(fUniqueIDs[format], 184 fInfo.width(), fInfo.height()), bitmap) && 185 check_output_bitmap(*bitmap, fUniqueIDs[format]); 186 } 187 188 bool SkImageCacherator::tryLockAsBitmap(SkBitmap* bitmap, const SkImage* client, 189 SkImage::CachingHint chint, CachedFormat format, 190 const SkImageInfo& info) { 191 if (this->lockAsBitmapOnlyIfAlreadyCached(bitmap, format)) { 192 return true; 193 } 194 if (!this->generateBitmap(bitmap, info)) { 195 return false; 196 } 197 198 if (kNeedNewImageUniqueID == fUniqueIDs[format]) { 199 fUniqueIDs[format] = SkNextID::ImageID(); 200 } 201 bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]); 202 if (SkImage::kAllow_CachingHint == chint) { 203 SkBitmapCache::Add(SkBitmapCacheDesc::Make(fUniqueIDs[format], 204 fInfo.width(), fInfo.height()), *bitmap); 205 if (client) { 206 as_IB(client)->notifyAddedToCache(); 207 } 208 } 209 return true; 210 } 211 212 bool SkImageCacherator::lockAsBitmap(GrContext* context, SkBitmap* bitmap, const SkImage* client, 213 SkColorSpace* dstColorSpace, 214 SkImage::CachingHint chint) { 215 CachedFormat format = this->chooseCacheFormat(dstColorSpace); 216 SkImageInfo cacheInfo = this->buildCacheInfo(format); 217 218 if (kNeedNewImageUniqueID == fUniqueIDs[format]) { 219 fUniqueIDs[format] = SkNextID::ImageID(); 220 } 221 222 if (this->tryLockAsBitmap(bitmap, client, chint, format, cacheInfo)) { 223 return check_output_bitmap(*bitmap, fUniqueIDs[format]); 224 } 225 226 #if SK_SUPPORT_GPU 227 if (!context) { 228 bitmap->reset(); 229 return false; 230 } 231 232 // Try to get a texture and read it back to raster (and then cache that with our ID) 233 sk_sp<GrTextureProxy> proxy; 234 235 { 236 ScopedGenerator generator(fSharedGenerator); 237 proxy = generator->generateTexture(context, cacheInfo, fOrigin); 238 } 239 if (!proxy) { 240 bitmap->reset(); 241 return false; 242 } 243 244 if (!bitmap->tryAllocPixels(cacheInfo)) { 245 bitmap->reset(); 246 return false; 247 } 248 249 sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext( 250 proxy, 251 fInfo.refColorSpace())); // src colorSpace 252 if (!sContext) { 253 bitmap->reset(); 254 return false; 255 } 256 257 if (!sContext->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) { 258 bitmap->reset(); 259 return false; 260 } 261 262 bitmap->pixelRef()->setImmutableWithID(fUniqueIDs[format]); 263 if (SkImage::kAllow_CachingHint == chint) { 264 SkBitmapCache::Add(SkBitmapCacheDesc::Make(fUniqueIDs[format], 265 fInfo.width(), fInfo.height()), *bitmap); 266 if (client) { 267 as_IB(client)->notifyAddedToCache(); 268 } 269 } 270 return check_output_bitmap(*bitmap, fUniqueIDs[format]); 271 #else 272 return false; 273 #endif 274 } 275 276 ////////////////////////////////////////////////////////////////////////////////////////////////// 277 278 // Abstraction of GrCaps that handles the cases where we don't have a caps pointer (because 279 // we're in raster mode), or where GPU support is entirely missing. In theory, we only need the 280 // chosen format to be texturable, but that lets us choose F16 on GLES implemenations where we 281 // won't be able to read the texture back. We'd like to ensure that SkImake::makeNonTextureImage 282 // works, so we require that the formats we choose are renderable (as a proxy for being readable). 283 struct CacheCaps { 284 CacheCaps(const GrCaps* caps) : fCaps(caps) {} 285 286 #if SK_SUPPORT_GPU 287 bool supportsHalfFloat() const { 288 return !fCaps || 289 (fCaps->isConfigTexturable(kRGBA_half_GrPixelConfig) && 290 fCaps->isConfigRenderable(kRGBA_half_GrPixelConfig, false)); 291 } 292 293 bool supportsSRGB() const { 294 return !fCaps || 295 (fCaps->srgbSupport() && fCaps->isConfigTexturable(kSRGBA_8888_GrPixelConfig)); 296 } 297 298 bool supportsSBGR() const { 299 return !fCaps || fCaps->srgbSupport(); 300 } 301 #else 302 bool supportsHalfFloat() const { return true; } 303 bool supportsSRGB() const { return true; } 304 bool supportsSBGR() const { return true; } 305 #endif 306 307 const GrCaps* fCaps; 308 }; 309 310 SkImageCacherator::CachedFormat SkImageCacherator::chooseCacheFormat(SkColorSpace* dstColorSpace, 311 const GrCaps* grCaps) { 312 SkColorSpace* cs = fInfo.colorSpace(); 313 if (!cs || !dstColorSpace) { 314 return kLegacy_CachedFormat; 315 } 316 317 CacheCaps caps(grCaps); 318 switch (fInfo.colorType()) { 319 case kUnknown_SkColorType: 320 case kAlpha_8_SkColorType: 321 case kRGB_565_SkColorType: 322 case kARGB_4444_SkColorType: 323 // We don't support color space on these formats, so always decode in legacy mode: 324 // TODO: Ask the codec to decode these to something else (at least sRGB 8888)? 325 return kLegacy_CachedFormat; 326 327 case kIndex_8_SkColorType: 328 // We can't draw from indexed textures with a color space, so ask the codec to expand 329 if (cs->gammaCloseToSRGB()) { 330 if (caps.supportsSRGB()) { 331 return kSRGB8888_CachedFormat; 332 } else if (caps.supportsHalfFloat()) { 333 return kLinearF16_CachedFormat; 334 } else { 335 return kLegacy_CachedFormat; 336 } 337 } else { 338 if (caps.supportsHalfFloat()) { 339 return kLinearF16_CachedFormat; 340 } else if (caps.supportsSRGB()) { 341 return kSRGB8888_CachedFormat; 342 } else { 343 return kLegacy_CachedFormat; 344 } 345 } 346 347 case kGray_8_SkColorType: 348 // TODO: What do we do with grayscale sources that have strange color spaces attached? 349 // The codecs and color space xform don't handle this correctly (yet), so drop it on 350 // the floor. (Also, inflating by a factor of 8 is going to be unfortunate). 351 // As it is, we don't directly support sRGB grayscale, so ask the codec to convert 352 // it for us. This bypasses some really sketchy code GrUploadPixmapToTexture. 353 if (cs->gammaCloseToSRGB() && caps.supportsSRGB()) { 354 return kSRGB8888_CachedFormat; 355 } else { 356 return kLegacy_CachedFormat; 357 } 358 359 case kRGBA_8888_SkColorType: 360 if (cs->gammaCloseToSRGB()) { 361 if (caps.supportsSRGB()) { 362 return kAsIs_CachedFormat; 363 } else if (caps.supportsHalfFloat()) { 364 return kLinearF16_CachedFormat; 365 } else { 366 return kLegacy_CachedFormat; 367 } 368 } else { 369 if (caps.supportsHalfFloat()) { 370 return kLinearF16_CachedFormat; 371 } else if (caps.supportsSRGB()) { 372 return kSRGB8888_CachedFormat; 373 } else { 374 return kLegacy_CachedFormat; 375 } 376 } 377 378 case kBGRA_8888_SkColorType: 379 // Odd case. sBGRA isn't a real thing, so we may not have this texturable. 380 if (caps.supportsSBGR()) { 381 if (cs->gammaCloseToSRGB()) { 382 return kAsIs_CachedFormat; 383 } else if (caps.supportsHalfFloat()) { 384 return kLinearF16_CachedFormat; 385 } else if (caps.supportsSRGB()) { 386 return kSRGB8888_CachedFormat; 387 } else { 388 // sBGRA support without sRGBA is highly unlikely (impossible?) Nevertheless. 389 return kLegacy_CachedFormat; 390 } 391 } else { 392 if (cs->gammaCloseToSRGB()) { 393 if (caps.supportsSRGB()) { 394 return kSRGB8888_CachedFormat; 395 } else if (caps.supportsHalfFloat()) { 396 return kLinearF16_CachedFormat; 397 } else { 398 return kLegacy_CachedFormat; 399 } 400 } else { 401 if (caps.supportsHalfFloat()) { 402 return kLinearF16_CachedFormat; 403 } else if (caps.supportsSRGB()) { 404 return kSRGB8888_CachedFormat; 405 } else { 406 return kLegacy_CachedFormat; 407 } 408 } 409 } 410 411 case kRGBA_F16_SkColorType: 412 if (!caps.supportsHalfFloat()) { 413 if (caps.supportsSRGB()) { 414 return kSRGB8888_CachedFormat; 415 } else { 416 return kLegacy_CachedFormat; 417 } 418 } else if (cs->gammaIsLinear()) { 419 return kAsIs_CachedFormat; 420 } else { 421 return kLinearF16_CachedFormat; 422 } 423 } 424 SkDEBUGFAIL("Unreachable"); 425 return kLegacy_CachedFormat; 426 } 427 428 SkImageInfo SkImageCacherator::buildCacheInfo(CachedFormat format) { 429 switch (format) { 430 case kLegacy_CachedFormat: 431 return fInfo.makeColorSpace(nullptr); 432 case kAsIs_CachedFormat: 433 return fInfo; 434 case kLinearF16_CachedFormat: 435 return fInfo 436 .makeColorType(kRGBA_F16_SkColorType) 437 .makeColorSpace(as_CSB(fInfo.colorSpace())->makeLinearGamma()); 438 case kSRGB8888_CachedFormat: 439 return fInfo 440 .makeColorType(kRGBA_8888_SkColorType) 441 .makeColorSpace(as_CSB(fInfo.colorSpace())->makeSRGBGamma()); 442 default: 443 SkDEBUGFAIL("Invalid cached format"); 444 return fInfo; 445 } 446 } 447 448 ////////////////////////////////////////////////////////////////////////////////////////////////// 449 450 #if SK_SUPPORT_GPU 451 452 void SkImageCacherator::makeCacheKeyFromOrigKey(const GrUniqueKey& origKey, CachedFormat format, 453 GrUniqueKey* cacheKey) { 454 SkASSERT(!cacheKey->isValid()); 455 if (origKey.isValid()) { 456 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); 457 GrUniqueKey::Builder builder(cacheKey, origKey, kDomain, 1); 458 builder[0] = format; 459 } 460 } 461 462 #ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR 463 static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrSurfaceDesc desc) { 464 const void* rawStart; 465 GrPixelConfig config = GrIsCompressedTextureDataSupported(ctx, data, desc.fWidth, desc.fHeight, 466 &rawStart); 467 if (kUnknown_GrPixelConfig == config) { 468 return nullptr; 469 } 470 471 desc.fConfig = config; 472 return ctx->resourceProvider()->createTexture(desc, SkBudgeted::kYes, rawStart, 0); 473 } 474 #endif 475 476 class Generator_GrYUVProvider : public GrYUVProvider { 477 SkImageGenerator* fGen; 478 479 public: 480 Generator_GrYUVProvider(SkImageGenerator* gen) : fGen(gen) {} 481 482 uint32_t onGetID() override { return fGen->uniqueID(); } 483 bool onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const override { 484 return fGen->queryYUV8(sizeInfo, colorSpace); 485 } 486 bool onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) override { 487 return fGen->getYUV8Planes(sizeInfo, planes); 488 } 489 }; 490 491 static void set_key_on_proxy(GrResourceProvider* resourceProvider, 492 GrTextureProxy* proxy, const GrUniqueKey& key) { 493 if (key.isValid()) { 494 resourceProvider->assignUniqueKeyToProxy(key, proxy); 495 } 496 } 497 498 sk_sp<SkColorSpace> SkImageCacherator::getColorSpace(GrContext* ctx, SkColorSpace* dstColorSpace) { 499 // TODO: This isn't always correct. Picture generator currently produces textures in N32, 500 // and will (soon) emit them in an arbitrary (destination) space. We will need to stash that 501 // information in/on the key so we can return the correct space in case #1 of lockTexture. 502 CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps()); 503 SkImageInfo cacheInfo = this->buildCacheInfo(format); 504 return sk_ref_sp(cacheInfo.colorSpace()); 505 } 506 507 /* 508 * We have a 5 ways to try to return a texture (in sorted order) 509 * 510 * 1. Check the cache for a pre-existing one 511 * 2. Ask the generator to natively create one 512 * 3. Ask the generator to return a compressed form that the GPU might support 513 * 4. Ask the generator to return YUV planes, which the GPU can convert 514 * 5. Ask the generator to return RGB(A) data, which the GPU can convert 515 */ 516 sk_sp<GrTextureProxy> SkImageCacherator::lockTextureProxy(GrContext* ctx, 517 const GrUniqueKey& origKey, 518 const SkImage* client, 519 SkImage::CachingHint chint, 520 bool willBeMipped, 521 SkColorSpace* dstColorSpace) { 522 // Values representing the various texture lock paths we can take. Used for logging the path 523 // taken to a histogram. 524 enum LockTexturePath { 525 kFailure_LockTexturePath, 526 kPreExisting_LockTexturePath, 527 kNative_LockTexturePath, 528 kCompressed_LockTexturePath, 529 kYUV_LockTexturePath, 530 kRGBA_LockTexturePath, 531 }; 532 533 enum { kLockTexturePathCount = kRGBA_LockTexturePath + 1 }; 534 535 // Determine which cached format we're going to use (which may involve decoding to a different 536 // info than the generator provides). 537 CachedFormat format = this->chooseCacheFormat(dstColorSpace, ctx->caps()); 538 539 // Fold the cache format into our texture key 540 GrUniqueKey key; 541 this->makeCacheKeyFromOrigKey(origKey, format, &key); 542 543 // 1. Check the cache for a pre-existing one 544 if (key.isValid()) { 545 if (sk_sp<GrTextureProxy> proxy = ctx->resourceProvider()->findProxyByUniqueKey(key)) { 546 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kPreExisting_LockTexturePath, 547 kLockTexturePathCount); 548 return proxy; 549 } 550 } 551 552 // The CachedFormat is both an index for which cache "slot" we'll use to store this particular 553 // decoded variant of the encoded data, and also a recipe for how to transform the original 554 // info to get the one that we're going to decode to. 555 SkImageInfo cacheInfo = this->buildCacheInfo(format); 556 557 // 2. Ask the generator to natively create one 558 { 559 ScopedGenerator generator(fSharedGenerator); 560 if (sk_sp<GrTextureProxy> proxy = generator->generateTexture(ctx, cacheInfo, fOrigin)) { 561 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kNative_LockTexturePath, 562 kLockTexturePathCount); 563 set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key); 564 return proxy; 565 } 566 } 567 568 const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(cacheInfo, *ctx->caps()); 569 570 #ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR 571 // 3. Ask the generator to return a compressed form that the GPU might support 572 sk_sp<SkData> data(this->refEncoded(ctx)); 573 if (data) { 574 GrTexture* tex = load_compressed_into_texture(ctx, data, desc); 575 if (tex) { 576 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kCompressed_LockTexturePath, 577 kLockTexturePathCount); 578 return set_key_and_return(tex, key); 579 } 580 } 581 #endif 582 583 // 4. Ask the generator to return YUV planes, which the GPU can convert 584 if (!ctx->contextPriv().disableGpuYUVConversion()) { 585 ScopedGenerator generator(fSharedGenerator); 586 Generator_GrYUVProvider provider(generator); 587 if (sk_sp<GrTextureProxy> proxy = provider.refAsTextureProxy(ctx, desc, true)) { 588 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kYUV_LockTexturePath, 589 kLockTexturePathCount); 590 set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key); 591 return proxy; 592 } 593 } 594 595 // 5. Ask the generator to return RGB(A) data, which the GPU can convert 596 SkBitmap bitmap; 597 if (this->tryLockAsBitmap(&bitmap, client, chint, format, cacheInfo)) { 598 sk_sp<GrTextureProxy> proxy; 599 if (willBeMipped) { 600 proxy = GrGenerateMipMapsAndUploadToTextureProxy(ctx, bitmap, dstColorSpace); 601 } 602 if (!proxy) { 603 proxy = GrUploadBitmapToTextureProxy(ctx->resourceProvider(), bitmap); 604 } 605 if (proxy) { 606 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kRGBA_LockTexturePath, 607 kLockTexturePathCount); 608 set_key_on_proxy(ctx->resourceProvider(), proxy.get(), key); 609 return proxy; 610 } 611 } 612 SK_HISTOGRAM_ENUMERATION("LockTexturePath", kFailure_LockTexturePath, 613 kLockTexturePathCount); 614 return nullptr; 615 } 616 617 /////////////////////////////////////////////////////////////////////////////////////////////////// 618 619 sk_sp<GrTextureProxy> SkImageCacherator::lockAsTextureProxy(GrContext* ctx, 620 const GrSamplerParams& params, 621 SkColorSpace* dstColorSpace, 622 sk_sp<SkColorSpace>* texColorSpace, 623 const SkImage* client, 624 SkScalar scaleAdjust[2], 625 SkImage::CachingHint chint) { 626 if (!ctx) { 627 return nullptr; 628 } 629 630 return GrImageTextureMaker(ctx, this, client, chint).refTextureProxyForParams(params, 631 dstColorSpace, 632 texColorSpace, 633 scaleAdjust); 634 } 635 636 #endif 637