1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 #include "GrGpuResource.h"
10 #include "GrContext.h"
11 #include "GrResourceCache.h"
12 #include "GrGpu.h"
13 #include "GrGpuResourcePriv.h"
14 #include "SkTraceMemoryDump.h"
15 
get_resource_cache(GrGpu * gpu)16 static inline GrResourceCache* get_resource_cache(GrGpu* gpu) {
17     SkASSERT(gpu);
18     SkASSERT(gpu->getContext());
19     SkASSERT(gpu->getContext()->getResourceCache());
20     return gpu->getContext()->getResourceCache();
21 }
22 
GrGpuResource(GrGpu * gpu,LifeCycle lifeCycle)23 GrGpuResource::GrGpuResource(GrGpu* gpu, LifeCycle lifeCycle)
24     : fGpu(gpu)
25     , fGpuMemorySize(kInvalidGpuMemorySize)
26     , fLifeCycle(lifeCycle)
27     , fUniqueID(CreateUniqueID()) {
28     SkDEBUGCODE(fCacheArrayIndex = -1);
29 }
30 
registerWithCache()31 void GrGpuResource::registerWithCache() {
32     get_resource_cache(fGpu)->resourceAccess().insertResource(this);
33 }
34 
~GrGpuResource()35 GrGpuResource::~GrGpuResource() {
36     // The cache should have released or destroyed this resource.
37     SkASSERT(this->wasDestroyed());
38 }
39 
release()40 void GrGpuResource::release() {
41     SkASSERT(fGpu);
42     this->onRelease();
43     get_resource_cache(fGpu)->resourceAccess().removeResource(this);
44     fGpu = nullptr;
45     fGpuMemorySize = 0;
46 }
47 
abandon()48 void GrGpuResource::abandon() {
49     if (this->wasDestroyed()) {
50         return;
51     }
52     SkASSERT(fGpu);
53     this->onAbandon();
54     get_resource_cache(fGpu)->resourceAccess().removeResource(this);
55     fGpu = nullptr;
56     fGpuMemorySize = 0;
57 }
58 
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const59 void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
60     // Dump resource as "skia/gpu_resources/resource_#".
61     SkString dumpName("skia/gpu_resources/resource_");
62     dumpName.appendS32(this->getUniqueID());
63 
64     traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", this->gpuMemorySize());
65 
66     if (this->isPurgeable()) {
67         traceMemoryDump->dumpNumericValue(dumpName.c_str(), "purgeable_size", "bytes",
68                                           this->gpuMemorySize());
69     }
70 
71     // Call setMemoryBacking to allow sub-classes with implementation specific backings (such as GL
72     // objects) to provide additional information.
73     this->setMemoryBacking(traceMemoryDump, dumpName);
74 }
75 
setCustomData(const SkData * data)76 const SkData* GrGpuResource::setCustomData(const SkData* data) {
77     SkSafeRef(data);
78     fData.reset(data);
79     return data;
80 }
81 
getContext() const82 const GrContext* GrGpuResource::getContext() const {
83     if (fGpu) {
84         return fGpu->getContext();
85     } else {
86         return nullptr;
87     }
88 }
89 
getContext()90 GrContext* GrGpuResource::getContext() {
91     if (fGpu) {
92         return fGpu->getContext();
93     } else {
94         return nullptr;
95     }
96 }
97 
didChangeGpuMemorySize() const98 void GrGpuResource::didChangeGpuMemorySize() const {
99     if (this->wasDestroyed()) {
100         return;
101     }
102 
103     size_t oldSize = fGpuMemorySize;
104     SkASSERT(kInvalidGpuMemorySize != oldSize);
105     fGpuMemorySize = kInvalidGpuMemorySize;
106     get_resource_cache(fGpu)->resourceAccess().didChangeGpuMemorySize(this, oldSize);
107 }
108 
removeUniqueKey()109 void GrGpuResource::removeUniqueKey() {
110     if (this->wasDestroyed()) {
111         return;
112     }
113     SkASSERT(fUniqueKey.isValid());
114     get_resource_cache(fGpu)->resourceAccess().removeUniqueKey(this);
115 }
116 
setUniqueKey(const GrUniqueKey & key)117 void GrGpuResource::setUniqueKey(const GrUniqueKey& key) {
118     SkASSERT(this->internalHasRef());
119     SkASSERT(key.isValid());
120 
121     // Wrapped and uncached resources can never have a unique key.
122     if (SkBudgeted::kNo == this->resourcePriv().isBudgeted()) {
123         return;
124     }
125 
126     if (this->wasDestroyed()) {
127         return;
128     }
129 
130     get_resource_cache(fGpu)->resourceAccess().changeUniqueKey(this, key);
131 }
132 
notifyAllCntsAreZero(CntType lastCntTypeToReachZero) const133 void GrGpuResource::notifyAllCntsAreZero(CntType lastCntTypeToReachZero) const {
134     if (this->wasDestroyed()) {
135         // We've already been removed from the cache. Goodbye cruel world!
136         delete this;
137         return;
138     }
139 
140     // We should have already handled this fully in notifyRefCntIsZero().
141     SkASSERT(kRef_CntType != lastCntTypeToReachZero);
142 
143     GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
144     static const uint32_t kFlag =
145         GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
146     get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, kFlag);
147 }
148 
notifyRefCountIsZero() const149 bool GrGpuResource::notifyRefCountIsZero() const {
150     if (this->wasDestroyed()) {
151         // handle this in notifyAllCntsAreZero().
152         return true;
153     }
154 
155     GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
156     uint32_t flags =
157         GrResourceCache::ResourceAccess::kRefCntReachedZero_RefNotificationFlag;
158     if (!this->internalHasPendingIO()) {
159         flags |= GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
160     }
161     get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, flags);
162 
163     // There is no need to call our notifyAllCntsAreZero function at this point since we already
164     // told the cache about the state of cnts.
165     return false;
166 }
167 
setScratchKey(const GrScratchKey & scratchKey)168 void GrGpuResource::setScratchKey(const GrScratchKey& scratchKey) {
169     SkASSERT(!fScratchKey.isValid());
170     SkASSERT(scratchKey.isValid());
171     // Wrapped resources can never have a scratch key.
172     if (this->cacheAccess().isExternal()) {
173         return;
174     }
175     fScratchKey = scratchKey;
176 }
177 
removeScratchKey()178 void GrGpuResource::removeScratchKey() {
179     if (!this->wasDestroyed() && fScratchKey.isValid()) {
180         get_resource_cache(fGpu)->resourceAccess().willRemoveScratchKey(this);
181         fScratchKey.reset();
182     }
183 }
184 
makeBudgeted()185 void GrGpuResource::makeBudgeted() {
186     if (!this->wasDestroyed() && GrGpuResource::kUncached_LifeCycle == fLifeCycle) {
187         fLifeCycle = kCached_LifeCycle;
188         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
189     }
190 }
191 
makeUnbudgeted()192 void GrGpuResource::makeUnbudgeted() {
193     if (!this->wasDestroyed() && GrGpuResource::kCached_LifeCycle == fLifeCycle &&
194         !fUniqueKey.isValid()) {
195         fLifeCycle = kUncached_LifeCycle;
196         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
197     }
198 }
199 
CreateUniqueID()200 uint32_t GrGpuResource::CreateUniqueID() {
201     static int32_t gUniqueID = SK_InvalidUniqueID;
202     uint32_t id;
203     do {
204         id = static_cast<uint32_t>(sk_atomic_inc(&gUniqueID) + 1);
205     } while (id == SK_InvalidUniqueID);
206     return id;
207 }
208