xref: /aosp_15_r20/external/skia/src/gpu/graphite/Resource.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2022 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Resource.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTraceMemoryDump.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceCache.h"
12*c8dee2aaSAndroid Build Coastguard Worker 
13*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
14*c8dee2aaSAndroid Build Coastguard Worker 
15*c8dee2aaSAndroid Build Coastguard Worker namespace {
create_unique_id()16*c8dee2aaSAndroid Build Coastguard Worker uint32_t create_unique_id() {
17*c8dee2aaSAndroid Build Coastguard Worker     static std::atomic<uint32_t> nextID{1};
18*c8dee2aaSAndroid Build Coastguard Worker     uint32_t id;
19*c8dee2aaSAndroid Build Coastguard Worker     do {
20*c8dee2aaSAndroid Build Coastguard Worker         id = nextID.fetch_add(1, std::memory_order_relaxed);
21*c8dee2aaSAndroid Build Coastguard Worker     } while (id == SK_InvalidUniqueID);
22*c8dee2aaSAndroid Build Coastguard Worker     return id;
23*c8dee2aaSAndroid Build Coastguard Worker }
24*c8dee2aaSAndroid Build Coastguard Worker } // namespace anonymous
25*c8dee2aaSAndroid Build Coastguard Worker 
Resource(const SharedContext * sharedContext,Ownership ownership,skgpu::Budgeted budgeted,size_t gpuMemorySize,bool commandBufferRefsAsUsageRefs)26*c8dee2aaSAndroid Build Coastguard Worker Resource::Resource(const SharedContext* sharedContext,
27*c8dee2aaSAndroid Build Coastguard Worker                    Ownership ownership,
28*c8dee2aaSAndroid Build Coastguard Worker                    skgpu::Budgeted budgeted,
29*c8dee2aaSAndroid Build Coastguard Worker                    size_t gpuMemorySize,
30*c8dee2aaSAndroid Build Coastguard Worker                    bool commandBufferRefsAsUsageRefs)
31*c8dee2aaSAndroid Build Coastguard Worker         : fSharedContext(sharedContext)
32*c8dee2aaSAndroid Build Coastguard Worker         , fUsageRefCnt(1)
33*c8dee2aaSAndroid Build Coastguard Worker         , fCommandBufferRefCnt(0)
34*c8dee2aaSAndroid Build Coastguard Worker         , fCacheRefCnt(0)
35*c8dee2aaSAndroid Build Coastguard Worker         , fCommandBufferRefsAsUsageRefs(commandBufferRefsAsUsageRefs)
36*c8dee2aaSAndroid Build Coastguard Worker         , fOwnership(ownership)
37*c8dee2aaSAndroid Build Coastguard Worker         , fGpuMemorySize(gpuMemorySize)
38*c8dee2aaSAndroid Build Coastguard Worker         , fBudgeted(budgeted)
39*c8dee2aaSAndroid Build Coastguard Worker         , fUniqueID(create_unique_id()) {
40*c8dee2aaSAndroid Build Coastguard Worker     // If we don't own the resource that must mean its wrapped in a client object. Thus we should
41*c8dee2aaSAndroid Build Coastguard Worker     // not be budgeted
42*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fOwnership == Ownership::kOwned || fBudgeted == skgpu::Budgeted::kNo);
43*c8dee2aaSAndroid Build Coastguard Worker }
44*c8dee2aaSAndroid Build Coastguard Worker 
~Resource()45*c8dee2aaSAndroid Build Coastguard Worker Resource::~Resource() {
46*c8dee2aaSAndroid Build Coastguard Worker     // The cache should have released or destroyed this resource.
47*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(this->wasDestroyed());
48*c8dee2aaSAndroid Build Coastguard Worker }
49*c8dee2aaSAndroid Build Coastguard Worker 
registerWithCache(sk_sp<ResourceCache> returnCache)50*c8dee2aaSAndroid Build Coastguard Worker void Resource::registerWithCache(sk_sp<ResourceCache> returnCache) {
51*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!fReturnCache);
52*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(returnCache);
53*c8dee2aaSAndroid Build Coastguard Worker 
54*c8dee2aaSAndroid Build Coastguard Worker     fReturnCache = std::move(returnCache);
55*c8dee2aaSAndroid Build Coastguard Worker }
56*c8dee2aaSAndroid Build Coastguard Worker 
notifyARefIsZero(LastRemovedRef removedRef) const57*c8dee2aaSAndroid Build Coastguard Worker bool Resource::notifyARefIsZero(LastRemovedRef removedRef) const {
58*c8dee2aaSAndroid Build Coastguard Worker     // No resource should have been destroyed if there was still any sort of ref on it.
59*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!this->wasDestroyed());
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker     Resource* mutableThis = const_cast<Resource*>(this);
62*c8dee2aaSAndroid Build Coastguard Worker 
63*c8dee2aaSAndroid Build Coastguard Worker     // TODO: We have not switched all resources to use the ResourceCache yet. Once we do we should
64*c8dee2aaSAndroid Build Coastguard Worker     // be able to assert that we have an fCacheReturn.
65*c8dee2aaSAndroid Build Coastguard Worker     // SkASSERT(fReturnCache);
66*c8dee2aaSAndroid Build Coastguard Worker     if (removedRef != LastRemovedRef::kCache &&
67*c8dee2aaSAndroid Build Coastguard Worker         fReturnCache &&
68*c8dee2aaSAndroid Build Coastguard Worker         fReturnCache->returnResource(mutableThis, removedRef)) {
69*c8dee2aaSAndroid Build Coastguard Worker         return false;
70*c8dee2aaSAndroid Build Coastguard Worker     }
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker     if (!this->hasAnyRefs()) {
73*c8dee2aaSAndroid Build Coastguard Worker         return true;
74*c8dee2aaSAndroid Build Coastguard Worker     }
75*c8dee2aaSAndroid Build Coastguard Worker     return false;
76*c8dee2aaSAndroid Build Coastguard Worker }
77*c8dee2aaSAndroid Build Coastguard Worker 
internalDispose()78*c8dee2aaSAndroid Build Coastguard Worker void Resource::internalDispose() {
79*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fSharedContext);
80*c8dee2aaSAndroid Build Coastguard Worker     this->invokeReleaseProc();
81*c8dee2aaSAndroid Build Coastguard Worker     this->freeGpuData();
82*c8dee2aaSAndroid Build Coastguard Worker     fSharedContext = nullptr;
83*c8dee2aaSAndroid Build Coastguard Worker     // TODO: If we ever support freeing all the backend objects without deleting the object, we'll
84*c8dee2aaSAndroid Build Coastguard Worker     // need to add a hasAnyRefs() check here.
85*c8dee2aaSAndroid Build Coastguard Worker     delete this;
86*c8dee2aaSAndroid Build Coastguard Worker }
87*c8dee2aaSAndroid Build Coastguard Worker 
isPurgeable() const88*c8dee2aaSAndroid Build Coastguard Worker bool Resource::isPurgeable() const {
89*c8dee2aaSAndroid Build Coastguard Worker     // For being purgeable we don't care if there are cacheRefs on the object since the cacheRef
90*c8dee2aaSAndroid Build Coastguard Worker     // will always be greater than 1 since we add one on insert and don't remove that ref until
91*c8dee2aaSAndroid Build Coastguard Worker     // the Resource is removed from the cache.
92*c8dee2aaSAndroid Build Coastguard Worker     return !(this->hasUsageRef() || this->hasCommandBufferRef());
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker 
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const95*c8dee2aaSAndroid Build Coastguard Worker void Resource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
96*c8dee2aaSAndroid Build Coastguard Worker     if (this->ownership() == Ownership::kWrapped && !traceMemoryDump->shouldDumpWrappedObjects()) {
97*c8dee2aaSAndroid Build Coastguard Worker         return;
98*c8dee2aaSAndroid Build Coastguard Worker     }
99*c8dee2aaSAndroid Build Coastguard Worker 
100*c8dee2aaSAndroid Build Coastguard Worker     if (this->budgeted() == skgpu::Budgeted::kNo &&
101*c8dee2aaSAndroid Build Coastguard Worker         !traceMemoryDump->shouldDumpUnbudgetedObjects()) {
102*c8dee2aaSAndroid Build Coastguard Worker         return;
103*c8dee2aaSAndroid Build Coastguard Worker     }
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker     size_t size = this->gpuMemorySize();
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker     // Avoid dumping zero-sized objects (e.g. Samplers, pipelines, etc) except memoryless textures.
108*c8dee2aaSAndroid Build Coastguard Worker     // TODO: Would a client ever actually want to see all of this? Wouldn't be hard to add it as an
109*c8dee2aaSAndroid Build Coastguard Worker     // option.
110*c8dee2aaSAndroid Build Coastguard Worker     if (size == 0 && this->asTexture() == nullptr) {
111*c8dee2aaSAndroid Build Coastguard Worker         return;
112*c8dee2aaSAndroid Build Coastguard Worker     }
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     SkString resourceName("skia/gpu_resources/resource_");
115*c8dee2aaSAndroid Build Coastguard Worker     resourceName.appendU32(this->uniqueID().asUInt());
116*c8dee2aaSAndroid Build Coastguard Worker 
117*c8dee2aaSAndroid Build Coastguard Worker     traceMemoryDump->dumpNumericValue(resourceName.c_str(), "size", "bytes", size);
118*c8dee2aaSAndroid Build Coastguard Worker     traceMemoryDump->dumpStringValue(resourceName.c_str(), "type", this->getResourceType());
119*c8dee2aaSAndroid Build Coastguard Worker     traceMemoryDump->dumpStringValue(resourceName.c_str(), "label", this->getLabel().c_str());
120*c8dee2aaSAndroid Build Coastguard Worker     if (this->isPurgeable()) {
121*c8dee2aaSAndroid Build Coastguard Worker         traceMemoryDump->dumpNumericValue(resourceName.c_str(), "purgeable_size", "bytes", size);
122*c8dee2aaSAndroid Build Coastguard Worker     }
123*c8dee2aaSAndroid Build Coastguard Worker     if (traceMemoryDump->shouldDumpWrappedObjects()) {
124*c8dee2aaSAndroid Build Coastguard Worker         traceMemoryDump->dumpWrappedState(resourceName.c_str(),
125*c8dee2aaSAndroid Build Coastguard Worker                                           this->ownership() == Ownership::kWrapped);
126*c8dee2aaSAndroid Build Coastguard Worker     }
127*c8dee2aaSAndroid Build Coastguard Worker     if (traceMemoryDump->shouldDumpUnbudgetedObjects()) {
128*c8dee2aaSAndroid Build Coastguard Worker         traceMemoryDump->dumpBudgetedState(resourceName.c_str(),
129*c8dee2aaSAndroid Build Coastguard Worker                                            this->budgeted() == skgpu::Budgeted::kYes);
130*c8dee2aaSAndroid Build Coastguard Worker     }
131*c8dee2aaSAndroid Build Coastguard Worker 
132*c8dee2aaSAndroid Build Coastguard Worker     this->onDumpMemoryStatistics(traceMemoryDump, resourceName.c_str());
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker     // TODO: implement this to report real gpu id backing the resource. Will be virtual implemented
135*c8dee2aaSAndroid Build Coastguard Worker     // by backend specific resource subclasses.
136*c8dee2aaSAndroid Build Coastguard Worker     //this->setMemoryBacking(traceMemoryDump, resourceName);
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
140*c8dee2aaSAndroid Build Coastguard Worker 
141