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