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()->contextPriv().getResourceCache());
     21     return gpu->getContext()->contextPriv().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::notifyAllCntsAreZero(CntType lastCntTypeToReachZero) const {
    159     GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
    160     mutableThis->removedLastRefOrPendingIO();
    161     if (this->wasDestroyed()) {
    162         // We've already been removed from the cache. Goodbye cruel world!
    163         delete this;
    164         return;
    165     }
    166 
    167     // We should have already handled this fully in notifyRefCntIsZero().
    168     SkASSERT(kRef_CntType != lastCntTypeToReachZero);
    169 
    170     static const uint32_t kFlag =
    171         GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
    172     get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, kFlag);
    173 }
    174 
    175 bool GrGpuResource::notifyRefCountIsZero() const {
    176     if (this->wasDestroyed()) {
    177         // handle this in notifyAllCntsAreZero().
    178         return true;
    179     }
    180 
    181     GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
    182     uint32_t flags = GrResourceCache::ResourceAccess::kRefCntReachedZero_RefNotificationFlag;
    183     if (!this->internalHasPendingIO()) {
    184         flags |= GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
    185         mutableThis->removedLastRefOrPendingIO();
    186     }
    187     get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, flags);
    188 
    189     // There is no need to call our notifyAllCntsAreZero function at this point since we already
    190     // told the cache about the state of cnts.
    191     return false;
    192 }
    193 
    194 void GrGpuResource::removeScratchKey() {
    195     if (!this->wasDestroyed() && fScratchKey.isValid()) {
    196         get_resource_cache(fGpu)->resourceAccess().willRemoveScratchKey(this);
    197         fScratchKey.reset();
    198     }
    199 }
    200 
    201 void GrGpuResource::makeBudgeted() {
    202     // We should never make a wrapped resource budgeted.
    203     SkASSERT(!fRefsWrappedObjects);
    204     // Only wrapped resources can be in the kUnbudgetedCacheable state.
    205     SkASSERT(fBudgetedType != GrBudgetedType::kUnbudgetedCacheable);
    206     if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable) {
    207         // Currently resources referencing wrapped objects are not budgeted.
    208         fBudgetedType = GrBudgetedType::kBudgeted;
    209         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
    210     }
    211 }
    212 
    213 void GrGpuResource::makeUnbudgeted() {
    214     if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kBudgeted &&
    215         !fUniqueKey.isValid()) {
    216         fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
    217         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
    218     }
    219 }
    220 
    221 uint32_t GrGpuResource::CreateUniqueID() {
    222     static std::atomic<uint32_t> nextID{1};
    223     uint32_t id;
    224     do {
    225         id = nextID++;
    226     } while (id == SK_InvalidUniqueID);
    227     return id;
    228 }
    229