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
~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 // 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
getContext() const87 const GrContext* GrGpuResource::getContext() const {
88 if (fGpu) {
89 return fGpu->getContext();
90 } else {
91 return nullptr;
92 }
93 }
94
getContext()95 GrContext* GrGpuResource::getContext() {
96 if (fGpu) {
97 return fGpu->getContext();
98 } else {
99 return nullptr;
100 }
101 }
102
didChangeGpuMemorySize() const103 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
removeUniqueKey()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
setUniqueKey(const GrUniqueKey & key)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
notifyAllCntsAreZero(CntType lastCntTypeToReachZero) const141 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
notifyRefCountIsZero() const157 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
removeScratchKey()175 void GrGpuResource::removeScratchKey() {
176 if (!this->wasDestroyed() && fScratchKey.isValid()) {
177 get_resource_cache(fGpu)->resourceAccess().willRemoveScratchKey(this);
178 fScratchKey.reset();
179 }
180 }
181
makeBudgeted()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
makeUnbudgeted()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
CreateUniqueID()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