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