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