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