LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkImageCacherator.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 293 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 35 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13