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