Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2011 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 "GrContext.h"
      9 #include "GrBackendSemaphore.h"
     10 #include "GrDrawingManager.h"
     11 #include "GrGpu.h"
     12 #include "GrMemoryPool.h"
     13 #include "GrPathRendererChain.h"
     14 #include "GrProxyProvider.h"
     15 #include "GrRenderTargetProxy.h"
     16 #include "GrResourceCache.h"
     17 #include "GrResourceProvider.h"
     18 #include "GrSemaphore.h"
     19 #include "GrSoftwarePathRenderer.h"
     20 #include "GrTracing.h"
     21 #include "SkDeferredDisplayList.h"
     22 #include "SkGr.h"
     23 #include "SkImageInfoPriv.h"
     24 #include "SkMakeUnique.h"
     25 #include "SkSurface_Gpu.h"
     26 #include "SkTaskGroup.h"
     27 #include "SkTraceMemoryDump.h"
     28 #include "effects/GrConfigConversionEffect.h"
     29 #include "effects/GrSkSLFP.h"
     30 #include "ccpr/GrCoverageCountingPathRenderer.h"
     31 #include "text/GrTextBlobCache.h"
     32 #include "text/GrTextContext.h"
     33 #include <atomic>
     34 #include <unordered_map>
     35 
     36 #define ASSERT_OWNED_PROXY(P) \
     37     SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == this)
     38 
     39 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
     40 #define ASSERT_SINGLE_OWNER \
     41     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
     42 #define RETURN_IF_ABANDONED if (this->abandoned()) { return; }
     43 #define RETURN_FALSE_IF_ABANDONED if (this->abandoned()) { return false; }
     44 #define RETURN_NULL_IF_ABANDONED if (this->abandoned()) { return nullptr; }
     45 
     46 ////////////////////////////////////////////////////////////////////////////////
     47 
     48 GrContext::GrContext(GrBackendApi backend, const GrContextOptions& options, int32_t contextID)
     49         : INHERITED(backend, options, contextID) {
     50     fResourceCache = nullptr;
     51     fResourceProvider = nullptr;
     52 }
     53 
     54 GrContext::~GrContext() {
     55     ASSERT_SINGLE_OWNER
     56 
     57     if (this->drawingManager()) {
     58         this->drawingManager()->cleanup();
     59     }
     60     delete fResourceProvider;
     61     delete fResourceCache;
     62 }
     63 
     64 bool GrContext::init(sk_sp<const GrCaps> caps, sk_sp<GrSkSLFPFactoryCache> FPFactoryCache) {
     65     ASSERT_SINGLE_OWNER
     66     SkASSERT(fThreadSafeProxy); // needs to have been initialized by derived classes
     67     SkASSERT(this->proxyProvider());
     68 
     69     if (!INHERITED::init(std::move(caps), std::move(FPFactoryCache))) {
     70         return false;
     71     }
     72 
     73     SkASSERT(this->caps());
     74     SkASSERT(this->getGrStrikeCache());
     75     SkASSERT(this->getTextBlobCache());
     76 
     77     if (fGpu) {
     78         fResourceCache = new GrResourceCache(this->caps(), this->singleOwner(), this->contextID());
     79         fResourceProvider = new GrResourceProvider(fGpu.get(), fResourceCache, this->singleOwner(),
     80                                                    this->explicitlyAllocateGPUResources());
     81     }
     82 
     83     if (fResourceCache) {
     84         fResourceCache->setProxyProvider(this->proxyProvider());
     85     }
     86 
     87     fDidTestPMConversions = false;
     88 
     89     // DDL TODO: we need to think through how the task group & persistent cache
     90     // get passed on to/shared between all the DDLRecorders created with this context.
     91     if (this->options().fExecutor) {
     92         fTaskGroup = skstd::make_unique<SkTaskGroup>(*this->options().fExecutor);
     93     }
     94 
     95     fPersistentCache = this->options().fPersistentCache;
     96 
     97     return true;
     98 }
     99 
    100 sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
    101     return fThreadSafeProxy;
    102 }
    103 
    104 //////////////////////////////////////////////////////////////////////////////
    105 
    106 void GrContext::abandonContext() {
    107     if (this->abandoned()) {
    108         return;
    109     }
    110 
    111     INHERITED::abandonContext();
    112 
    113     fResourceProvider->abandon();
    114 
    115     // Need to cleanup the drawing manager first so all the render targets
    116     // will be released/forgotten before they too are abandoned.
    117     this->drawingManager()->cleanup();
    118 
    119     // abandon first to so destructors
    120     // don't try to free the resources in the API.
    121     fResourceCache->abandonAll();
    122 
    123     fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
    124 }
    125 
    126 void GrContext::releaseResourcesAndAbandonContext() {
    127     if (this->abandoned()) {
    128         return;
    129     }
    130 
    131     INHERITED::abandonContext();
    132 
    133     fResourceProvider->abandon();
    134 
    135     // Need to cleanup the drawing manager first so all the render targets
    136     // will be released/forgotten before they too are abandoned.
    137     this->drawingManager()->cleanup();
    138 
    139     // Release all resources in the backend 3D API.
    140     fResourceCache->releaseAll();
    141 
    142     fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
    143 }
    144 
    145 void GrContext::resetGLTextureBindings() {
    146     if (this->abandoned() || this->backend() != GrBackendApi::kOpenGL) {
    147         return;
    148     }
    149     fGpu->resetTextureBindings();
    150 }
    151 
    152 void GrContext::resetContext(uint32_t state) {
    153     ASSERT_SINGLE_OWNER
    154     fGpu->markContextDirty(state);
    155 }
    156 
    157 void GrContext::freeGpuResources() {
    158     ASSERT_SINGLE_OWNER
    159 
    160     // TODO: the glyph cache doesn't hold any GpuResources so this call should not be needed here.
    161     // Some slack in the GrTextBlob's implementation requires it though. That could be fixed.
    162     this->getGrStrikeCache()->freeAll();
    163 
    164     this->drawingManager()->freeGpuResources();
    165 
    166     fResourceCache->purgeAllUnlocked();
    167 }
    168 
    169 void GrContext::purgeUnlockedResources(bool scratchResourcesOnly) {
    170     ASSERT_SINGLE_OWNER
    171     fResourceCache->purgeUnlockedResources(scratchResourcesOnly);
    172     fResourceCache->purgeAsNeeded();
    173 
    174     // The textBlob Cache doesn't actually hold any GPU resource but this is a convenient
    175     // place to purge stale blobs
    176     this->getTextBlobCache()->purgeStaleBlobs();
    177 }
    178 
    179 void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) {
    180     ASSERT_SINGLE_OWNER
    181 
    182     auto purgeTime = GrStdSteadyClock::now() - msNotUsed;
    183 
    184     fResourceCache->purgeAsNeeded();
    185     fResourceCache->purgeResourcesNotUsedSince(purgeTime);
    186 
    187     if (auto ccpr = this->drawingManager()->getCoverageCountingPathRenderer()) {
    188         ccpr->purgeCacheEntriesOlderThan(this->proxyProvider(), purgeTime);
    189     }
    190 
    191     // The textBlob Cache doesn't actually hold any GPU resource but this is a convenient
    192     // place to purge stale blobs
    193     this->getTextBlobCache()->purgeStaleBlobs();
    194 }
    195 
    196 void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
    197     ASSERT_SINGLE_OWNER
    198     fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources);
    199 }
    200 
    201 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
    202     ASSERT_SINGLE_OWNER
    203 
    204     if (resourceCount) {
    205         *resourceCount = fResourceCache->getBudgetedResourceCount();
    206     }
    207     if (resourceBytes) {
    208         *resourceBytes = fResourceCache->getBudgetedResourceBytes();
    209     }
    210 }
    211 
    212 size_t GrContext::getResourceCachePurgeableBytes() const {
    213     ASSERT_SINGLE_OWNER
    214     return fResourceCache->getPurgeableBytes();
    215 }
    216 
    217 ////////////////////////////////////////////////////////////////////////////////
    218 
    219 int GrContext::maxTextureSize() const { return this->caps()->maxTextureSize(); }
    220 
    221 int GrContext::maxRenderTargetSize() const { return this->caps()->maxRenderTargetSize(); }
    222 
    223 bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const {
    224     GrPixelConfig config = SkColorType2GrPixelConfig(colorType);
    225     return this->caps()->isConfigTexturable(config);
    226 }
    227 
    228 int GrContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const {
    229     GrPixelConfig config = SkColorType2GrPixelConfig(colorType);
    230     return this->caps()->maxRenderTargetSampleCount(config);
    231 }
    232 
    233 ////////////////////////////////////////////////////////////////////////////////
    234 
    235 bool GrContext::wait(int numSemaphores, const GrBackendSemaphore waitSemaphores[]) {
    236     if (!fGpu || fGpu->caps()->fenceSyncSupport()) {
    237         return false;
    238     }
    239     for (int i = 0; i < numSemaphores; ++i) {
    240         sk_sp<GrSemaphore> sema = fResourceProvider->wrapBackendSemaphore(
    241                 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
    242                 kAdopt_GrWrapOwnership);
    243         fGpu->waitSemaphore(std::move(sema));
    244     }
    245     return true;
    246 }
    247 
    248 
    249 ////////////////////////////////////////////////////////////////////////////////
    250 
    251 void GrContext::flush() {
    252     ASSERT_SINGLE_OWNER
    253     RETURN_IF_ABANDONED
    254 
    255     this->drawingManager()->flush(nullptr, SkSurface::BackendSurfaceAccess::kNoAccess,
    256                                   kNone_GrFlushFlags, 0, nullptr, nullptr, nullptr);
    257 }
    258 
    259 GrSemaphoresSubmitted GrContext::flush(GrFlushFlags flags, int numSemaphores,
    260                                        GrBackendSemaphore signalSemaphores[],
    261                                        GrGpuFinishedProc finishedProc,
    262                                        GrGpuFinishedContext finishedContext) {
    263     ASSERT_SINGLE_OWNER
    264     if (this->abandoned()) {
    265         return GrSemaphoresSubmitted::kNo;
    266     }
    267 
    268     return this->drawingManager()->flush(nullptr, SkSurface::BackendSurfaceAccess::kNoAccess,
    269                                          flags, numSemaphores, signalSemaphores, finishedProc,
    270                                          finishedContext);
    271 }
    272 
    273 ////////////////////////////////////////////////////////////////////////////////
    274 
    275 void GrContext::storeVkPipelineCacheData() {
    276     if (fGpu) {
    277         fGpu->storeVkPipelineCacheData();
    278     }
    279 }
    280 
    281 ////////////////////////////////////////////////////////////////////////////////
    282 
    283 std::unique_ptr<GrFragmentProcessor> GrContext::createPMToUPMEffect(
    284         std::unique_ptr<GrFragmentProcessor> fp) {
    285     ASSERT_SINGLE_OWNER
    286     // We should have already called this->validPMUPMConversionExists() in this case
    287     SkASSERT(fDidTestPMConversions);
    288     // ...and it should have succeeded
    289     SkASSERT(this->validPMUPMConversionExists());
    290 
    291     return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToUnpremul);
    292 }
    293 
    294 std::unique_ptr<GrFragmentProcessor> GrContext::createUPMToPMEffect(
    295         std::unique_ptr<GrFragmentProcessor> fp) {
    296     ASSERT_SINGLE_OWNER
    297     // We should have already called this->validPMUPMConversionExists() in this case
    298     SkASSERT(fDidTestPMConversions);
    299     // ...and it should have succeeded
    300     SkASSERT(this->validPMUPMConversionExists());
    301 
    302     return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToPremul);
    303 }
    304 
    305 bool GrContext::validPMUPMConversionExists() {
    306     ASSERT_SINGLE_OWNER
    307     if (!fDidTestPMConversions) {
    308         fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this);
    309         fDidTestPMConversions = true;
    310     }
    311 
    312     // The PM<->UPM tests fail or succeed together so we only need to check one.
    313     return fPMUPMConversionsRoundTrip;
    314 }
    315 
    316 bool GrContext::supportsDistanceFieldText() const {
    317     return this->caps()->shaderCaps()->supportsDistanceFieldText();
    318 }
    319 
    320 //////////////////////////////////////////////////////////////////////////////
    321 
    322 // DDL TODO: remove 'maxResources'
    323 void GrContext::getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const {
    324     ASSERT_SINGLE_OWNER
    325     if (maxResources) {
    326         *maxResources = fResourceCache->getMaxResourceCount();
    327     }
    328     if (maxResourceBytes) {
    329         *maxResourceBytes = fResourceCache->getMaxResourceBytes();
    330     }
    331 }
    332 
    333 void GrContext::setResourceCacheLimits(int maxResources, size_t maxResourceBytes) {
    334     ASSERT_SINGLE_OWNER
    335     fResourceCache->setLimits(maxResources, maxResourceBytes);
    336 }
    337 
    338 //////////////////////////////////////////////////////////////////////////////
    339 void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
    340     ASSERT_SINGLE_OWNER
    341     fResourceCache->dumpMemoryStatistics(traceMemoryDump);
    342     traceMemoryDump->dumpNumericValue("skia/gr_text_blob_cache", "size", "bytes",
    343                                       this->getTextBlobCache()->usedBytes());
    344 }
    345 
    346