• 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 "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