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 "include/core/SkTraceMemoryDump.h" 9#include "include/gpu/GrDirectContext.h" 10#include "src/gpu/GrDirectContextPriv.h" 11#include "src/gpu/GrGpu.h" 12#include "src/gpu/GrGpuResource.h" 13#include "src/gpu/GrGpuResourcePriv.h" 14#include "src/gpu/GrResourceCache.h" 15#include <atomic> 16 17static inline GrResourceCache* get_resource_cache(GrGpu* gpu) { 18 SkASSERT(gpu); 19 SkASSERT(gpu->getContext()); 20 SkASSERT(gpu->getContext()->priv().getResourceCache()); 21 return gpu->getContext()->priv().getResourceCache(); 22} 23 24GrGpuResource::GrGpuResource(GrGpu* gpu) : fGpu(gpu), fUniqueID(CreateUniqueID()) { 25 SkDEBUGCODE(fCacheArrayIndex = -1); 26 auto cache = get_resource_cache(fGpu); 27 if (cache) { 28 fGrResourceTag = cache->resourceAccess().getCurrentGrResourceTag(); 29 } 30} 31 32void GrGpuResource::registerWithCache(SkBudgeted budgeted) { 33 SkASSERT(fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable); 34 fBudgetedType = budgeted == SkBudgeted::kYes ? GrBudgetedType::kBudgeted 35 : GrBudgetedType::kUnbudgetedUncacheable; 36 this->computeScratchKey(&fScratchKey); 37 get_resource_cache(fGpu)->resourceAccess().insertResource(this); 38} 39 40void GrGpuResource::registerWithCacheWrapped(GrWrapCacheable wrapType) { 41 SkASSERT(fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable); 42 // Resources referencing wrapped objects are never budgeted. They may be cached or uncached. 43 fBudgetedType = wrapType == GrWrapCacheable::kNo ? GrBudgetedType::kUnbudgetedUncacheable 44 : GrBudgetedType::kUnbudgetedCacheable; 45 fRefsWrappedObjects = true; 46 get_resource_cache(fGpu)->resourceAccess().insertResource(this); 47} 48 49GrGpuResource::~GrGpuResource() { 50 // The cache should have released or destroyed this resource. 51 SkASSERT(this->wasDestroyed()); 52} 53 54void GrGpuResource::release() { 55 SkASSERT(fGpu); 56 std::lock_guard<std::mutex> lock(mutex_); 57 if (!fGpu) { 58 SkDebugf("OHOS GrGpuResource::release(), fGpu == nullptr"); 59 return; 60 } 61 this->onRelease(); 62 get_resource_cache(fGpu)->resourceAccess().removeResource(this); 63 fGpu = nullptr; 64 fGpuMemorySize = 0; 65} 66 67void GrGpuResource::abandon() { 68 if (this->wasDestroyed()) { 69 return; 70 } 71 SkASSERT(fGpu); 72 this->onAbandon(); 73 get_resource_cache(fGpu)->resourceAccess().removeResource(this); 74 fGpu = nullptr; 75 fGpuMemorySize = 0; 76} 77 78void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { 79 if (this->fRefsWrappedObjects && !traceMemoryDump->shouldDumpWrappedObjects()) { 80 return; 81 } 82 83 this->dumpMemoryStatisticsPriv(traceMemoryDump, this->getResourceName(), 84 this->getResourceType(), this->gpuMemorySize()); 85} 86 87void GrGpuResource::dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump, 88 const SkString& resourceName, 89 const char* type, size_t size) const { 90 const char* tag = "Scratch"; 91 if (fUniqueKey.isValid()) { 92 tag = (fUniqueKey.tag() != nullptr) ? fUniqueKey.tag() : "Other"; 93 } 94 95 traceMemoryDump->dumpNumericValue(resourceName.c_str(), "size", "bytes", size); 96 traceMemoryDump->dumpStringValue(resourceName.c_str(), "type", type); 97 traceMemoryDump->dumpStringValue(resourceName.c_str(), "category", tag); 98 if (this->isPurgeable()) { 99 traceMemoryDump->dumpNumericValue(resourceName.c_str(), "purgeable_size", "bytes", size); 100 } 101 if (traceMemoryDump->shouldDumpWrappedObjects()) { 102 traceMemoryDump->dumpWrappedState(resourceName.c_str(), fRefsWrappedObjects); 103 } 104 105 this->setMemoryBacking(traceMemoryDump, resourceName); 106} 107 108bool GrGpuResource::isPurgeable() const { 109 // Resources in the kUnbudgetedCacheable state are never purgeable when they have a unique 110 // key. The key must be removed/invalidated to make them purgeable. 111 return !this->hasRef() && 112 this->hasNoCommandBufferUsages() && 113 !(fBudgetedType == GrBudgetedType::kUnbudgetedCacheable && fUniqueKey.isValid()); 114} 115 116bool GrGpuResource::hasRef() const { return this->internalHasRef(); } 117 118bool GrGpuResource::hasNoCommandBufferUsages() const { 119 return this->internalHasNoCommandBufferUsages(); 120} 121 122SkString GrGpuResource::getResourceName() const { 123 // Dump resource as "skia/gpu_resources/resource_#". 124 SkString resourceName("skia/gpu_resources/resource_"); 125 resourceName.appendU32(this->uniqueID().asUInt()); 126 return resourceName; 127} 128 129const GrDirectContext* GrGpuResource::getContext() const { 130 if (fGpu) { 131 return fGpu->getContext(); 132 } else { 133 return nullptr; 134 } 135} 136 137GrDirectContext* GrGpuResource::getContext() { 138 if (fGpu) { 139 return fGpu->getContext(); 140 } else { 141 return nullptr; 142 } 143} 144 145void GrGpuResource::removeUniqueKey() { 146 if (this->wasDestroyed()) { 147 return; 148 } 149 SkASSERT(fUniqueKey.isValid()); 150 get_resource_cache(fGpu)->resourceAccess().removeUniqueKey(this); 151} 152 153void GrGpuResource::setUniqueKey(const GrUniqueKey& key) { 154 SkASSERT(this->internalHasRef()); 155 SkASSERT(key.isValid()); 156 157 // Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped 158 // resources are a special case: the unique keys give us a weak ref so that we can reuse the 159 // same resource (rather than re-wrapping). When a wrapped resource is no longer referenced, 160 // it will always be released - it is never converted to a scratch resource. 161 if (this->resourcePriv().budgetedType() != GrBudgetedType::kBudgeted && 162 !this->fRefsWrappedObjects) { 163 return; 164 } 165 166 if (this->wasDestroyed()) { 167 return; 168 } 169 170 get_resource_cache(fGpu)->resourceAccess().changeUniqueKey(this, key); 171} 172 173void GrGpuResource::notifyARefCntIsZero(LastRemovedRef removedRef) const { 174 if (this->wasDestroyed()) { 175 if (this->hasNoCommandBufferUsages() && !this->hasRef()) { 176 // We've already been removed from the cache. Goodbye cruel world! 177 delete this; 178 } 179 return; 180 } 181 182 GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this); 183 184 get_resource_cache(fGpu)->resourceAccess().notifyARefCntReachedZero(mutableThis, removedRef); 185} 186 187void GrGpuResource::removeScratchKey() { 188 if (!this->wasDestroyed() && fScratchKey.isValid()) { 189 get_resource_cache(fGpu)->resourceAccess().willRemoveScratchKey(this); 190 fScratchKey.reset(); 191 } 192} 193 194void GrGpuResource::makeBudgeted() { 195 // We should never make a wrapped resource budgeted. 196 SkASSERT(!fRefsWrappedObjects); 197 // Only wrapped resources can be in the kUnbudgetedCacheable state. 198 SkASSERT(fBudgetedType != GrBudgetedType::kUnbudgetedCacheable); 199 if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable) { 200 // Currently resources referencing wrapped objects are not budgeted. 201 fBudgetedType = GrBudgetedType::kBudgeted; 202 get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this); 203 } 204} 205 206void GrGpuResource::makeUnbudgeted() { 207 if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kBudgeted && 208 !fUniqueKey.isValid()) { 209 fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable; 210 get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this); 211 } 212} 213 214void GrGpuResource::userRegisterResource() 215{ 216 if (this->wasDestroyed()) { 217 return; 218 } 219 SkASSERT(!fScratchKey.isValid()); 220 SkASSERT(!fUniqueKey.isValid()); 221 if (fCacheArrayIndex >= 0 && fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable) { 222 this->computeScratchKey(&fScratchKey); 223 makeBudgeted(); 224 } 225} 226 227uint32_t GrGpuResource::CreateUniqueID() { 228 static std::atomic<uint32_t> nextID{1}; 229 uint32_t id; 230 do { 231 id = nextID.fetch_add(1, std::memory_order_relaxed); 232 } while (id == SK_InvalidUniqueID); 233 return id; 234} 235 236void GrGpuResource::setResourceTag(const GrGpuResourceTag tag) 237{ 238 int32_t pid = fGrResourceTag.fPid; 239 fGrResourceTag = tag; 240 if (pid == tag.fPid || !fRealAlloc) { 241 return; 242 } 243 size_t size = this->gpuMemorySize(); 244 get_resource_cache(fGpu)->resourceAccess().changeByteOfPid(pid, tag.fPid, fRealAllocSize); 245} 246 247////////////////////////////////////////////////////////////////////////////// 248 249void GrGpuResource::ProxyAccess::ref(GrResourceCache* cache) { 250 SkASSERT(cache == fResource->getContext()->priv().getResourceCache()); 251 cache->resourceAccess().refResource(fResource); 252} 253