• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/math/mathf.h>
22 #include <render/resource_handle.h>
23 
24 #include "device/gpu_resource_manager.h"
25 #include "util/log.h"
26 
27 RENDER_BEGIN_NAMESPACE()
28 using namespace BASE_NS;
29 
30 namespace {
CreateImage(GpuResourceManager & gpuResourceMgr,const CacheGpuImageDesc & desc)31 RenderHandleReference CreateImage(GpuResourceManager& gpuResourceMgr, const CacheGpuImageDesc& desc)
32 {
33     constexpr ImageUsageFlags USAGE_FLAGS { ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
34                                             ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT };
35     constexpr ImageUsageFlags MSAA_USAGE_FLAGS { ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
36                                                  ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT };
37     constexpr MemoryPropertyFlags MEMORY_FLAGS { MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT };
38     constexpr MemoryPropertyFlags MSAA_MEMORY_FLAGS {
39         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
40         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
41     };
42     const ImageUsageFlags usageFlags =
43         (desc.sampleCountFlags > SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT) ? MSAA_USAGE_FLAGS : USAGE_FLAGS;
44     const MemoryPropertyFlags memoryFlags =
45         (desc.sampleCountFlags > SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT) ? MSAA_MEMORY_FLAGS : MEMORY_FLAGS;
46 
47     const GpuImageDesc newDesc {
48         ImageType::CORE_IMAGE_TYPE_2D,          // imageType
49         ImageViewType::CORE_IMAGE_VIEW_TYPE_2D, // imageViewType
50         desc.format,                            // format
51         ImageTiling::CORE_IMAGE_TILING_OPTIMAL, // imageTiling
52         usageFlags,                             // usageFlags
53         memoryFlags,                            // memoryPropertyFlags
54         0,                                      // createFlags
55         EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS |
56             EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_RESET_STATE_ON_FRAME_BORDERS, // engineCreationFlags
57         desc.width,                                                                               // width
58         desc.height,                                                                              // height
59         1,                                                                                        // depth
60         desc.mipCount,                                                                            // mipCount
61         desc.layerCount,                                                                          // layerCount
62         desc.sampleCountFlags,                                                                    // sampleCountFlags
63         desc.componentMapping,                                                                    // componentMapping
64     };
65 
66     return gpuResourceMgr.CreateShallowHandle(newDesc);
67 }
68 } // namespace
69 
GpuResourceCache(GpuResourceManager & gpuResourceMgr)70 GpuResourceCache::GpuResourceCache(GpuResourceManager& gpuResourceMgr) : gpuResourceMgr_(gpuResourceMgr) {}
71 
~GpuResourceCache()72 GpuResourceCache::~GpuResourceCache()
73 {
74 #if (RENDER_VALIDATION_ENABLED == 1)
75     {
76         const auto clientLock = std::lock_guard(mutex_);
77 
78         uint32_t aliveCounter = 0;
79         const uint32_t readIdx = 1u - writeIdx_;
80         for (const auto& imagesRef : frameData_[writeIdx_].images) {
81             if (imagesRef.handle && (imagesRef.handle.GetRefCount() > 2)) { // 2 : count
82                 aliveCounter++;
83             }
84         }
85         for (const auto& imagesRef : frameData_[readIdx].images) {
86             if (imagesRef.handle && (imagesRef.handle.GetRefCount() > 2)) { // 2 : count
87                 aliveCounter++;
88             }
89         }
90         if (aliveCounter > 0) {
91             PLUGIN_LOG_W("RENDER_VALIDATION: Not all GPU resource cache references released (count: %u)", aliveCounter);
92         }
93     };
94 #endif
95 }
96 
BeginFrame(const uint64_t frameCount)97 void GpuResourceCache::BeginFrame(const uint64_t frameCount)
98 {
99     const auto lock = std::lock_guard(mutex_);
100 
101     // NOTE: does not try to re-use handles
102     if (frameCount == frameCounter_) {
103         return;
104     }
105     frameCounter_ = frameCount;
106     writeIdx_ = 1u - writeIdx_;
107 
108     DestroyOldImages();
109     AllocateAndRemapImages();
110 }
111 
GetImageData() const112 array_view<const GpuResourceCache::ImageData> GpuResourceCache::GetImageData() const
113 {
114     const uint32_t readIdx = 1u - writeIdx_;
115     return frameData_[readIdx].images;
116 }
117 
ReserveGpuImageImpl(const CacheGpuImageDesc & desc)118 RenderHandleReference GpuResourceCache::ReserveGpuImageImpl(const CacheGpuImageDesc& desc)
119 {
120     const auto lock = std::lock_guard(mutex_);
121 
122     auto& fd = frameData_[writeIdx_];
123     fd.images.push_back({ CreateImage(gpuResourceMgr_, desc), HashCacheGpuImageDesc(desc) });
124     return fd.images.back().handle;
125 }
126 
ReserveGpuImage(const CacheGpuImageDesc & desc)127 RenderHandleReference GpuResourceCache::ReserveGpuImage(const CacheGpuImageDesc& desc)
128 {
129     return ReserveGpuImageImpl(desc);
130 }
131 
ReserveGpuImages(const array_view<const CacheGpuImageDesc> descs)132 vector<RenderHandleReference> GpuResourceCache::ReserveGpuImages(const array_view<const CacheGpuImageDesc> descs)
133 {
134     vector<RenderHandleReference> handles(descs.size());
135     for (size_t idx = 0; idx < handles.size(); ++idx) {
136         handles[idx] = ReserveGpuImageImpl(descs[idx]);
137     }
138     return handles;
139 }
140 
GetCacheGpuImageDesc(const RenderHandleReference & gpuImageHandle) const141 CacheGpuImageDesc GpuResourceCache::GetCacheGpuImageDesc(const RenderHandleReference& gpuImageHandle) const
142 {
143     const GpuImageDesc desc = gpuResourceMgr_.GetImageDescriptor(gpuImageHandle);
144     return { desc.format, desc.width, desc.height, desc.mipCount, desc.layerCount, desc.sampleCountFlags,
145         desc.componentMapping };
146 }
147 
ReserveGpuImagePair(const CacheGpuImageDesc & desc,const SampleCountFlags sampleCountFlags)148 CacheGpuImagePair GpuResourceCache::ReserveGpuImagePair(
149     const CacheGpuImageDesc& desc, const SampleCountFlags sampleCountFlags)
150 {
151     // allocate both handles
152     CacheGpuImageDesc secondDesc = desc;
153     secondDesc.sampleCountFlags = sampleCountFlags;
154     return CacheGpuImagePair { ReserveGpuImageImpl(desc), ReserveGpuImageImpl(secondDesc) };
155 }
156 
AllocateAndRemapImages()157 void GpuResourceCache::AllocateAndRemapImages()
158 {
159     const uint32_t readIdx = 1u - writeIdx_;
160     const auto& images = frameData_[readIdx].images;
161     for (const auto& ref : images) {
162         RenderHandle remapHandle;
163         for (auto& gpuRef : gpuBackedImages_) {
164             if ((gpuRef.hash == ref.hash) && (gpuRef.frameUseIndex != frameCounter_)) {
165                 remapHandle = gpuRef.handle.GetHandle();
166                 gpuRef.frameUseIndex = frameCounter_;
167                 break;
168             }
169         }
170         if (!RenderHandleUtil::IsValid(remapHandle)) {
171             GpuImageDesc desc = gpuResourceMgr_.GetImageDescriptor(ref.handle);
172             RenderHandleReference handle = gpuResourceMgr_.Create(desc);
173             remapHandle = handle.GetHandle();
174             gpuBackedImages_.push_back({ ref.hash, frameCounter_, move(handle) });
175         }
176         gpuResourceMgr_.RemapGpuImageHandle(ref.handle.GetHandle(), remapHandle);
177     }
178 }
179 
DestroyOldImages()180 void GpuResourceCache::DestroyOldImages()
181 {
182     // shallow handles
183     {
184         const uint32_t readIdx = 1u - writeIdx_;
185         auto& imagesRef = frameData_[readIdx].images;
186         const auto invalidHandles = std::partition(imagesRef.begin(), imagesRef.end(), [&](const ImageData& imgRef) {
187             if (imgRef.handle.GetRefCount() > 2) {
188                 return true;
189             } else {
190                 PLUGIN_ASSERT(imgRef.handle.GetRefCount() == 2);
191                 return false;
192             }
193         });
194         if (invalidHandles != imagesRef.end()) {
195             imagesRef.erase(invalidHandles, imagesRef.end());
196         }
197     }
198     // gpu backed resources
199     {
200         constexpr uint64_t minAge = 2;
201         const auto ageLimit = (frameCounter_ < minAge) ? 0 : (frameCounter_ - minAge);
202         const auto invalidHandles =
203             std::partition(gpuBackedImages_.begin(), gpuBackedImages_.end(), [&](const GpuBackedData& imgRef) {
204                 if (imgRef.frameUseIndex < ageLimit) {
205                     return false;
206                 } else {
207                     return true;
208                 }
209             });
210         if (invalidHandles != gpuBackedImages_.end()) {
211             gpuBackedImages_.erase(invalidHandles, gpuBackedImages_.end());
212         }
213     }
214 }
215 
HashCacheGpuImageDesc(const CacheGpuImageDesc & desc)216 uint64_t GpuResourceCache::HashCacheGpuImageDesc(const CacheGpuImageDesc& desc)
217 {
218     // pack: width, height, mipCount, layerCount to a single 64 bit "hash"
219     const uint32_t sizeHash = (desc.width << 16u) | desc.height;
220     const uint32_t mipLayerSwizzleHash = (desc.componentMapping.r << 28) | (desc.componentMapping.g << 24) |
221                                          (desc.componentMapping.b << 20) | (desc.componentMapping.a << 16) |
222                                          (desc.mipCount << 8u) | desc.layerCount;
223     const uint64_t formatSamplesHash =
224         ((static_cast<uint64_t>(desc.format)) << 32) | ((static_cast<uint64_t>(desc.sampleCountFlags)) & 0xFFFFffff);
225     uint64_t hash = ((static_cast<uint64_t>(mipLayerSwizzleHash)) << 32u) | sizeHash;
226     HashCombine(hash, formatSamplesHash);
227     return hash;
228 }
229 RENDER_END_NAMESPACE()
230