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
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
22 GrGpuResource::GrGpuResource(GrGpu* gpu)
23 : fExternalFlushCntWhenBecamePurgeable(0)
24 , fGpu(gpu)
25 , fGpuMemorySize(kInvalidGpuMemorySize)
operator =(const GrMesh & di)26 , fBudgeted(SkBudgeted::kNo)
27 , fRefsWrappedObjects(false)
28 , fUniqueID(CreateUniqueID()) {
29 SkDEBUGCODE(fCacheArrayIndex = -1);
30 }
31
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
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
GrGpu(GrContext * context)46 GrGpuResource::~GrGpuResource() {
47 // The cache should have released or destroyed this resource.
48 SkASSERT(this->wasDestroyed());
49 }
50
51 void GrGpuResource::release() {
52 SkASSERT(fGpu);
~GrGpu()53 this->onRelease();
54 get_resource_cache(fGpu)->resourceAccess().removeResource(this);
disconnect(DisconnectType)55 fGpu = nullptr;
56 fGpuMemorySize = 0;
57 }
58
makeCopyForTextureParams(int width,int height,const GrTextureParams & textureParams,GrTextureProducer::CopyParams * copyParams) const59 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
70 void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
71 // Dump resource as "skia/gpu_resources/resource_#".
72 SkString dumpName("skia/gpu_resources/resource_");
73 dumpName.appendS32(this->uniqueID());
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 }
resolve_origin(GrSurfaceOrigin origin,bool renderTarget)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
87 const GrContext* GrGpuResource::getContext() const {
88 if (fGpu) {
89 return fGpu->getContext();
90 } else {
91 return nullptr;
92 }
93 }
94
95 GrContext* GrGpuResource::getContext() {
96 if (fGpu) {
97 return fGpu->getContext();
98 } else {
99 return nullptr;
check_texture_creation_params(const GrCaps & caps,const GrSurfaceDesc & desc,bool * isRT,const SkTArray<GrMipLevel> & texels)100 }
101 }
102
103 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
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
122 void GrGpuResource::setUniqueKey(const GrUniqueKey& key) {
123 SkASSERT(this->internalHasRef());
124 SkASSERT(key.isValid());
125
126 // Wrapped and uncached resources can never have a unique key.
127 if (SkBudgeted::kNo == this->resourcePriv().isBudgeted()) {
128 return;
129 }
130
131 if (this->wasDestroyed()) {
132 return;
133 }
134
135 get_resource_cache(fGpu)->resourceAccess().changeUniqueKey(this, key);
createTexture(const GrSurfaceDesc & origDesc,SkBudgeted budgeted,const SkTArray<GrMipLevel> & texels)136 }
137
138 void GrGpuResource::notifyAllCntsAreZero(CntType lastCntTypeToReachZero) const {
139 if (this->wasDestroyed()) {
140 // We've already been removed from the cache. Goodbye cruel world!
141 delete this;
142 return;
143 }
144
145 // We should have already handled this fully in notifyRefCntIsZero().
146 SkASSERT(kRef_CntType != lastCntTypeToReachZero);
147
148 GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
149 static const uint32_t kFlag =
150 GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
151 get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, kFlag);
152 }
153
154 bool GrGpuResource::notifyRefCountIsZero() const {
155 if (this->wasDestroyed()) {
156 // handle this in notifyAllCntsAreZero().
157 return true;
158 }
159
160 GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
161 uint32_t flags =
162 GrResourceCache::ResourceAccess::kRefCntReachedZero_RefNotificationFlag;
163 if (!this->internalHasPendingIO()) {
164 flags |= GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
165 }
166 get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, flags);
167
168 // There is no need to call our notifyAllCntsAreZero function at this point since we already
169 // told the cache about the state of cnts.
170 return false;
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 if (!this->wasDestroyed() && SkBudgeted::kNo == fBudgeted) {
182 // Currently resources referencing wrapped objects are not budgeted.
183 SkASSERT(!fRefsWrappedObjects);
184 fBudgeted = SkBudgeted::kYes;
185 get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
186 }
187 }
188
189 void GrGpuResource::makeUnbudgeted() {
190 if (!this->wasDestroyed() && SkBudgeted::kYes == fBudgeted &&
191 !fUniqueKey.isValid()) {
192 fBudgeted = SkBudgeted::kNo;
wrapBackendTexture(const GrBackendTextureDesc & desc,GrWrapOwnership ownership)193 get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
194 }
195 }
196
197 uint32_t GrGpuResource::CreateUniqueID() {
198 static int32_t gUniqueID = SK_InvalidUniqueID;
199 uint32_t id;
200 do {
201 id = static_cast<uint32_t>(sk_atomic_inc(&gUniqueID) + 1);
202 } while (id == SK_InvalidUniqueID);
203 return id;
204 }
205