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