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