• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ganesh/GrDirectContextPriv.h"
11 #include "src/gpu/ganesh/GrGpu.h"
12 #include "src/gpu/ganesh/GrGpuResource.h"
13 #include "src/gpu/ganesh/GrGpuResourcePriv.h"
14 #include "src/gpu/ganesh/GrResourceCache.h"
15 #include <atomic>
16 
get_resource_cache(GrGpu * gpu)17 static 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 
GrGpuResource(GrGpu * gpu,std::string_view label)24 GrGpuResource::GrGpuResource(GrGpu* gpu, std::string_view label)
25         : fGpu(gpu), fUniqueID(CreateUniqueID()), fLabel(label) {
26     SkDEBUGCODE(fCacheArrayIndex = -1);
27 }
28 
registerWithCache(skgpu::Budgeted budgeted)29 void GrGpuResource::registerWithCache(skgpu::Budgeted budgeted) {
30     SkASSERT(fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable);
31     fBudgetedType = budgeted == skgpu::Budgeted::kYes ? GrBudgetedType::kBudgeted
32                                                       : GrBudgetedType::kUnbudgetedUncacheable;
33     this->computeScratchKey(&fScratchKey);
34     get_resource_cache(fGpu)->resourceAccess().insertResource(this);
35 }
36 
registerWithCacheWrapped(GrWrapCacheable wrapType)37 void GrGpuResource::registerWithCacheWrapped(GrWrapCacheable wrapType) {
38     SkASSERT(fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable);
39     // Resources referencing wrapped objects are never budgeted. They may be cached or uncached.
40     fBudgetedType = wrapType == GrWrapCacheable::kNo ? GrBudgetedType::kUnbudgetedUncacheable
41                                                      : GrBudgetedType::kUnbudgetedCacheable;
42     fRefsWrappedObjects = true;
43     get_resource_cache(fGpu)->resourceAccess().insertResource(this);
44 }
45 
~GrGpuResource()46 GrGpuResource::~GrGpuResource() {
47     // The cache should have released or destroyed this resource.
48     SkASSERT(this->wasDestroyed());
49 }
50 
release()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 
abandon()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 
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const70 void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
71     if (this->fRefsWrappedObjects && !traceMemoryDump->shouldDumpWrappedObjects()) {
72         return;
73     }
74 
75     this->dumpMemoryStatisticsPriv(traceMemoryDump, this->getResourceName(),
76                                    this->getResourceType(), this->gpuMemorySize());
77 }
78 
dumpMemoryStatisticsPriv(SkTraceMemoryDump * traceMemoryDump,const SkString & resourceName,const char * type,size_t size) const79 void GrGpuResource::dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump,
80                                              const SkString& resourceName,
81                                              const char* type, size_t size) const {
82     const char* tag = "Scratch";
83     if (fUniqueKey.isValid()) {
84         tag = (fUniqueKey.tag() != nullptr) ? fUniqueKey.tag() : "Other";
85     }
86 
87     traceMemoryDump->dumpNumericValue(resourceName.c_str(), "size", "bytes", size);
88     traceMemoryDump->dumpStringValue(resourceName.c_str(), "type", type);
89     traceMemoryDump->dumpStringValue(resourceName.c_str(), "category", tag);
90     if (this->isPurgeable()) {
91         traceMemoryDump->dumpNumericValue(resourceName.c_str(), "purgeable_size", "bytes", size);
92     }
93     if (traceMemoryDump->shouldDumpWrappedObjects()) {
94         traceMemoryDump->dumpWrappedState(resourceName.c_str(), fRefsWrappedObjects);
95     }
96 
97     this->setMemoryBacking(traceMemoryDump, resourceName);
98 }
99 
isPurgeable() const100 bool GrGpuResource::isPurgeable() const {
101     // Resources in the kUnbudgetedCacheable state are never purgeable when they have a unique
102     // key. The key must be removed/invalidated to make them purgeable.
103     return !this->hasRef() &&
104            this->hasNoCommandBufferUsages() &&
105            !(fBudgetedType == GrBudgetedType::kUnbudgetedCacheable && fUniqueKey.isValid());
106 }
107 
hasRef() const108 bool GrGpuResource::hasRef() const { return this->internalHasRef(); }
109 
hasNoCommandBufferUsages() const110 bool GrGpuResource::hasNoCommandBufferUsages() const {
111     return this->internalHasNoCommandBufferUsages();
112 }
113 
getResourceName() const114 SkString GrGpuResource::getResourceName() const {
115     // Dump resource as "skia/gpu_resources/resource_#".
116     SkString resourceName("skia/gpu_resources/resource_");
117     resourceName.appendU32(this->uniqueID().asUInt());
118     return resourceName;
119 }
120 
getContext() const121 const GrDirectContext* GrGpuResource::getContext() const {
122     if (fGpu) {
123         return fGpu->getContext();
124     } else {
125         return nullptr;
126     }
127 }
128 
getContext()129 GrDirectContext* GrGpuResource::getContext() {
130     if (fGpu) {
131         return fGpu->getContext();
132     } else {
133         return nullptr;
134     }
135 }
136 
removeUniqueKey()137 void GrGpuResource::removeUniqueKey() {
138     if (this->wasDestroyed()) {
139         return;
140     }
141     SkASSERT(fUniqueKey.isValid());
142     get_resource_cache(fGpu)->resourceAccess().removeUniqueKey(this);
143 }
144 
setUniqueKey(const skgpu::UniqueKey & key)145 void GrGpuResource::setUniqueKey(const skgpu::UniqueKey& key) {
146     SkASSERT(this->internalHasRef());
147     SkASSERT(key.isValid());
148 
149     // Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped
150     // resources are a special case: the unique keys give us a weak ref so that we can reuse the
151     // same resource (rather than re-wrapping). When a wrapped resource is no longer referenced,
152     // it will always be released - it is never converted to a scratch resource.
153     if (this->resourcePriv().budgetedType() != GrBudgetedType::kBudgeted &&
154         !this->fRefsWrappedObjects) {
155         return;
156     }
157 
158     if (this->wasDestroyed()) {
159         return;
160     }
161 
162     get_resource_cache(fGpu)->resourceAccess().changeUniqueKey(this, key);
163 }
164 
notifyARefCntIsZero(LastRemovedRef removedRef) const165 void GrGpuResource::notifyARefCntIsZero(LastRemovedRef removedRef) const {
166     if (this->wasDestroyed()) {
167         if (this->hasNoCommandBufferUsages() && !this->hasRef()) {
168             // We've already been removed from the cache. Goodbye cruel world!
169             delete this;
170         }
171         return;
172     }
173 
174     GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
175 
176     get_resource_cache(fGpu)->resourceAccess().notifyARefCntReachedZero(mutableThis, removedRef);
177 }
178 
removeScratchKey()179 void GrGpuResource::removeScratchKey() {
180     if (!this->wasDestroyed() && fScratchKey.isValid()) {
181         get_resource_cache(fGpu)->resourceAccess().willRemoveScratchKey(this);
182         fScratchKey.reset();
183     }
184 }
185 
makeBudgeted()186 void GrGpuResource::makeBudgeted() {
187     // We should never make a wrapped resource budgeted.
188     SkASSERT(!fRefsWrappedObjects);
189     // Only wrapped resources can be in the kUnbudgetedCacheable state.
190     SkASSERT(fBudgetedType != GrBudgetedType::kUnbudgetedCacheable);
191     if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable) {
192         // Currently resources referencing wrapped objects are not budgeted.
193         fBudgetedType = GrBudgetedType::kBudgeted;
194         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
195     }
196 }
197 
makeUnbudgeted()198 void GrGpuResource::makeUnbudgeted() {
199     if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kBudgeted &&
200         !fUniqueKey.isValid()) {
201         fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
202         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
203     }
204 }
205 
CreateUniqueID()206 uint32_t GrGpuResource::CreateUniqueID() {
207     static std::atomic<uint32_t> nextID{1};
208     uint32_t id;
209     do {
210         id = nextID.fetch_add(1, std::memory_order_relaxed);
211     } while (id == SK_InvalidUniqueID);
212     return id;
213 }
214 
215 //////////////////////////////////////////////////////////////////////////////
216 
ref(GrResourceCache * cache)217 void GrGpuResource::ProxyAccess::ref(GrResourceCache* cache) {
218     SkASSERT(cache == fResource->getContext()->priv().getResourceCache());
219     cache->resourceAccess().refResource(fResource);
220 }
221