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 "GrGpuResource.h"
      9 #include "GrContext.h"
     10 #include "GrContextPriv.h"
     11 #include "GrResourceCache.h"
     12 #include "GrGpu.h"
     13 #include "GrGpuResourcePriv.h"
     14 #include "SkTraceMemoryDump.h"
     15 #include <atomic>
     16 
     17 static inline GrResourceCache* get_resource_cache(GrGpu* gpu) {
     18     SkASSERT(gpu);
     19     SkASSERT(gpu->getContext());
     20     SkASSERT(gpu->getContext()->priv().getResourceCache());
     21     return gpu->getContext()->priv().getResourceCache();
     22 }
     23 
     24 GrGpuResource::GrGpuResource(GrGpu* gpu) : fGpu(gpu), fUniqueID(CreateUniqueID()) {
     25     SkDEBUGCODE(fCacheArrayIndex = -1);
     26 }
     27 
     28 void GrGpuResource::registerWithCache(SkBudgeted budgeted) {
     29     SkASSERT(fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable);
     30     fBudgetedType = budgeted == SkBudgeted::kYes ? GrBudgetedType::kBudgeted
     31                                                  : GrBudgetedType::kUnbudgetedUncacheable;
     32     this->computeScratchKey(&fScratchKey);
     33     get_resource_cache(fGpu)->resourceAccess().insertResource(this);
     34 }
     35 
     36 void GrGpuResource::registerWithCacheWrapped(GrWrapCacheable wrapType) {
     37     SkASSERT(fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable);
     38     // Resources referencing wrapped objects are never budgeted. They may be cached or uncached.
     39     fBudgetedType = wrapType == GrWrapCacheable::kNo ? GrBudgetedType::kUnbudgetedUncacheable
     40                                                      : GrBudgetedType::kUnbudgetedCacheable;
     41     fRefsWrappedObjects = true;
     42     get_resource_cache(fGpu)->resourceAccess().insertResource(this);
     43 }
     44 
     45 GrGpuResource::~GrGpuResource() {
     46     // The cache should have released or destroyed this resource.
     47     SkASSERT(this->wasDestroyed());
     48 }
     49 
     50 void GrGpuResource::release() {
     51     SkASSERT(fGpu);
     52     this->onRelease();
     53     get_resource_cache(fGpu)->resourceAccess().removeResource(this);
     54     fGpu = nullptr;
     55     fGpuMemorySize = 0;
     56 }
     57 
     58 void GrGpuResource::abandon() {
     59     if (this->wasDestroyed()) {
     60         return;
     61     }
     62     SkASSERT(fGpu);
     63     this->onAbandon();
     64     get_resource_cache(fGpu)->resourceAccess().removeResource(this);
     65     fGpu = nullptr;
     66     fGpuMemorySize = 0;
     67 }
     68 
     69 void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
     70     if (this->fRefsWrappedObjects && !traceMemoryDump->shouldDumpWrappedObjects()) {
     71         return;
     72     }
     73 
     74     this->dumpMemoryStatisticsPriv(traceMemoryDump, this->getResourceName(),
     75                                    this->getResourceType(), this->gpuMemorySize());
     76 }
     77 
     78 void GrGpuResource::dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump,
     79                                              const SkString& resourceName,
     80                                              const char* type, size_t size) const {
     81     const char* tag = "Scratch";
     82     if (fUniqueKey.isValid()) {
     83         tag = (fUniqueKey.tag() != nullptr) ? fUniqueKey.tag() : "Other";
     84     }
     85 
     86     traceMemoryDump->dumpNumericValue(resourceName.c_str(), "size", "bytes", size);
     87     traceMemoryDump->dumpStringValue(resourceName.c_str(), "type", type);
     88     traceMemoryDump->dumpStringValue(resourceName.c_str(), "category", tag);
     89     if (this->isPurgeable()) {
     90         traceMemoryDump->dumpNumericValue(resourceName.c_str(), "purgeable_size", "bytes", size);
     91     }
     92 
     93     this->setMemoryBacking(traceMemoryDump, resourceName);
     94 }
     95 
     96 bool GrGpuResource::isPurgeable() const {
     97     // Resources in the kUnbudgetedCacheable state are never purgeable when they have a unique
     98     // key. The key must be removed/invalidated to make them purgeable.
     99     return !this->hasRefOrPendingIO() &&
    100            !(fBudgetedType == GrBudgetedType::kUnbudgetedCacheable && fUniqueKey.isValid());
    101 }
    102 
    103 bool GrGpuResource::hasRefOrPendingIO() const {
    104     return this->internalHasRef() || this->internalHasPendingIO();
    105 }
    106 
    107 SkString GrGpuResource::getResourceName() const {
    108     // Dump resource as "skia/gpu_resources/resource_#".
    109     SkString resourceName("skia/gpu_resources/resource_");
    110     resourceName.appendU32(this->uniqueID().asUInt());
    111     return resourceName;
    112 }
    113 
    114 const GrContext* GrGpuResource::getContext() const {
    115     if (fGpu) {
    116         return fGpu->getContext();
    117     } else {
    118         return nullptr;
    119     }
    120 }
    121 
    122 GrContext* GrGpuResource::getContext() {
    123     if (fGpu) {
    124         return fGpu->getContext();
    125     } else {
    126         return nullptr;
    127     }
    128 }
    129 
    130 void GrGpuResource::removeUniqueKey() {
    131     if (this->wasDestroyed()) {
    132         return;
    133     }
    134     SkASSERT(fUniqueKey.isValid());
    135     get_resource_cache(fGpu)->resourceAccess().removeUniqueKey(this);
    136 }
    137 
    138 void GrGpuResource::setUniqueKey(const GrUniqueKey& key) {
    139     SkASSERT(this->internalHasRef());
    140     SkASSERT(key.isValid());
    141 
    142     // Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped
    143     // resources are a special case: the unique keys give us a weak ref so that we can reuse the
    144     // same resource (rather than re-wrapping). When a wrapped resource is no longer referenced,
    145     // it will always be released - it is never converted to a scratch resource.
    146     if (this->resourcePriv().budgetedType() != GrBudgetedType::kBudgeted &&
    147         !this->fRefsWrappedObjects) {
    148         return;
    149     }
    150 
    151     if (this->wasDestroyed()) {
    152         return;
    153     }
    154 
    155     get_resource_cache(fGpu)->resourceAccess().changeUniqueKey(this, key);
    156 }
    157 
    158 void GrGpuResource::notifyAllCntsWillBeZero() const {
    159     GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
    160     mutableThis->willRemoveLastRefOrPendingIO();
    161 }
    162 
    163 void GrGpuResource::notifyAllCntsAreZero(CntType lastCntTypeToReachZero) const {
    164     if (this->wasDestroyed()) {
    165         // We've already been removed from the cache. Goodbye cruel world!
    166         delete this;
    167         return;
    168     }
    169 
    170     // We should have already handled this fully in notifyRefCntIsZero().
    171     SkASSERT(kRef_CntType != lastCntTypeToReachZero);
    172 
    173     static const uint32_t kFlag =
    174         GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
    175     GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
    176     get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, kFlag);
    177 }
    178 
    179 bool GrGpuResource::notifyRefCountIsZero() const {
    180     if (this->wasDestroyed()) {
    181         // handle this in notifyAllCntsAreZero().
    182         return true;
    183     }
    184 
    185     GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
    186     uint32_t flags = GrResourceCache::ResourceAccess::kRefCntReachedZero_RefNotificationFlag;
    187     if (!this->internalHasPendingIO()) {
    188         flags |= GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
    189     }
    190     get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, flags);
    191 
    192     // There is no need to call our notifyAllCntsAreZero function at this point since we already
    193     // told the cache about the state of cnts.
    194     return false;
    195 }
    196 
    197 void GrGpuResource::removeScratchKey() {
    198     if (!this->wasDestroyed() && fScratchKey.isValid()) {
    199         get_resource_cache(fGpu)->resourceAccess().willRemoveScratchKey(this);
    200         fScratchKey.reset();
    201     }
    202 }
    203 
    204 void GrGpuResource::makeBudgeted() {
    205     // We should never make a wrapped resource budgeted.
    206     SkASSERT(!fRefsWrappedObjects);
    207     // Only wrapped resources can be in the kUnbudgetedCacheable state.
    208     SkASSERT(fBudgetedType != GrBudgetedType::kUnbudgetedCacheable);
    209     if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable) {
    210         // Currently resources referencing wrapped objects are not budgeted.
    211         fBudgetedType = GrBudgetedType::kBudgeted;
    212         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
    213     }
    214 }
    215 
    216 void GrGpuResource::makeUnbudgeted() {
    217     if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kBudgeted &&
    218         !fUniqueKey.isValid()) {
    219         fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
    220         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
    221     }
    222 }
    223 
    224 uint32_t GrGpuResource::CreateUniqueID() {
    225     static std::atomic<uint32_t> nextID{1};
    226     uint32_t id;
    227     do {
    228         id = nextID++;
    229     } while (id == SK_InvalidUniqueID);
    230     return id;
    231 }
    232