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