• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/GrDirectContext.h"
10 #include "src/gpu/GrDirectContextPriv.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 #include "include/core/SkLog.h"
17 #include "include/core/SkTypes.h"
18 
get_resource_cache(GrGpu * gpu)19 static inline GrResourceCache* get_resource_cache(GrGpu* gpu) {
20     SkASSERT(gpu);
21     SkASSERT(gpu->getContext());
22     SkASSERT(gpu->getContext()->priv().getResourceCache());
23     return gpu->getContext()->priv().getResourceCache();
24 }
25 
GrGpuResource(GrGpu * gpu)26 GrGpuResource::GrGpuResource(GrGpu* gpu) : fGpu(gpu), fUniqueID(CreateUniqueID()) {
27     SkDEBUGCODE(fCacheArrayIndex = -1);
28     auto cache = get_resource_cache(fGpu);
29     if (cache) {
30         fGrResourceTag = cache->resourceAccess().getCurrentGrResourceTag();
31     }
32 }
33 
registerWithCache(SkBudgeted budgeted)34 void GrGpuResource::registerWithCache(SkBudgeted budgeted) {
35     SkASSERT(fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable);
36     fBudgetedType = budgeted == SkBudgeted::kYes ? GrBudgetedType::kBudgeted
37                                                  : GrBudgetedType::kUnbudgetedUncacheable;
38     this->computeScratchKey(&fScratchKey);
39     get_resource_cache(fGpu)->resourceAccess().insertResource(this);
40 }
41 
registerWithCacheWrapped(GrWrapCacheable wrapType)42 void GrGpuResource::registerWithCacheWrapped(GrWrapCacheable wrapType) {
43     SkASSERT(fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable);
44     // Resources referencing wrapped objects are never budgeted. They may be cached or uncached.
45     fBudgetedType = wrapType == GrWrapCacheable::kNo ? GrBudgetedType::kUnbudgetedUncacheable
46                                                      : GrBudgetedType::kUnbudgetedCacheable;
47     fRefsWrappedObjects = true;
48     get_resource_cache(fGpu)->resourceAccess().insertResource(this);
49 }
50 
~GrGpuResource()51 GrGpuResource::~GrGpuResource() {
52     // The cache should have released or destroyed this resource.
53 #ifdef SKIA_OHOS_SINGLE_OWNER
54     static const bool isEnabledSkiaSingleOwner = GetEnableSkiaSingleOwner();
55     static const int SIGNAL_FOR_OCEAN = 42;
56     if (isEnabledSkiaSingleOwner && fTid != pthread_self()) {
57         SK_LOGE("GrResource fTid[%{public}d]", fTid);
58         raise(SIGNAL_FOR_OCEAN);
59     }
60 #endif
61     fMagicNum = 0;
62     SkASSERT(this->wasDestroyed());
63 }
64 
release()65 void GrGpuResource::release() {
66     SkASSERT(fGpu);
67     this->onRelease();
68     get_resource_cache(fGpu)->resourceAccess().removeResource(this);
69     fGpu = nullptr;
70     fGpuMemorySize = 0;
71     fMagicNum = 0;
72 }
73 
abandon()74 void GrGpuResource::abandon() {
75     if (this->wasDestroyed()) {
76         return;
77     }
78     SkASSERT(fGpu);
79     this->onAbandon();
80     get_resource_cache(fGpu)->resourceAccess().removeResource(this);
81     fGpu = nullptr;
82     fGpuMemorySize = 0;
83 }
84 
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const85 void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
86     if (this->fRefsWrappedObjects && !traceMemoryDump->shouldDumpWrappedObjects()) {
87         return;
88     }
89 
90     this->dumpMemoryStatisticsPriv(traceMemoryDump, this->getResourceName(),
91                                    this->getResourceType(), this->gpuMemorySize());
92 }
93 
dumpMemoryStatisticsPriv(SkTraceMemoryDump * traceMemoryDump,const SkString & resourceName,const char * type,size_t size) const94 void GrGpuResource::dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump,
95                                              const SkString& resourceName,
96                                              const char* type, size_t size) const {
97     const char* tag = "Scratch";
98     if (fUniqueKey.isValid()) {
99         tag = (fUniqueKey.tag() != nullptr) ? fUniqueKey.tag() : "Other";
100     }
101 
102     traceMemoryDump->dumpNumericValue(resourceName.c_str(), "size", "bytes", size);
103     traceMemoryDump->dumpStringValue(resourceName.c_str(), "type", type);
104     traceMemoryDump->dumpStringValue(resourceName.c_str(), "category", tag);
105     if (this->isPurgeable()) {
106         traceMemoryDump->dumpNumericValue(resourceName.c_str(), "purgeable_size", "bytes", size);
107     }
108     if (traceMemoryDump->shouldDumpWrappedObjects()) {
109         traceMemoryDump->dumpWrappedState(resourceName.c_str(), fRefsWrappedObjects);
110     }
111 
112     this->setMemoryBacking(traceMemoryDump, resourceName);
113 }
114 
isPurgeable() const115 bool GrGpuResource::isPurgeable() const {
116     // Resources in the kUnbudgetedCacheable state are never purgeable when they have a unique
117     // key. The key must be removed/invalidated to make them purgeable.
118     return !this->hasRef() &&
119            this->hasNoCommandBufferUsages() &&
120            !(fBudgetedType == GrBudgetedType::kUnbudgetedCacheable && fUniqueKey.isValid());
121 }
122 
hasRef() const123 bool GrGpuResource::hasRef() const { return this->internalHasRef(); }
124 
hasNoCommandBufferUsages() const125 bool GrGpuResource::hasNoCommandBufferUsages() const {
126     return this->internalHasNoCommandBufferUsages();
127 }
128 
getResourceName() const129 SkString GrGpuResource::getResourceName() const {
130     // Dump resource as "skia/gpu_resources/resource_#".
131     SkString resourceName("skia/gpu_resources/resource_");
132     resourceName.appendU32(this->uniqueID().asUInt());
133     return resourceName;
134 }
135 
getContext() const136 const GrDirectContext* GrGpuResource::getContext() const {
137     if (fGpu) {
138         return fGpu->getContext();
139     } else {
140         return nullptr;
141     }
142 }
143 
getContext()144 GrDirectContext* GrGpuResource::getContext() {
145     if (fGpu) {
146         return fGpu->getContext();
147     } else {
148         return nullptr;
149     }
150 }
151 
removeUniqueKey()152 void GrGpuResource::removeUniqueKey() {
153     if (this->wasDestroyed()) {
154         return;
155     }
156     SkASSERT(fUniqueKey.isValid());
157     get_resource_cache(fGpu)->resourceAccess().removeUniqueKey(this);
158 }
159 
setUniqueKey(const GrUniqueKey & key)160 void GrGpuResource::setUniqueKey(const GrUniqueKey& key) {
161     SkASSERT(this->internalHasRef());
162     SkASSERT(key.isValid());
163 
164     // Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped
165     // resources are a special case: the unique keys give us a weak ref so that we can reuse the
166     // same resource (rather than re-wrapping). When a wrapped resource is no longer referenced,
167     // it will always be released - it is never converted to a scratch resource.
168     if (this->resourcePriv().budgetedType() != GrBudgetedType::kBudgeted &&
169         !this->fRefsWrappedObjects) {
170         return;
171     }
172 
173     if (this->wasDestroyed()) {
174         return;
175     }
176 
177     get_resource_cache(fGpu)->resourceAccess().changeUniqueKey(this, key);
178 }
179 
notifyARefCntIsZero(LastRemovedRef removedRef) const180 void GrGpuResource::notifyARefCntIsZero(LastRemovedRef removedRef) const {
181     if (this->wasDestroyed()) {
182         if (this->hasNoCommandBufferUsages() && !this->hasRef()) {
183             // We've already been removed from the cache. Goodbye cruel world!
184             delete this;
185         }
186         return;
187     }
188 
189     GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
190 
191     get_resource_cache(fGpu)->resourceAccess().notifyARefCntReachedZero(mutableThis, removedRef);
192 }
193 
removeScratchKey()194 void GrGpuResource::removeScratchKey() {
195     if (!this->wasDestroyed() && fScratchKey.isValid()) {
196         get_resource_cache(fGpu)->resourceAccess().willRemoveScratchKey(this);
197         fScratchKey.reset();
198     }
199 }
200 
makeBudgeted()201 void GrGpuResource::makeBudgeted() {
202     // We should never make a wrapped resource budgeted.
203     SkASSERT(!fRefsWrappedObjects);
204     // Only wrapped resources can be in the kUnbudgetedCacheable state.
205     SkASSERT(fBudgetedType != GrBudgetedType::kUnbudgetedCacheable);
206     if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable) {
207         // Currently resources referencing wrapped objects are not budgeted.
208         fBudgetedType = GrBudgetedType::kBudgeted;
209         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
210     }
211 }
212 
makeUnbudgeted()213 void GrGpuResource::makeUnbudgeted() {
214     if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kBudgeted &&
215         !fUniqueKey.isValid()) {
216         fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
217         get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
218     }
219 }
220 
userRegisterResource()221 void GrGpuResource::userRegisterResource()
222 {
223     if (this->wasDestroyed()) {
224         return;
225     }
226     SkASSERT(!fScratchKey.isValid());
227     SkASSERT(!fUniqueKey.isValid());
228     if (fCacheArrayIndex >= 0 && fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable) {
229         this->computeScratchKey(&fScratchKey);
230         makeBudgeted();
231     }
232 }
233 
CreateUniqueID()234 uint32_t GrGpuResource::CreateUniqueID() {
235     static std::atomic<uint32_t> nextID{1};
236     uint32_t id;
237     do {
238         id = nextID.fetch_add(1, std::memory_order_relaxed);
239     } while (id == SK_InvalidUniqueID);
240     return id;
241 }
242 
setResourceTag(const GrGpuResourceTag tag,bool curRealAlloc)243 void GrGpuResource::setResourceTag(const GrGpuResourceTag tag, bool curRealAlloc)
244 {
245     int32_t pid = fGrResourceTag.fPid;
246     fGrResourceTag = tag;
247     if ((pid == tag.fPid) && (fRealAlloc == curRealAlloc)) {
248         return;
249     }
250     size_t size = this->gpuMemorySize();
251     get_resource_cache(fGpu)->resourceAccess().changeByteOfPid(pid, tag.fPid, size, fRealAlloc, curRealAlloc);
252     fRealAlloc = curRealAlloc;
253 }
254 
255 //////////////////////////////////////////////////////////////////////////////
256 
ref(GrResourceCache * cache)257 void GrGpuResource::ProxyAccess::ref(GrResourceCache* cache) {
258     SkASSERT(cache == fResource->getContext()->priv().getResourceCache());
259     cache->resourceAccess().refResource(fResource);
260 }
261