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     // Dump resource as "skia/gpu_resources/resource_#".
     73     SkString dumpName("skia/gpu_resources/resource_");
     74     dumpName.appendU32(this->uniqueID().asUInt());
     75 
     76     traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", this->gpuMemorySize());
     77 
     78     if (this->isPurgeable()) {
     79         traceMemoryDump->dumpNumericValue(dumpName.c_str(), "purgeable_size", "bytes",
     80                                           this->gpuMemorySize());
     81     }
     82 
     83     // Call setMemoryBacking to allow sub-classes with implementation specific backings (such as GL
     84     // objects) to provide additional information.
     85     this->setMemoryBacking(traceMemoryDump, dumpName);
     86 }
     87 
     88 const GrContext* GrGpuResource::getContext() const {
     89     if (fGpu) {
     90         return fGpu->getContext();
     91     } else {
     92         return nullptr;
     93     }
     94 }
     95 
     96 GrContext* GrGpuResource::getContext() {
     97     if (fGpu) {
     98         return fGpu->getContext();
     99     } else {
    100         return nullptr;
    101     }
    102 }
    103 
    104 void GrGpuResource::didChangeGpuMemorySize() const {
    105     if (this->wasDestroyed()) {
    106         return;
    107     }
    108 
    109     size_t oldSize = fGpuMemorySize;
    110     SkASSERT(kInvalidGpuMemorySize != oldSize);
    111     fGpuMemorySize = kInvalidGpuMemorySize;
    112     get_resource_cache(fGpu)->resourceAccess().didChangeGpuMemorySize(this, oldSize);
    113 }
    114 
    115 void GrGpuResource::removeUniqueKey() {
    116     if (this->wasDestroyed()) {
    117         return;
    118     }
    119     SkASSERT(fUniqueKey.isValid());
    120     get_resource_cache(fGpu)->resourceAccess().removeUniqueKey(this);
    121 }
    122 
    123 void GrGpuResource::setUniqueKey(const GrUniqueKey& key) {
    124     SkASSERT(this->internalHasRef());
    125     SkASSERT(key.isValid());
    126 
    127     // Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped
    128     // resources are a special case: the unique keys give us a weak ref so that we can reuse the
    129     // same resource (rather than re-wrapping). When a wrapped resource is no longer referenced,
    130     // it will always be released - it is never converted to a scratch resource.
    131     if (SkBudgeted::kNo == this->resourcePriv().isBudgeted() && !this->fRefsWrappedObjects) {
    132         return;
    133     }
    134 
    135     if (this->wasDestroyed()) {
    136         return;
    137     }
    138 
    139     get_resource_cache(fGpu)->resourceAccess().changeUniqueKey(this, key);
    140 }
    141 
    142 void GrGpuResource::notifyAllCntsAreZero(CntType lastCntTypeToReachZero) const {
    143     if (this->wasDestroyed()) {
    144         // We've already been removed from the cache. Goodbye cruel world!
    145         delete this;
    146         return;
    147     }
    148 
    149     // We should have already handled this fully in notifyRefCntIsZero().
    150     SkASSERT(kRef_CntType != lastCntTypeToReachZero);
    151 
    152     GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
    153     static const uint32_t kFlag =
    154         GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
    155     get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, kFlag);
    156 }
    157 
    158 bool GrGpuResource::notifyRefCountIsZero() const {
    159     if (this->wasDestroyed()) {
    160         // handle this in notifyAllCntsAreZero().
    161         return true;
    162     }
    163 
    164     GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
    165     uint32_t flags = GrResourceCache::ResourceAccess::kRefCntReachedZero_RefNotificationFlag;
    166     if (!this->internalHasPendingIO()) {
    167         flags |= GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
    168     }
    169     get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, flags);
    170 
    171     // There is no need to call our notifyAllCntsAreZero function at this point since we already
    172     // told the cache about the state of cnts.
    173     return false;
    174 }
    175 
    176 void GrGpuResource::removeScratchKey() {
    177     if (!this->wasDestroyed() && fScratchKey.isValid()) {
    178         get_resource_cache(fGpu)->resourceAccess().willRemoveScratchKey(this);
    179         fScratchKey.reset();
    180     }
    181 }
    182 
    183 void GrGpuResource::makeBudgeted() {
    184     if (!this->wasDestroyed() && SkBudgeted::kNo == fBudgeted) {
    185         // Currently resources referencing wrapped objects are not budgeted.
    186         SkASSERT(!fRefsWrappedObjects);
    187         fBudgeted = SkBudgeted::kYes;
    188         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
    189     }
    190 }
    191 
    192 void GrGpuResource::makeUnbudgeted() {
    193     if (!this->wasDestroyed() && SkBudgeted::kYes == fBudgeted &&
    194         !fUniqueKey.isValid()) {
    195         fBudgeted = SkBudgeted::kNo;
    196         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
    197     }
    198 }
    199 
    200 uint32_t GrGpuResource::CreateUniqueID() {
    201     static int32_t gUniqueID = SK_InvalidUniqueID;
    202     uint32_t id;
    203     do {
    204         id = static_cast<uint32_t>(sk_atomic_inc(&gUniqueID) + 1);
    205     } while (id == SK_InvalidUniqueID);
    206     return id;
    207 }
    208