1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "gpu_resource_cache.h"
17
18 #include <algorithm>
19 #include <cinttypes>
20
21 #include <base/containers/fixed_string.h>
22 #include <base/containers/string.h>
23 #include <base/math/mathf.h>
24 #include <render/resource_handle.h>
25
26 #include "device/gpu_resource_manager.h"
27 #include "util/log.h"
28
29 RENDER_BEGIN_NAMESPACE()
30 using namespace BASE_NS;
31
32 namespace {
CreateImage(GpuResourceManager & gpuResourceMgr,const CacheGpuImageDesc & desc)33 RenderHandleReference CreateImage(GpuResourceManager& gpuResourceMgr, const CacheGpuImageDesc& desc)
34 {
35 constexpr ImageUsageFlags USAGE_FLAGS { ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
36 ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT };
37 constexpr ImageUsageFlags MSAA_USAGE_FLAGS { ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
38 ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT };
39 constexpr MemoryPropertyFlags MEMORY_FLAGS { MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
40 constexpr MemoryPropertyFlags MSAA_MEMORY_FLAGS {
41 MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
42 MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
43 };
44 const ImageUsageFlags usageFlags =
45 (desc.sampleCountFlags > SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT) ? MSAA_USAGE_FLAGS : USAGE_FLAGS;
46 const MemoryPropertyFlags memoryFlags =
47 (desc.sampleCountFlags > SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT) ? MSAA_MEMORY_FLAGS : MEMORY_FLAGS;
48
49 const GpuImageDesc newDesc {
50 ImageType::CORE_IMAGE_TYPE_2D, // imageType
51 ImageViewType::CORE_IMAGE_VIEW_TYPE_2D, // imageViewType
52 desc.format, // format
53 ImageTiling::CORE_IMAGE_TILING_OPTIMAL, // imageTiling
54 usageFlags, // usageFlags
55 memoryFlags, // memoryPropertyFlags
56 0, // createFlags
57 EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS |
58 EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_RESET_STATE_ON_FRAME_BORDERS, // engineCreationFlags
59 desc.width, // width
60 desc.height, // height
61 1, // depth
62 desc.mipCount, // mipCount
63 desc.layerCount, // layerCount
64 desc.sampleCountFlags, // sampleCountFlags
65 desc.componentMapping, // componentMapping
66 };
67
68 return gpuResourceMgr.CreateShallowHandle(newDesc);
69 }
70 } // namespace
71
GpuResourceCache(GpuResourceManager & gpuResourceMgr)72 GpuResourceCache::GpuResourceCache(GpuResourceManager& gpuResourceMgr) : gpuResourceMgr_(gpuResourceMgr) {}
73
~GpuResourceCache()74 GpuResourceCache::~GpuResourceCache()
75 {
76 #if (RENDER_VALIDATION_ENABLED == 1)
77 {
78 const auto clientLock = std::lock_guard(mutex_);
79
80 uint32_t aliveCounter = 0;
81 const uint32_t readIdx = 1u - writeIdx_;
82 for (const auto& imagesRef : frameData_[writeIdx_].images) {
83 if (imagesRef.handle && (imagesRef.handle.GetRefCount() > 2)) { // 2:count number
84 aliveCounter++;
85 }
86 }
87 for (const auto& imagesRef : frameData_[readIdx].images) {
88 if (imagesRef.handle && (imagesRef.handle.GetRefCount() > 2)) { // 2: count number
89 aliveCounter++;
90 }
91 }
92 if (aliveCounter > 0) {
93 PLUGIN_LOG_W("RENDER_VALIDATION: Not all GPU resource cache references released (count: %u)", aliveCounter);
94 }
95 };
96 #endif
97 }
98
BeginFrame(const uint64_t frameCount)99 void GpuResourceCache::BeginFrame(const uint64_t frameCount)
100 {
101 const auto lock = std::lock_guard(mutex_);
102
103 // NOTE: does not try to re-use handles
104 if (frameCount == frameCounter_) {
105 return;
106 }
107 frameCounter_ = frameCount;
108 writeIdx_ = 1u - writeIdx_;
109
110 AllocateAndRemapImages();
111 DestroyOldImages();
112 }
113
GetImageData() const114 array_view<const GpuResourceCache::ImageData> GpuResourceCache::GetImageData() const
115 {
116 const uint32_t readIdx = 1u - writeIdx_;
117 return frameData_[readIdx].images;
118 }
119
ReserveGpuImageImpl(const CacheGpuImageDesc & desc)120 RenderHandleReference GpuResourceCache::ReserveGpuImageImpl(const CacheGpuImageDesc& desc)
121 {
122 const auto lock = std::lock_guard(mutex_);
123
124 auto& fd = frameData_[writeIdx_];
125 fd.images.push_back({ CreateImage(gpuResourceMgr_, desc), HashCacheGpuImageDesc(desc) });
126 return fd.images.back().handle;
127 }
128
ReserveGpuImage(const CacheGpuImageDesc & desc)129 RenderHandleReference GpuResourceCache::ReserveGpuImage(const CacheGpuImageDesc& desc)
130 {
131 return ReserveGpuImageImpl(desc);
132 }
133
ReserveGpuImages(const array_view<const CacheGpuImageDesc> descs)134 vector<RenderHandleReference> GpuResourceCache::ReserveGpuImages(const array_view<const CacheGpuImageDesc> descs)
135 {
136 vector<RenderHandleReference> handles(descs.size());
137 for (size_t idx = 0; idx < handles.size(); ++idx) {
138 handles[idx] = ReserveGpuImageImpl(descs[idx]);
139 }
140 return handles;
141 }
142
GetCacheGpuImageDesc(const RenderHandleReference & gpuImageHandle) const143 CacheGpuImageDesc GpuResourceCache::GetCacheGpuImageDesc(const RenderHandleReference& gpuImageHandle) const
144 {
145 const GpuImageDesc desc = gpuResourceMgr_.GetImageDescriptor(gpuImageHandle);
146 return { desc.format, desc.width, desc.height, desc.mipCount, desc.layerCount, desc.sampleCountFlags,
147 desc.componentMapping };
148 }
149
ReserveGpuImagePair(const CacheGpuImageDesc & desc,const SampleCountFlags sampleCountFlags)150 CacheGpuImagePair GpuResourceCache::ReserveGpuImagePair(
151 const CacheGpuImageDesc& desc, const SampleCountFlags sampleCountFlags)
152 {
153 // allocate both handles
154 CacheGpuImageDesc secondDesc = desc;
155 secondDesc.sampleCountFlags = sampleCountFlags;
156 return CacheGpuImagePair { ReserveGpuImageImpl(desc), ReserveGpuImageImpl(secondDesc) };
157 }
158
AllocateAndRemapImages()159 void GpuResourceCache::AllocateAndRemapImages()
160 {
161 const uint32_t readIdx = 1u - writeIdx_;
162 const auto& images = frameData_[readIdx].images;
163 for (const auto& ref : images) {
164 RenderHandle remapHandle;
165 for (auto& gpuRef : gpuBackedImages_) {
166 if ((gpuRef.hash == ref.hash) && (gpuRef.frameUseIndex != frameCounter_)) {
167 remapHandle = gpuRef.handle.GetHandle();
168 gpuRef.frameUseIndex = frameCounter_;
169 break;
170 }
171 }
172 if (!RenderHandleUtil::IsValid(remapHandle)) {
173 GpuImageDesc desc = gpuResourceMgr_.GetImageDescriptor(ref.handle);
174 RenderHandleReference handle = gpuResourceMgr_.Create(desc);
175 remapHandle = handle.GetHandle();
176 gpuBackedImages_.push_back({ ref.hash, frameCounter_, move(handle) });
177 }
178 gpuResourceMgr_.RemapGpuImageHandle(ref.handle.GetHandle(), remapHandle);
179 }
180 }
181
DestroyOldImages()182 void GpuResourceCache::DestroyOldImages()
183 {
184 // shallow handles
185 {
186 const uint32_t readIdx = 1u - writeIdx_;
187 auto& imagesRef = frameData_[readIdx].images;
188 const auto invalidHandles = std::partition(imagesRef.begin(), imagesRef.end(), [&](const ImageData& imgRef) {
189 if (imgRef.handle.GetRefCount() > 2) {
190 return true;
191 } else {
192 PLUGIN_ASSERT(imgRef.handle.GetRefCount() == 2);
193 return false;
194 }
195 });
196 if (invalidHandles != imagesRef.end()) {
197 imagesRef.erase(invalidHandles, imagesRef.end());
198 }
199 }
200 // gpu backed resources
201 {
202 constexpr uint64_t minAge = 2;
203 const auto ageLimit = (frameCounter_ < minAge) ? 0 : (frameCounter_ - minAge);
204 const auto invalidHandles =
205 std::partition(gpuBackedImages_.begin(), gpuBackedImages_.end(), [&](const GpuBackedData& imgRef) {
206 if (imgRef.frameUseIndex < ageLimit) {
207 return false;
208 } else {
209 return true;
210 }
211 });
212 if (invalidHandles != gpuBackedImages_.end()) {
213 gpuBackedImages_.erase(invalidHandles, gpuBackedImages_.end());
214 }
215 }
216 }
217
HashCacheGpuImageDesc(const CacheGpuImageDesc & desc) const218 uint64_t GpuResourceCache::HashCacheGpuImageDesc(const CacheGpuImageDesc& desc) const
219 {
220 // pack: width, height, mipCount, layerCount to a single 64 bit "hash"
221 const uint32_t sizeHash = (desc.width << 16u) | desc.height;
222 const uint32_t mipLayerSwizzleHash = (desc.componentMapping.r << 28) | (desc.componentMapping.g << 24) |
223 (desc.componentMapping.b << 20) | (desc.componentMapping.a << 16) |
224 (desc.mipCount << 8u) | desc.layerCount;
225 const uint64_t formatSamplesHash =
226 ((static_cast<uint64_t>(desc.format)) << 32) | ((static_cast<uint64_t>(desc.sampleCountFlags)) & 0xFFFFffff);
227 uint64_t hash = (static_cast<uint64_t>(mipLayerSwizzleHash) << 32u) | sizeHash;
228 HashCombine(hash, formatSamplesHash);
229 return hash;
230 }
231 RENDER_END_NAMESPACE()
232