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
get_resource_cache(GrGpu * gpu)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
GrGpuResource(GrGpu * gpu)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
registerWithCache(SkBudgeted budgeted)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
registerWithCacheWrapped()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
detachFromCache()46 void GrGpuResource::detachFromCache() {
47 if (this->wasDestroyed()) {
48 return;
49 }
50 if (fUniqueKey.isValid()) {
51 this->removeUniqueKey();
52 }
53 this->removeScratchKey();
54 this->makeUnbudgeted();
55 }
56
~GrGpuResource()57 GrGpuResource::~GrGpuResource() {
58 // The cache should have released or destroyed this resource.
59 SkASSERT(this->wasDestroyed());
60 }
61
release()62 void GrGpuResource::release() {
63 SkASSERT(fGpu);
64 this->onRelease();
65 get_resource_cache(fGpu)->resourceAccess().removeResource(this);
66 fGpu = nullptr;
67 fGpuMemorySize = 0;
68 }
69
abandon()70 void GrGpuResource::abandon() {
71 if (this->wasDestroyed()) {
72 return;
73 }
74 SkASSERT(fGpu);
75 this->onAbandon();
76 get_resource_cache(fGpu)->resourceAccess().removeResource(this);
77 fGpu = nullptr;
78 fGpuMemorySize = 0;
79 }
80
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const81 void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
82 // Dump resource as "skia/gpu_resources/resource_#".
83 SkString dumpName("skia/gpu_resources/resource_");
84 dumpName.appendU32(this->uniqueID().asUInt());
85
86 traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", this->gpuMemorySize());
87
88 if (this->isPurgeable()) {
89 traceMemoryDump->dumpNumericValue(dumpName.c_str(), "purgeable_size", "bytes",
90 this->gpuMemorySize());
91 }
92
93 // Call setMemoryBacking to allow sub-classes with implementation specific backings (such as GL
94 // objects) to provide additional information.
95 this->setMemoryBacking(traceMemoryDump, dumpName);
96 }
97
getContext() const98 const GrContext* GrGpuResource::getContext() const {
99 if (fGpu) {
100 return fGpu->getContext();
101 } else {
102 return nullptr;
103 }
104 }
105
getContext()106 GrContext* GrGpuResource::getContext() {
107 if (fGpu) {
108 return fGpu->getContext();
109 } else {
110 return nullptr;
111 }
112 }
113
didChangeGpuMemorySize() const114 void GrGpuResource::didChangeGpuMemorySize() const {
115 if (this->wasDestroyed()) {
116 return;
117 }
118
119 size_t oldSize = fGpuMemorySize;
120 SkASSERT(kInvalidGpuMemorySize != oldSize);
121 fGpuMemorySize = kInvalidGpuMemorySize;
122 get_resource_cache(fGpu)->resourceAccess().didChangeGpuMemorySize(this, oldSize);
123 }
124
removeUniqueKey()125 void GrGpuResource::removeUniqueKey() {
126 if (this->wasDestroyed()) {
127 return;
128 }
129 SkASSERT(fUniqueKey.isValid());
130 get_resource_cache(fGpu)->resourceAccess().removeUniqueKey(this);
131 }
132
setUniqueKey(const GrUniqueKey & key)133 void GrGpuResource::setUniqueKey(const GrUniqueKey& key) {
134 SkASSERT(this->internalHasRef());
135 SkASSERT(key.isValid());
136
137 // Wrapped and uncached resources can never have a unique key.
138 if (SkBudgeted::kNo == this->resourcePriv().isBudgeted()) {
139 return;
140 }
141
142 if (this->wasDestroyed()) {
143 return;
144 }
145
146 get_resource_cache(fGpu)->resourceAccess().changeUniqueKey(this, key);
147 }
148
notifyAllCntsAreZero(CntType lastCntTypeToReachZero) const149 void GrGpuResource::notifyAllCntsAreZero(CntType lastCntTypeToReachZero) const {
150 if (this->wasDestroyed()) {
151 // We've already been removed from the cache. Goodbye cruel world!
152 delete this;
153 return;
154 }
155
156 // We should have already handled this fully in notifyRefCntIsZero().
157 SkASSERT(kRef_CntType != lastCntTypeToReachZero);
158
159 GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
160 static const uint32_t kFlag =
161 GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
162 get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, kFlag);
163 }
164
notifyRefCountIsZero() const165 bool GrGpuResource::notifyRefCountIsZero() const {
166 if (this->wasDestroyed()) {
167 // handle this in notifyAllCntsAreZero().
168 return true;
169 }
170
171 GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
172 uint32_t flags =
173 GrResourceCache::ResourceAccess::kRefCntReachedZero_RefNotificationFlag;
174 if (!this->internalHasPendingIO()) {
175 flags |= GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
176 }
177 get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, flags);
178
179 // There is no need to call our notifyAllCntsAreZero function at this point since we already
180 // told the cache about the state of cnts.
181 return false;
182 }
183
removeScratchKey()184 void GrGpuResource::removeScratchKey() {
185 if (!this->wasDestroyed() && fScratchKey.isValid()) {
186 get_resource_cache(fGpu)->resourceAccess().willRemoveScratchKey(this);
187 fScratchKey.reset();
188 }
189 }
190
makeBudgeted()191 void GrGpuResource::makeBudgeted() {
192 if (!this->wasDestroyed() && SkBudgeted::kNo == fBudgeted) {
193 // Currently resources referencing wrapped objects are not budgeted.
194 SkASSERT(!fRefsWrappedObjects);
195 fBudgeted = SkBudgeted::kYes;
196 get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
197 }
198 }
199
makeUnbudgeted()200 void GrGpuResource::makeUnbudgeted() {
201 if (!this->wasDestroyed() && SkBudgeted::kYes == fBudgeted &&
202 !fUniqueKey.isValid()) {
203 fBudgeted = SkBudgeted::kNo;
204 get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
205 }
206 }
207
CreateUniqueID()208 uint32_t GrGpuResource::CreateUniqueID() {
209 static int32_t gUniqueID = SK_InvalidUniqueID;
210 uint32_t id;
211 do {
212 id = static_cast<uint32_t>(sk_atomic_inc(&gUniqueID) + 1);
213 } while (id == SK_InvalidUniqueID);
214 return id;
215 }
216