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