• 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_manager.h"
17 
18 #include <algorithm>
19 #include <cinttypes>
20 #if !defined(NDEBUG) || (defined(PLUGIN_LOG_DEBUG) && (PLUGIN_LOG_DEBUG == 1))
21 #include <sstream>
22 #include <thread>
23 #endif
24 
25 #include <base/math/mathf.h>
26 #include <render/namespace.h>
27 
28 #include "device/device.h"
29 #include "device/gpu_buffer.h"
30 #include "device/gpu_image.h"
31 #include "device/gpu_resource_cache.h"
32 #include "device/gpu_resource_desc_flag_validation.h"
33 #include "device/gpu_resource_manager_base.h"
34 #include "device/gpu_sampler.h"
35 #include "resource_handle_impl.h"
36 #include "util/log.h"
37 
38 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
39 #include "device/gpu_resource_util.h"
40 #endif
41 
42 using namespace BASE_NS;
43 using namespace CORE_NS;
44 
45 RENDER_BEGIN_NAMESPACE()
46 namespace {
47 constexpr uint32_t INVALID_PENDING_INDEX { ~0u };
48 constexpr uint32_t MAX_IMAGE_EXTENT { 32768u }; // should be fetched from the device
49 
50 constexpr MemoryPropertyFlags NEEDED_DEVICE_MEMORY_PROPERTY_FLAGS_FOR_STAGING_MEM_OPT {
51     CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT
52 };
53 constexpr MemoryPropertyFlags ADD_STAGING_MEM_OPT_FLAGS { CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
54                                                           CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT };
55 
56 constexpr uint32_t BUFFER_ALIGNMENT { 256U };
57 
Align(uint32_t value,uint32_t align)58 constexpr uint32_t Align(uint32_t value, uint32_t align)
59 {
60     if (value == 0) {
61         return 0;
62     }
63     return ((value + align) / align) * align;
64 }
65 
66 // make sure that generation is valid
67 constexpr uint64_t INVALIDATE_GENERATION_SHIFT { 32 };
InvalidateWithGeneration(const EngineResourceHandle handle)68 EngineResourceHandle InvalidateWithGeneration(const EngineResourceHandle handle)
69 {
70     return { handle.id | ~RenderHandleUtil::RES_HANDLE_GENERATION_MASK };
71 }
72 
UnpackNewHandle(const EngineResourceHandle & handle,const RenderHandleType type,const uint32_t arrayIndex)73 EngineResourceHandle UnpackNewHandle(
74     const EngineResourceHandle& handle, const RenderHandleType type, const uint32_t arrayIndex)
75 {
76     // increments generation counter
77     if (RenderHandleUtil::IsValid(handle)) {
78         const uint32_t gpuGenIndex = RenderHandleUtil::GetGenerationIndexPart(handle) + 1;
79         return RenderHandleUtil::CreateEngineResourceHandle(type, arrayIndex, gpuGenIndex);
80     } else {
81         const uint64_t genIndex =
82             (InvalidateWithGeneration(handle).id & RenderHandleUtil::RES_HANDLE_GENERATION_MASK) >>
83             INVALIDATE_GENERATION_SHIFT;
84         const uint32_t gpuGenIndex = uint32_t(genIndex) + 1;
85         return RenderHandleUtil::CreateEngineResourceHandle(type, arrayIndex, gpuGenIndex);
86     }
87 }
88 
89 // we need to know if image is a depth format when binding to descriptor set as read only
GetAdditionalImageFlagsFromFormat(const Format format)90 constexpr RenderHandleInfoFlags GetAdditionalImageFlagsFromFormat(const Format format)
91 {
92     RenderHandleInfoFlags flags {};
93 
94     const bool isDepthFormat =
95         ((format == Format::BASE_FORMAT_D16_UNORM) || (format == Format::BASE_FORMAT_X8_D24_UNORM_PACK32) ||
96             (format == Format::BASE_FORMAT_D32_SFLOAT) || (format == Format::BASE_FORMAT_D24_UNORM_S8_UINT));
97     if (isDepthFormat) {
98         flags |= CORE_RESOURCE_HANDLE_DEPTH_IMAGE;
99     }
100 
101     return flags;
102 }
103 
104 #if (RENDER_VALIDATION_ENABLED == 1)
ValidateGpuBufferDesc(const GpuBufferDesc & desc)105 void ValidateGpuBufferDesc(const GpuBufferDesc& desc)
106 {
107     if (desc.usageFlags == 0) {
108         PLUGIN_LOG_E("RENDER_VALIDATION: BufferUsageFlags must not be 0");
109     }
110     if ((desc.usageFlags & (~GpuResourceDescFlagValidation::ALL_GPU_BUFFER_USAGE_FLAGS)) != 0) {
111         PLUGIN_LOG_E("RENDER_VALIDATION: Invalid BufferUsageFlags (%u)", desc.usageFlags);
112     }
113     if (desc.memoryPropertyFlags == 0) {
114         PLUGIN_LOG_E("RENDER_VALIDATION: MemoryPropertyFlags must not be 0");
115     }
116     if ((desc.memoryPropertyFlags & (~GpuResourceDescFlagValidation::ALL_MEMORY_PROPERTY_FLAGS)) != 0) {
117         PLUGIN_LOG_E("RENDER_VALIDATION: Invalid MemoryPropertyFlags (%u)", desc.memoryPropertyFlags);
118     }
119     if ((desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_MAP_OUTSIDE_RENDERER) &&
120         ((desc.memoryPropertyFlags & MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)) {
121         PLUGIN_LOG_E(
122             "RENDER_VALIDATION: Invalid MemoryPropertyFlags for CORE_ENGINE_BUFFER_CREATION_MAP_OUTSIDE_RENDERER (%u)",
123             desc.memoryPropertyFlags);
124     }
125     if (desc.byteSize == 0) {
126         PLUGIN_LOG_E("RENDER_VALIDATION: Buffer byteSize must larger than zero");
127     }
128 }
129 
ValidateGpuImageDesc(const GpuImageDesc & desc,const string_view name)130 void ValidateGpuImageDesc(const GpuImageDesc& desc, const string_view name)
131 {
132     bool valid = true;
133     if (desc.format == Format::BASE_FORMAT_UNDEFINED) {
134         PLUGIN_LOG_E("RENDER_VALIDATION: Undefined image format");
135         valid = false;
136     }
137     if (desc.imageType > ImageType::CORE_IMAGE_TYPE_3D) {
138         PLUGIN_LOG_E("RENDER_VALIDATION: Unsupported image type");
139         valid = false;
140     }
141     if ((desc.imageViewType == ImageViewType::CORE_IMAGE_VIEW_TYPE_2D) && (desc.layerCount > 1u)) {
142         PLUGIN_LOG_E(
143             "RENDER_VALIDATION: Default image view is done for sampling / shader resource access and needs to be "
144             "CORE_IMAGE_VIEW_TYPE_2D_ARRAY with multiple layers");
145         valid = false;
146     }
147     if (desc.imageTiling > ImageTiling::CORE_IMAGE_TILING_LINEAR) {
148         PLUGIN_LOG_E("RENDER_VALIDATION: Unsupported image tiling mode (%u)", static_cast<uint32_t>(desc.imageTiling));
149         valid = false;
150     }
151     if (desc.usageFlags == 0) {
152         PLUGIN_LOG_E("RENDER_VALIDATION: ImageUsageFlags must not be 0");
153         valid = false;
154     }
155     if ((desc.usageFlags & (~GpuResourceDescFlagValidation::ALL_GPU_IMAGE_USAGE_FLAGS)) != 0) {
156         PLUGIN_LOG_E("RENDER_VALIDATION: Invalid ImageUsageFlags (%u)", desc.usageFlags);
157         valid = false;
158     }
159     if (desc.memoryPropertyFlags == 0) {
160         PLUGIN_LOG_E("RENDER_VALIDATION: MemoryPropertyFlags must not be 0");
161         valid = false;
162     }
163     if ((desc.memoryPropertyFlags & (~GpuResourceDescFlagValidation::ALL_MEMORY_PROPERTY_FLAGS)) != 0) {
164         PLUGIN_LOG_E("RENDER_VALIDATION: Invalid MemoryPropertyFlags (%u)", desc.memoryPropertyFlags);
165         valid = false;
166     }
167     if (desc.width == 0 || desc.height == 0 || desc.depth == 0) {
168         PLUGIN_LOG_E("RENDER_VALIDATION: Image extents must not be zero (x:%u, y:%u, z:%u)", desc.width, desc.height,
169             desc.depth);
170         valid = false;
171     }
172     if (desc.width > MAX_IMAGE_EXTENT || desc.height > MAX_IMAGE_EXTENT || desc.depth > MAX_IMAGE_EXTENT) {
173         PLUGIN_LOG_E("RENDER_VALIDATION: Image extents must not be bigger than (%u) (x:%u, y:%u, z:%u)",
174             MAX_IMAGE_EXTENT, desc.width, desc.height, desc.depth);
175         valid = false;
176     }
177     if (desc.mipCount == 0 || desc.layerCount == 0) {
178         PLUGIN_LOG_E("RENDER_VALIDATION: Image mip and layer count must be >=1 (mipCount:%u, layerCount:%u)",
179             desc.mipCount, desc.layerCount);
180         valid = false;
181     }
182     if ((desc.createFlags & (~GpuResourceDescFlagValidation::ALL_IMAGE_CREATE_FLAGS)) != 0) {
183         PLUGIN_LOG_E("RENDER_VALIDATION: Invalid ImageCreateFlags (%u)", desc.createFlags);
184         valid = false;
185     }
186     if ((desc.engineCreationFlags & CORE_ENGINE_IMAGE_CREATION_GENERATE_MIPS) &&
187         ((desc.usageFlags & CORE_IMAGE_USAGE_TRANSFER_SRC_BIT) == 0)) {
188         PLUGIN_LOG_E(
189             "RENDER_VALIDATION: Must use usage flags CORE_IMAGE_USAGE_TRANSFER_SRC_BIT when generating mip maps");
190         valid = false;
191     }
192     if (desc.usageFlags & CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) {
193         const ImageUsageFlags usageFlags =
194             desc.usageFlags &
195             ~(CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | CORE_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
196                 CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
197         if (usageFlags != 0) {
198             PLUGIN_LOG_E(
199                 "RENDER_VALIDATION: If image usage flags contain CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, only "
200                 "DEPTH_STENCIL_ATTACHMENT_BIT, INPUT_ATTACHMENT_BIT, and COLOR_ATTACHMENT_BIT can be set.");
201             valid = false;
202         }
203     }
204     if ((desc.layerCount > 1u) && (desc.imageViewType <= CORE_IMAGE_VIEW_TYPE_3D)) {
205         PLUGIN_LOG_E("RENDER_VALIDATION: If image layer count (%u) is larger than 1, then image view type must be "
206                      "CORE_IMAGE_VIEW_TYPE_XX_ARRAY",
207             desc.layerCount);
208         valid = false;
209     }
210 
211     if ((!valid) && (!name.empty())) {
212         PLUGIN_LOG_E("RENDER_VALIDATION: validation issue(s) with image (name: %s)", name.data());
213     }
214 }
215 
ValidateGpuAccelerationStructureDesc(const GpuAccelerationStructureDesc & desc)216 void ValidateGpuAccelerationStructureDesc(const GpuAccelerationStructureDesc& desc)
217 {
218     ValidateGpuBufferDesc(desc.bufferDesc);
219     if ((desc.bufferDesc.usageFlags & CORE_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT) == 0) {
220         PLUGIN_LOG_E("RENDER_VALIDATION: usageFlags must include CORE_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT "
221                      "for acceleration structures");
222     }
223 }
224 
ValidateGpuImageCopy(const GpuImageDesc & desc,const BufferImageCopy & copy,const string_view name)225 void ValidateGpuImageCopy(const GpuImageDesc& desc, const BufferImageCopy& copy, const string_view name)
226 {
227     const uint32_t mip = copy.imageSubresource.mipLevel;
228     const Size3D imageSize { desc.width >> mip, desc.height >> mip, desc.depth };
229     if ((copy.imageOffset.width >= imageSize.width) || (copy.imageOffset.width >= imageSize.height) ||
230         (copy.imageOffset.depth >= imageSize.depth)) {
231         PLUGIN_LOG_E(
232             "RENDER_VALIDATION: BufferImageCopy offset exceeds GpuImageDesc. Mipsize: %u, %u, %u, offset: %u %u %u. "
233             "(name: %s)",
234             imageSize.width, imageSize.height, imageSize.depth, copy.imageOffset.width, copy.imageOffset.height,
235             copy.imageOffset.depth, name.data());
236     }
237 }
238 #endif
239 
GetValidGpuBufferDesc(const GpuBufferDesc & desc)240 inline constexpr GpuBufferDesc GetValidGpuBufferDesc(const GpuBufferDesc& desc)
241 {
242     return GpuBufferDesc {
243         desc.usageFlags & GpuResourceDescFlagValidation::ALL_GPU_BUFFER_USAGE_FLAGS,
244         desc.memoryPropertyFlags & GpuResourceDescFlagValidation::ALL_MEMORY_PROPERTY_FLAGS,
245         desc.engineCreationFlags,
246         desc.byteSize,
247     };
248 }
249 
GetMapBufferDesc(const uint32_t byteSize)250 inline constexpr GpuBufferDesc GetMapBufferDesc(const uint32_t byteSize)
251 {
252     return {
253         BufferUsageFlagBits::CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
254         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT |
255             MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
256         0U,
257         byteSize,
258     };
259 }
260 
CheckAndEnableMemoryOptimizations(const uint32_t gpuResourceMgrFlags,GpuBufferDesc & desc)261 inline constexpr void CheckAndEnableMemoryOptimizations(const uint32_t gpuResourceMgrFlags, GpuBufferDesc& desc)
262 {
263     if (gpuResourceMgrFlags & GpuResourceManager::GPU_RESOURCE_MANAGER_OPTIMIZE_STAGING_MEMORY) {
264         if ((desc.memoryPropertyFlags == CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &&
265             (desc.usageFlags & CORE_BUFFER_USAGE_TRANSFER_DST_BIT) &&
266             (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_ENABLE_MEMORY_OPTIMIZATIONS)) {
267             desc.memoryPropertyFlags |= ADD_STAGING_MEM_OPT_FLAGS;
268         }
269     }
270 }
271 
GetScalingImageNeed(const GpuImageDesc & desc,const array_view<const IImageContainer::SubImageDesc> & copies)272 inline constexpr bool GetScalingImageNeed(
273     const GpuImageDesc& desc, const array_view<const IImageContainer::SubImageDesc>& copies)
274 {
275     bool scale = false;
276     if (desc.engineCreationFlags & EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_SCALE) {
277         // we only support single image (single buffer image copy) scaling
278         if (copies.size() == 1) {
279             scale = (copies[0].width != desc.width) || (copies[0].height != desc.height);
280         }
281     }
282     return scale;
283 }
284 
GetScalingImageNeed(const GpuImageDesc & desc,const array_view<const BufferImageCopy> & copies)285 inline constexpr bool GetScalingImageNeed(const GpuImageDesc& desc, const array_view<const BufferImageCopy>& copies)
286 {
287     bool scale = false;
288     if (desc.engineCreationFlags & EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_SCALE) {
289         // we only support single image (single buffer image copy) scaling
290         if (copies.size() == 1) {
291             scale = (copies[0].imageExtent.width != desc.width) || (copies[0].imageExtent.height != desc.height);
292         }
293     }
294     return scale;
295 }
296 
297 // staging needs to be locked when called with the input resources
UpdateStagingScaling(const Format format,const array_view<const IImageContainer::SubImageDesc> & copies,ScalingImageDataStruct & siData)298 void UpdateStagingScaling(
299     const Format format, const array_view<const IImageContainer::SubImageDesc>& copies, ScalingImageDataStruct& siData)
300 {
301     PLUGIN_ASSERT(copies.size() == 1);
302     if (auto iter = siData.formatToScalingImages.find(format); iter != siData.formatToScalingImages.end()) {
303         const size_t index = iter->second;
304         PLUGIN_ASSERT(index < siData.scalingImages.size());
305         auto& scaleImage = siData.scalingImages[index];
306         scaleImage.maxWidth = Math::max(scaleImage.maxWidth, copies[0].width);
307         scaleImage.maxHeight = Math::max(scaleImage.maxHeight, copies[0].height);
308     } else {
309         const size_t index = siData.scalingImages.size();
310         siData.scalingImages.push_back({ {}, format, copies[0].width, copies[0].height });
311         siData.formatToScalingImages[format] = index;
312     }
313 }
314 
UpdateStagingScaling(const Format format,const array_view<const BufferImageCopy> & copies,ScalingImageDataStruct & siData)315 void UpdateStagingScaling(
316     const Format format, const array_view<const BufferImageCopy>& copies, ScalingImageDataStruct& siData)
317 {
318     PLUGIN_ASSERT(copies.size() == 1);
319     const auto& extent = copies[0].imageExtent;
320     if (auto iter = siData.formatToScalingImages.find(format); iter != siData.formatToScalingImages.end()) {
321         const size_t index = iter->second;
322         PLUGIN_ASSERT(index < siData.scalingImages.size());
323         auto& scaleImage = siData.scalingImages[index];
324         scaleImage.maxWidth = Math::max(scaleImage.maxWidth, extent.width);
325         scaleImage.maxHeight = Math::max(scaleImage.maxHeight, extent.height);
326     } else {
327         const size_t index = siData.scalingImages.size();
328         siData.scalingImages.push_back({ {}, format, extent.width, extent.height });
329         siData.formatToScalingImages[format] = index;
330     }
331 }
332 
GetStagingScalingImageDesc(const Format format,const uint32_t width,const uint32_t height)333 GpuImageDesc GetStagingScalingImageDesc(const Format format, const uint32_t width, const uint32_t height)
334 {
335     return GpuImageDesc {
336         ImageType::CORE_IMAGE_TYPE_2D,
337         ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,
338         format,
339         ImageTiling::CORE_IMAGE_TILING_OPTIMAL,
340         // NOTE sampled is not needed, but image view should not be created
341         ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSFER_SRC_BIT | ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSFER_DST_BIT |
342             ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT,
343         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
344         0,
345         0, // No dynamic barrriers
346         width,
347         height,
348         1u,
349         1u,
350         1u,
351         1u,
352         {},
353     };
354 }
355 
ConvertCoreBufferImageCopy(const IImageContainer::SubImageDesc & bufferImageCopy,const uint32_t additionalBufferOffset)356 BufferImageCopy ConvertCoreBufferImageCopy(
357     const IImageContainer::SubImageDesc& bufferImageCopy, const uint32_t additionalBufferOffset)
358 {
359     return BufferImageCopy {
360         /** Buffer offset */
361         bufferImageCopy.bufferOffset + additionalBufferOffset,
362         /** Buffer row length */
363         bufferImageCopy.bufferRowLength,
364         /** Buffer image height */
365         bufferImageCopy.bufferImageHeight,
366         /** Image subresource */
367         { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, bufferImageCopy.mipLevel, 0, bufferImageCopy.layerCount },
368         /** Image offset */
369         { 0, 0, 0 },
370         /** Image extent */
371         { bufferImageCopy.width, bufferImageCopy.height, bufferImageCopy.depth },
372     };
373 }
374 
375 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
LogGpuResource(const RenderHandle & gpuHandle,const EngineResourceHandle engineHandle)376 void LogGpuResource(const RenderHandle& gpuHandle, const EngineResourceHandle engineHandle)
377 {
378     constexpr string_view names[] = { "buffer", "image", "sampler" };
379     const RenderHandleType handleType = RenderHandleUtil::GetHandleType(gpuHandle);
380     uint32_t idx = 0;
381     if (handleType == RenderHandleType::GPU_IMAGE) {
382         idx = 1u;
383     } else if (handleType == RenderHandleType::GPU_SAMPLER) {
384         idx = 2u;
385     }
386     PLUGIN_LOG_E("gpu %s > %" PRIx64 "=%" PRIx64 " generation: %u=%u", names[idx].data(), gpuHandle.id, engineHandle.id,
387         RenderHandleUtil::GetGenerationIndexPart(gpuHandle), RenderHandleUtil::GetGenerationIndexPart(engineHandle));
388 }
389 #endif
390 } // namespace
391 
GpuResourceManager(Device & device,const CreateInfo & createInfo)392 GpuResourceManager::GpuResourceManager(Device& device, const CreateInfo& createInfo)
393     : device_(device), gpuResourceMgrFlags_(createInfo.flags),
394       gpuBufferMgr_(make_unique<GpuResourceManagerTyped<GpuBuffer, GpuBufferDesc>>(device)),
395       gpuImageMgr_(make_unique<GpuResourceManagerTyped<GpuImage, GpuImageDesc>>(device)),
396       gpuSamplerMgr_(make_unique<GpuResourceManagerTyped<GpuSampler, GpuSamplerDesc>>(device))
397 {
398     gpuResourceCache_ = make_unique<GpuResourceCache>(*this);
399 
400     bufferStore_.mgr = gpuBufferMgr_.get();
401     imageStore_.mgr = gpuImageMgr_.get();
402     samplerStore_.mgr = gpuSamplerMgr_.get();
403 
404     const MemoryPropertyFlags deviceSharedMemoryPropertyFlags = device_.GetSharedMemoryPropertyFlags();
405     // remove create info flag if not really available
406     if (((gpuResourceMgrFlags_ & GPU_RESOURCE_MANAGER_OPTIMIZE_STAGING_MEMORY) == 0) ||
407         (deviceSharedMemoryPropertyFlags & NEEDED_DEVICE_MEMORY_PROPERTY_FLAGS_FOR_STAGING_MEM_OPT) !=
408             NEEDED_DEVICE_MEMORY_PROPERTY_FLAGS_FOR_STAGING_MEM_OPT) {
409         gpuResourceMgrFlags_ = gpuResourceMgrFlags_ & ~GPU_RESOURCE_MANAGER_OPTIMIZE_STAGING_MEMORY;
410     }
411 }
412 
~GpuResourceManager()413 GpuResourceManager::~GpuResourceManager()
414 {
415     // reset cache before logging
416     // cache logs it's own un-released resources
417     gpuResourceCache_.reset();
418 
419 #if (RENDER_VALIDATION_ENABLED == 1)
420     auto checkAndPrintValidation = [](const PerManagerStore& store, const string_view name) {
421         uint32_t aliveCounter = 0;
422         const auto clientLock = std::lock_guard(store.clientMutex);
423         for (const auto& ref : store.clientHandles) {
424             if (ref && (ref.GetRefCount() > 1)) {
425                 aliveCounter++;
426             }
427         }
428         if (aliveCounter > 0) {
429             PLUGIN_LOG_W(
430                 "RENDER_VALIDATION: Not all %s handle references released (count: %u)", name.data(), aliveCounter);
431         }
432     };
433     checkAndPrintValidation(bufferStore_, "GPU buffer");
434     checkAndPrintValidation(imageStore_, "GPU image");
435     checkAndPrintValidation(samplerStore_, "GPU sampler");
436 #endif
437 }
438 
Get(const RenderHandle & handle) const439 RenderHandleReference GpuResourceManager::Get(const RenderHandle& handle) const
440 {
441     if (RenderHandleUtil::IsValid(handle)) {
442         const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
443         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
444         if (handleType == RenderHandleType::GPU_BUFFER) {
445             auto& store = bufferStore_;
446             auto const clientLock = std::shared_lock(store.clientMutex);
447             if (arrayIndex < static_cast<uint32_t>(store.clientHandles.size())) {
448                 return store.clientHandles[arrayIndex];
449             }
450         } else if (handleType == RenderHandleType::GPU_IMAGE) {
451             auto& store = imageStore_;
452             auto const clientLock = std::shared_lock(store.clientMutex);
453             if (arrayIndex < static_cast<uint32_t>(store.clientHandles.size())) {
454                 return store.clientHandles[arrayIndex];
455             }
456         } else if (handleType == RenderHandleType::GPU_SAMPLER) {
457             auto& store = samplerStore_;
458             auto const clientLock = std::shared_lock(store.clientMutex);
459             if (arrayIndex < static_cast<uint32_t>(store.clientHandles.size())) {
460                 return store.clientHandles[arrayIndex];
461             }
462         }
463     }
464     return RenderHandleReference {};
465 }
466 
GetRawHandle(const RenderHandle & handle) const467 RenderHandle GpuResourceManager::GetRawHandle(const RenderHandle& handle) const
468 {
469     if (RenderHandleUtil::IsValid(handle)) {
470         const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
471         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
472         if (handleType == RenderHandleType::GPU_BUFFER) {
473             auto& store = bufferStore_;
474             auto const clientLock = std::shared_lock(store.clientMutex);
475             if (arrayIndex < static_cast<uint32_t>(store.clientHandles.size())) {
476                 return store.clientHandles[arrayIndex].GetHandle();
477             }
478         } else if (handleType == RenderHandleType::GPU_IMAGE) {
479             auto& store = imageStore_;
480             auto const clientLock = std::shared_lock(store.clientMutex);
481             if (arrayIndex < static_cast<uint32_t>(store.clientHandles.size())) {
482                 return store.clientHandles[arrayIndex].GetHandle();
483             }
484         } else if (handleType == RenderHandleType::GPU_SAMPLER) {
485             auto& store = samplerStore_;
486             auto const clientLock = std::shared_lock(store.clientMutex);
487             if (arrayIndex < static_cast<uint32_t>(store.clientHandles.size())) {
488                 return store.clientHandles[arrayIndex].GetHandle();
489             }
490         }
491     }
492     return RenderHandle {};
493 }
494 
GetStagingBufferDesc(const uint32_t byteSize)495 GpuBufferDesc GpuResourceManager::GetStagingBufferDesc(const uint32_t byteSize)
496 {
497     return {
498         BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_SRC_BIT,
499         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT |
500             MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
501         EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_SINGLE_SHOT_STAGING,
502         byteSize,
503     };
504 }
505 
506 // call to evaluate if there's already pending resources which we will replace
507 // store.clientMutex needs to be locked
GetPendingOptionalResourceIndex(const PerManagerStore & store,const RenderHandle & handle,const string_view name)508 uint32_t GpuResourceManager::GetPendingOptionalResourceIndex(
509     const PerManagerStore& store, const RenderHandle& handle, const string_view name)
510 {
511     uint32_t optionalResourceIndex = ~0u;
512     uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
513     const bool hasReplaceHandle = (arrayIndex < static_cast<uint32_t>(store.clientHandles.size()));
514     if ((!hasReplaceHandle) && (!name.empty())) {
515         if (auto const iter = store.nameToClientIndex.find(name); iter != store.nameToClientIndex.cend()) {
516             arrayIndex = RenderHandleUtil::GetIndexPart(iter->second);
517         }
518     }
519     if (arrayIndex < static_cast<uint32_t>(store.clientHandles.size())) {
520         if (const uint32_t pendingArrIndex = store.additionalData[arrayIndex].indexToPendingData;
521             pendingArrIndex != INVALID_PENDING_INDEX) {
522             PLUGIN_ASSERT(pendingArrIndex < store.pendingData.allocations.size());
523             if (pendingArrIndex < static_cast<uint32_t>(store.pendingData.allocations.size())) {
524                 const auto& allocOp = store.pendingData.allocations[pendingArrIndex];
525                 optionalResourceIndex = allocOp.optionalResourceIndex;
526             }
527         }
528     }
529     return optionalResourceIndex;
530 }
531 
532 // needs to be locked when called
CreateStagingBuffer(const GpuBufferDesc & desc)533 RenderHandleReference GpuResourceManager::CreateStagingBuffer(const GpuBufferDesc& desc)
534 {
535     PerManagerStore& store = bufferStore_;
536     return StoreAllocation(store, { ResourceDescriptor { desc }, {}, {}, RenderHandleType::GPU_BUFFER, ~0u, 0u })
537         .handle;
538 }
539 
540 // needs to be locked when called
CreateBuffer(const string_view name,const RenderHandle & replacedHandle,const GpuBufferDesc & desc)541 GpuResourceManager::StoreAllocationData GpuResourceManager::CreateBuffer(
542     const string_view name, const RenderHandle& replacedHandle, const GpuBufferDesc& desc)
543 {
544 #if (RENDER_VALIDATION_ENABLED == 1)
545     ValidateGpuBufferDesc(desc);
546 #endif
547     MemoryPropertyFlags additionalMemPropFlags = 0U;
548     if (device_.GetBackendType() == DeviceBackendType::VULKAN) {
549         additionalMemPropFlags = (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_MAP_OUTSIDE_RENDERER)
550                                      ? (MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
551                                      : 0U;
552     } else {
553         additionalMemPropFlags = (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_MAP_OUTSIDE_RENDERER)
554                                      ? (MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT |
555                                            MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
556                                      : 0U;
557     }
558     const GpuBufferDesc validatedDesc {
559         desc.usageFlags | defaultBufferUsageFlags_,
560         desc.memoryPropertyFlags | additionalMemPropFlags,
561         desc.engineCreationFlags,
562         Math::max(desc.byteSize, 1u),
563         desc.format,
564     };
565     PerManagerStore& store = bufferStore_;
566     if (validatedDesc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE) {
567         // replace immediate created if still pending (i.e. not usable on the GPU)
568         // memory pointers on client become invalid
569         const auto emplaceResourceIndex = static_cast<uint32_t>(store.pendingData.buffers.size());
570         const uint32_t optionalResourceIndex =
571             Math::min(emplaceResourceIndex, GetPendingOptionalResourceIndex(store, replacedHandle, name));
572 
573         if (unique_ptr<GpuBuffer> gpuBuffer = [this](const GpuBufferDesc validatedDesc) {
574                 // protect GPU memory allocations
575                 auto lock = std::lock_guard(allocationMutex_);
576                 return device_.CreateGpuBuffer(validatedDesc);
577             }(validatedDesc)) {
578             // safety checks
579             if ((optionalResourceIndex < emplaceResourceIndex) &&
580                 (optionalResourceIndex < store.pendingData.buffers.size())) {
581                 store.pendingData.buffers[optionalResourceIndex] = move(gpuBuffer);
582             } else {
583                 store.pendingData.buffers.push_back(move(gpuBuffer));
584             }
585         }
586 
587         StoreAllocationData sad = StoreAllocation(store, { ResourceDescriptor { validatedDesc }, name, replacedHandle,
588                                                              RenderHandleType::GPU_BUFFER, optionalResourceIndex, 0u });
589         // additional data is increased in StoreAllocation
590         // there are as many additional data elements as clientHandle elements
591         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(sad.handle.GetHandle());
592         PLUGIN_ASSERT(arrayIndex < store.additionalData.size());
593         if (GpuBuffer* buffer = store.pendingData.buffers[optionalResourceIndex].get(); buffer) {
594             store.additionalData[arrayIndex].resourcePtr = reinterpret_cast<uintptr_t>(reinterpret_cast<void*>(buffer));
595         }
596         return sad;
597     } else {
598         return StoreAllocation(store,
599             { ResourceDescriptor { validatedDesc }, name, replacedHandle, RenderHandleType::GPU_BUFFER, ~0u, 0u });
600     }
601 }
602 
GetOrCreate(const string_view name,const GpuBufferDesc & desc)603 RenderHandleReference GpuResourceManager::GetOrCreate(const string_view name, const GpuBufferDesc& desc)
604 {
605     RenderHandleReference handle;
606 
607     GpuBufferDesc validDesc = GetValidGpuBufferDesc(desc);
608     CheckAndEnableMemoryOptimizations(gpuResourceMgrFlags_, validDesc);
609     {
610         PerManagerStore& store = bufferStore_;
611         const auto lock = std::lock_guard(store.clientMutex);
612 
613         // check if present (not locked inside)
614         handle = GetHandleNoLock(store, name);
615         // create
616         if (!handle) {
617             if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE) {
618                 device_.Activate();
619             }
620 
621             handle = CreateBuffer(name, {}, validDesc).handle;
622 
623             if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE) {
624                 device_.Deactivate();
625             }
626         }
627     }
628     return handle;
629 }
630 
Create(const string_view name,const GpuBufferDesc & desc)631 RenderHandleReference GpuResourceManager::Create(const string_view name, const GpuBufferDesc& desc)
632 {
633     RenderHandleReference handle;
634 
635     GpuBufferDesc validDesc = GetValidGpuBufferDesc(desc);
636     CheckAndEnableMemoryOptimizations(gpuResourceMgrFlags_, validDesc);
637 
638     if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE) {
639         device_.Activate();
640     }
641     PerManagerStore& store = bufferStore_;
642     {
643         const auto lock = std::lock_guard(store.clientMutex);
644 
645         handle = CreateBuffer(name, {}, validDesc).handle;
646     }
647     if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE) {
648         device_.Deactivate();
649     }
650     return handle;
651 }
652 
Create(const RenderHandleReference & replacedHandle,const GpuBufferDesc & desc)653 RenderHandleReference GpuResourceManager::Create(const RenderHandleReference& replacedHandle, const GpuBufferDesc& desc)
654 {
655     RenderHandleReference handle;
656 
657     const RenderHandle rawHandle = replacedHandle.GetHandle();
658 #if (RENDER_VALIDATION_ENABLED == 1)
659     const bool valid = RenderHandleUtil::IsValid(rawHandle);
660     const RenderHandleType type = RenderHandleUtil::GetHandleType(rawHandle);
661     if (valid && (type != RenderHandleType::GPU_BUFFER)) {
662         PLUGIN_LOG_E("RENDER_VALIDATION: trying to replace a non GPU buffer handle (type: %u) with GpuBufferDesc",
663             (uint32_t)type);
664     }
665 #endif
666     GpuBufferDesc validDesc = GetValidGpuBufferDesc(desc);
667     CheckAndEnableMemoryOptimizations(gpuResourceMgrFlags_, validDesc);
668 
669     if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE) {
670         device_.Activate();
671     }
672     {
673         PerManagerStore& store = bufferStore_;
674         const auto lock = std::lock_guard(store.clientMutex);
675 
676         handle = CreateBuffer({}, rawHandle, validDesc).handle;
677     }
678     if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE) {
679         device_.Deactivate();
680     }
681     return handle;
682 }
683 
Create(const string_view name,const GpuBufferDesc & desc,const array_view<const uint8_t> data)684 RenderHandleReference GpuResourceManager::Create(
685     const string_view name, const GpuBufferDesc& desc, const array_view<const uint8_t> data)
686 {
687     RenderHandleReference handle;
688 
689 #if (RENDER_VALIDATION_ENABLED == 1)
690     ValidateGpuBufferDesc(desc);
691 #endif
692 
693     GpuBufferDesc validDesc = GetValidGpuBufferDesc(desc);
694     CheckAndEnableMemoryOptimizations(gpuResourceMgrFlags_, validDesc);
695     const bool useStagingBuffer = (validDesc.memoryPropertyFlags & CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT) !=
696                                   CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
697 
698     auto& store = bufferStore_;
699     if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE) {
700         device_.Activate();
701     }
702     {
703         StoreAllocationData sad;
704         const auto lock = std::lock_guard(store.clientMutex);
705 
706         sad = CreateBuffer(name, {}, validDesc);
707         const uint32_t minByteSize = std::min(validDesc.byteSize, (uint32_t)data.size_bytes());
708 
709         auto const stagingLock = std::lock_guard(stagingMutex_);
710 
711         stagingOperations_.bufferCopies.push_back(BufferCopy { 0, 0, minByteSize });
712         const uint32_t beginIndex = (uint32_t)stagingOperations_.bufferCopies.size() - 1;
713         vector<uint8_t> copiedData(data.cbegin().ptr(), data.cbegin().ptr() + minByteSize);
714 
715         // add staging vector index handle to resource handle in pending allocations
716         PLUGIN_ASSERT(sad.allocationIndex < store.pendingData.allocations.size());
717         auto& allocRef = store.pendingData.allocations[sad.allocationIndex];
718         allocRef.optionalStagingVectorIndex = static_cast<uint32_t>(stagingOperations_.bufferToBuffer.size());
719         allocRef.optionalStagingCopyType = useStagingBuffer ? StagingCopyStruct::CopyType::BUFFER_TO_BUFFER
720                                                             : StagingCopyStruct::CopyType::CPU_TO_BUFFER;
721 
722         if (useStagingBuffer) {
723             const uint32_t stagingBufferByteOffset = stagingOperations_.stagingByteSize;
724             // offset to data copy
725             stagingOperations_.bufferCopies[beginIndex].srcOffset += stagingBufferByteOffset;
726             const uint32_t stagingBufferByteSize =
727                 useStagingBuffer ? static_cast<uint32_t>(copiedData.size_in_bytes()) : 0u;
728             stagingOperations_.stagingByteSize =
729                 Align(stagingOperations_.stagingByteSize + stagingBufferByteSize, BUFFER_ALIGNMENT);
730             stagingOperations_.bufferToBuffer.push_back(StagingCopyStruct {
731                 StagingCopyStruct::DataType::DATA_TYPE_VECTOR, {}, sad.handle, beginIndex, 1, move(copiedData), nullptr,
732                 Format::BASE_FORMAT_UNDEFINED, stagingBufferByteOffset, stagingBufferByteSize, false });
733         } else {
734             stagingOperations_.cpuToBuffer.push_back(
735                 StagingCopyStruct { StagingCopyStruct::DataType::DATA_TYPE_VECTOR, {}, sad.handle, beginIndex, 1,
736                     move(copiedData), nullptr, Format::BASE_FORMAT_UNDEFINED, 0U, 0U, false });
737         }
738         handle = move(sad.handle);
739     }
740     if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE) {
741         device_.Deactivate();
742     }
743     return handle;
744 }
745 
Create(const GpuBufferDesc & desc)746 RenderHandleReference GpuResourceManager::Create(const GpuBufferDesc& desc)
747 {
748     RenderHandleReference handle;
749     GpuBufferDesc validDesc = GetValidGpuBufferDesc(desc);
750     CheckAndEnableMemoryOptimizations(gpuResourceMgrFlags_, validDesc);
751     if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE) {
752         device_.Activate();
753     }
754     {
755         auto& store = bufferStore_;
756         const auto lock = std::lock_guard(store.clientMutex);
757 
758         handle = CreateBuffer({}, {}, validDesc).handle;
759     }
760     if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE) {
761         device_.Deactivate();
762     }
763     return handle;
764 }
765 
Create(const GpuBufferDesc & desc,const array_view<const uint8_t> data)766 RenderHandleReference GpuResourceManager::Create(const GpuBufferDesc& desc, const array_view<const uint8_t> data)
767 {
768     // this is a fwd-method, desc is validated inside the called method
769     return Create({}, desc, data);
770 }
771 
772 // needs to be locked when called
CreateImage(const string_view name,const RenderHandle & replacedHandle,const GpuImageDesc & desc)773 GpuResourceManager::StoreAllocationData GpuResourceManager::CreateImage(
774     const string_view name, const RenderHandle& replacedHandle, const GpuImageDesc& desc)
775 {
776 #if (RENDER_VALIDATION_ENABLED == 1)
777     ValidateGpuImageDesc(desc, name);
778 #endif
779 
780     PerManagerStore& store = imageStore_;
781     const StoreAllocationInfo info {
782         ResourceDescriptor { GpuImageDesc {
783             desc.imageType,
784             desc.imageViewType,
785             device_.GetFormatOrFallback(desc.format),
786             (desc.imageTiling > ImageTiling::CORE_IMAGE_TILING_LINEAR) ? ImageTiling::CORE_IMAGE_TILING_OPTIMAL
787                                                                        : desc.imageTiling,
788             (desc.usageFlags & GpuResourceDescFlagValidation::ALL_GPU_IMAGE_USAGE_FLAGS) | defaultImageUsageFlags_,
789             ((desc.memoryPropertyFlags != 0) ? desc.memoryPropertyFlags
790                                              : MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &
791                 GpuResourceDescFlagValidation::ALL_MEMORY_PROPERTY_FLAGS,
792             desc.createFlags & GpuResourceDescFlagValidation::ALL_IMAGE_CREATE_FLAGS,
793             desc.engineCreationFlags,
794             Math::min(MAX_IMAGE_EXTENT, Math::max(1u, desc.width)),
795             Math::min(MAX_IMAGE_EXTENT, Math::max(1u, desc.height)),
796             Math::min(MAX_IMAGE_EXTENT, Math::max(1u, desc.depth)),
797             Math::max(1u,
798                 Math::min(desc.mipCount,
799                     static_cast<uint32_t>(std::log2f(static_cast<float>(Math::max(desc.width, desc.height)))) + 1u)),
800             Math::max(1u, desc.layerCount),
801             Math::max(1u, desc.sampleCountFlags),
802             desc.componentMapping,
803         } },
804         name, replacedHandle, RenderHandleType::GPU_IMAGE, ~0u, 0u
805     };
806     if (info.descriptor.imageDescriptor.format == Format::BASE_FORMAT_UNDEFINED) {
807         PLUGIN_LOG_E("Undefined image BASE_FORMAT_UNDEFINED (input format %u)", static_cast<uint32_t>(desc.format));
808         return {};
809     }
810 
811     return StoreAllocation(store, info);
812 }
813 
Create(const RenderHandleReference & replacedHandle,const GpuImageDesc & desc)814 RenderHandleReference GpuResourceManager::Create(const RenderHandleReference& replacedHandle, const GpuImageDesc& desc)
815 {
816     const RenderHandle rawHandle = replacedHandle.GetHandle();
817 #if (RENDER_VALIDATION_ENABLED == 1)
818     const bool valid = RenderHandleUtil::IsValid(rawHandle);
819     const RenderHandleType type = RenderHandleUtil::GetHandleType(rawHandle);
820     if (valid && (type != RenderHandleType::GPU_IMAGE)) {
821         PLUGIN_LOG_E(
822             "RENDER_VALIDATION: trying to replace a non GPU image handle (type: %u) with GpuImageDesc", (uint32_t)type);
823     }
824 #endif
825     PerManagerStore& store = imageStore_;
826     const auto lock = std::lock_guard(store.clientMutex);
827 
828     return CreateImage({}, rawHandle, desc).handle;
829 }
830 
GetOrCreate(const string_view name,const GpuImageDesc & desc)831 RenderHandleReference GpuResourceManager::GetOrCreate(const string_view name, const GpuImageDesc& desc)
832 {
833     RenderHandleReference handle;
834     {
835         PerManagerStore& store = imageStore_;
836         const auto lock = std::lock_guard(store.clientMutex);
837         // check if present (not locked inside)
838         handle = GetHandleNoLock(store, name);
839         if (!handle) {
840             handle = CreateImage(name, {}, desc).handle;
841         }
842     }
843     return handle;
844 }
845 
Create(const string_view name,const GpuImageDesc & desc)846 RenderHandleReference GpuResourceManager::Create(const string_view name, const GpuImageDesc& desc)
847 {
848     PerManagerStore& store = imageStore_;
849     const auto lock = std::lock_guard(store.clientMutex);
850 
851     return CreateImage(name, {}, desc).handle;
852 }
853 
Create(const GpuImageDesc & desc)854 RenderHandleReference GpuResourceManager::Create(const GpuImageDesc& desc)
855 {
856     PerManagerStore& store = imageStore_;
857     const auto lock = std::lock_guard(store.clientMutex);
858 
859     return CreateImage({}, {}, desc).handle;
860 }
861 
RemapGpuImageHandle(const RenderHandle & clientHandle,const RenderHandle & clientHandleGpuResource)862 void GpuResourceManager::RemapGpuImageHandle(
863     const RenderHandle& clientHandle, const RenderHandle& clientHandleGpuResource)
864 {
865     bool validClientHandles = (RenderHandleUtil::GetHandleType(clientHandle) == RenderHandleType::GPU_IMAGE) ||
866                               (RenderHandleUtil::GetHandleType(clientHandleGpuResource) == RenderHandleType::GPU_IMAGE);
867     if (validClientHandles) {
868         PerManagerStore& store = imageStore_;
869         auto const lock = std::lock_guard(store.clientMutex);
870 
871         const uint32_t clientArrayIndex = RenderHandleUtil::GetIndexPart(clientHandle);
872         const uint32_t clientResourceArrayIndex = RenderHandleUtil::GetIndexPart(clientHandleGpuResource);
873         validClientHandles =
874             validClientHandles && ((clientArrayIndex < (uint32_t)store.clientHandles.size()) &&
875                                       (clientResourceArrayIndex < (uint32_t)store.clientHandles.size()));
876         if (validClientHandles) {
877             store.descriptions[clientArrayIndex] = store.descriptions[clientResourceArrayIndex];
878             store.pendingData.remaps.push_back(RemapDescription { clientHandle, clientHandleGpuResource });
879         }
880     }
881 
882     if (!validClientHandles) {
883         PLUGIN_LOG_E("invalid client handles given to RemapGpuImageHandle()");
884     }
885 }
886 
Create(const string_view name,const GpuImageDesc & desc,IImageContainer::Ptr image)887 RenderHandleReference GpuResourceManager::Create(
888     const string_view name, const GpuImageDesc& desc, IImageContainer::Ptr image)
889 {
890     StoreAllocationData sad;
891     if (image) {
892         PerManagerStore& store = imageStore_;
893         auto const lockImg = std::lock_guard(store.clientMutex);
894 
895         sad = CreateImage(name, {}, desc);
896         if (IsGpuImage(sad.handle)) {
897             auto const lockStag = std::lock_guard(stagingMutex_);
898 
899             const auto& copies = image->GetBufferImageCopies();
900             const bool scaleImage = GetScalingImageNeed(desc, copies);
901 
902             const uint32_t stagingBufferByteOffset = stagingOperations_.stagingByteSize;
903             Format format = Format::BASE_FORMAT_UNDEFINED;
904             if (scaleImage) { // needs to be locked
905                 UpdateStagingScaling(desc.format, copies, stagingOperations_.scalingImageData);
906                 format = desc.format;
907             }
908             for (const auto& copyRef : copies) {
909                 stagingOperations_.bufferImageCopies.push_back(
910                     ConvertCoreBufferImageCopy(copyRef, stagingBufferByteOffset));
911             }
912 
913             // add staging handle to resource handle in pending allocations
914             PLUGIN_ASSERT(sad.allocationIndex < store.pendingData.allocations.size());
915             auto& allocRef = store.pendingData.allocations[sad.allocationIndex];
916             allocRef.optionalStagingVectorIndex = static_cast<uint32_t>(stagingOperations_.bufferToImage.size());
917             allocRef.optionalStagingCopyType = StagingCopyStruct::CopyType::BUFFER_TO_IMAGE;
918 
919             const uint32_t stagingBufferByteSize = static_cast<uint32_t>(image->GetData().size_bytes());
920             stagingOperations_.stagingByteSize =
921                 Align(stagingOperations_.stagingByteSize + stagingBufferByteSize, BUFFER_ALIGNMENT);
922             const auto count = static_cast<uint32_t>(copies.size());
923             const uint32_t beginIndex = static_cast<uint32_t>(stagingOperations_.bufferImageCopies.size()) - count;
924             stagingOperations_.bufferToImage.push_back(
925                 StagingCopyStruct { StagingCopyStruct::DataType::DATA_TYPE_IMAGE_CONTAINER, {}, sad.handle, beginIndex,
926                     count, {}, move(image), format, stagingBufferByteOffset, stagingBufferByteSize, false });
927         }
928     } else {
929         PLUGIN_LOG_E("invalid image pointer to Create GPU image");
930     }
931     return sad.handle;
932 }
933 
Create(const string_view name,const GpuImageDesc & desc,const array_view<const uint8_t> data,const array_view<const BufferImageCopy> bufferImageCopies)934 RenderHandleReference GpuResourceManager::Create(const string_view name, const GpuImageDesc& desc,
935     const array_view<const uint8_t> data, const array_view<const BufferImageCopy> bufferImageCopies)
936 {
937     StoreAllocationData sad;
938     {
939         PerManagerStore& store = imageStore_;
940         auto const lockImg = std::lock_guard(store.clientMutex);
941 
942         sad = CreateImage(name, {}, desc);
943         if (IsGpuImage(sad.handle)) {
944             auto const lockStag = std::lock_guard(stagingMutex_);
945 
946             const uint32_t stagingBufferByteOffset = stagingOperations_.stagingByteSize;
947             Format format = Format::BASE_FORMAT_UNDEFINED;
948             if (GetScalingImageNeed(desc, bufferImageCopies)) { // needs to be locked
949                 UpdateStagingScaling(desc.format, bufferImageCopies, stagingOperations_.scalingImageData);
950                 format = desc.format;
951             }
952             for (const auto& copyRef : bufferImageCopies) {
953 #if (RENDER_VALIDATION_ENABLED == 1)
954                 ValidateGpuImageCopy(desc, copyRef, name);
955 #endif
956                 BufferImageCopy bic = copyRef;
957                 bic.bufferOffset += stagingBufferByteOffset; // add additional staging offset
958                 stagingOperations_.bufferImageCopies.push_back(bic);
959             }
960             // add staging vector index to resource alloc in pending allocations
961             PLUGIN_ASSERT(sad.allocationIndex < store.pendingData.allocations.size());
962             auto& allocRef = store.pendingData.allocations[sad.allocationIndex];
963             allocRef.optionalStagingVectorIndex = static_cast<uint32_t>(stagingOperations_.bufferToImage.size());
964             allocRef.optionalStagingCopyType = StagingCopyStruct::CopyType::BUFFER_TO_IMAGE;
965 
966             const auto stagingBufferByteSize = static_cast<uint32_t>(data.size_bytes());
967             stagingOperations_.stagingByteSize =
968                 Align(stagingOperations_.stagingByteSize + stagingBufferByteSize, BUFFER_ALIGNMENT);
969             const auto count = (uint32_t)bufferImageCopies.size();
970             const uint32_t beginIndex = (uint32_t)stagingOperations_.bufferImageCopies.size() - count;
971 
972             vector<uint8_t> copiedData(data.cbegin().ptr(), data.cend().ptr());
973             stagingOperations_.bufferToImage.push_back(
974                 StagingCopyStruct { StagingCopyStruct::DataType::DATA_TYPE_VECTOR, {}, sad.handle, beginIndex, count,
975                     move(copiedData), nullptr, format, stagingBufferByteOffset, stagingBufferByteSize, false });
976         }
977     }
978     return sad.handle;
979 }
980 
Create(const string_view name,const GpuImageDesc & desc,const array_view<const uint8_t> data)981 RenderHandleReference GpuResourceManager::Create(
982     const string_view name, const GpuImageDesc& desc, const array_view<const uint8_t> data)
983 {
984     BufferImageCopy bufferImageCopy {
985         0,
986         desc.width,
987         desc.height,
988         { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0, 0, desc.layerCount },
989         { 0, 0, 0 },
990         { desc.width, desc.height, desc.depth },
991     };
992 
993     const array_view<const BufferImageCopy> av(&bufferImageCopy, 1);
994     return Create(name, desc, data, av);
995 }
996 
CreateView(const string_view name,const GpuImageDesc & desc,const GpuImagePlatformData & gpuImagePlatformData)997 RenderHandleReference GpuResourceManager::CreateView(
998     const string_view name, const GpuImageDesc& desc, const GpuImagePlatformData& gpuImagePlatformData)
999 {
1000     device_.Activate();
1001     PerManagerStore& store = imageStore_;
1002     const auto lock = std::lock_guard(store.clientMutex);
1003 
1004     // replace immediate created if still pending (i.e. not usable on the GPU)
1005     const auto emplaceResourceIndex = static_cast<uint32_t>(store.pendingData.images.size());
1006     const uint32_t optionalResourceIndex =
1007         Math::min(emplaceResourceIndex, GetPendingOptionalResourceIndex(store, {}, name));
1008 
1009     if (unique_ptr<GpuImage> gpuImage = [this](const GpuImageDesc& desc,
1010         const GpuImagePlatformData& gpuImagePlatformData) {
1011             // protect GPU memory allocations
1012             auto lock = std::lock_guard(allocationMutex_);
1013             return device_.CreateGpuImageView(desc, gpuImagePlatformData);
1014         }(desc, gpuImagePlatformData)) {
1015         // safety checks
1016         if ((optionalResourceIndex < emplaceResourceIndex) &&
1017             (optionalResourceIndex < store.pendingData.images.size())) {
1018             store.pendingData.images[optionalResourceIndex] = move(gpuImage);
1019         } else {
1020             store.pendingData.images.push_back(move(gpuImage));
1021         }
1022     }
1023     device_.Deactivate();
1024 
1025     return StoreAllocation(
1026         store, { ResourceDescriptor { desc }, name, {}, RenderHandleType::GPU_IMAGE, optionalResourceIndex, 0u })
1027         .handle;
1028 }
1029 
CreateView(const string_view name,const GpuImageDesc & desc,const BackendSpecificImageDesc & backendSpecificData)1030 RenderHandleReference GpuResourceManager::CreateView(
1031     const string_view name, const GpuImageDesc& desc, const BackendSpecificImageDesc& backendSpecificData)
1032 {
1033     device_.Activate();
1034     PerManagerStore& store = imageStore_;
1035     const auto lock = std::lock_guard(store.clientMutex);
1036 
1037     // replace immediate created if still pending (i.e. not usable on the GPU)
1038     const auto emplaceResourceIndex = static_cast<uint32_t>(store.pendingData.images.size());
1039     const uint32_t optionalResourceIndex =
1040         Math::min(emplaceResourceIndex, GetPendingOptionalResourceIndex(store, {}, name));
1041 
1042     // additional handle flags provide information if platform conversion is needed
1043     uint32_t additionalHandleFlags = 0u;
1044 
1045     if (unique_ptr<GpuImage> gpuImage = [this](const GpuImageDesc& desc,
1046         const BackendSpecificImageDesc& backendSpecificData) {
1047             // protect GPU memory allocations
1048             auto lock = std::lock_guard(allocationMutex_);
1049             return device_.CreateGpuImageView(desc, backendSpecificData);
1050         }(desc, backendSpecificData)) {
1051         const auto additionalImageFlags = gpuImage->GetAdditionalFlags();
1052         additionalHandleFlags =
1053             (additionalImageFlags & GpuImage::AdditionalFlagBits::ADDITIONAL_PLATFORM_CONVERSION_BIT)
1054                 ? CORE_RESOURCE_HANDLE_PLATFORM_CONVERSION
1055                 : 0u;
1056         // safety checks
1057         if ((optionalResourceIndex < emplaceResourceIndex) &&
1058             (optionalResourceIndex < store.pendingData.images.size())) {
1059             store.pendingData.images[optionalResourceIndex] = move(gpuImage);
1060         } else {
1061             store.pendingData.images.push_back(move(gpuImage));
1062         }
1063     }
1064     device_.Deactivate();
1065 
1066     const auto& images = store.pendingData.images;
1067     const auto& finalDesc = (optionalResourceIndex < images.size() && images[optionalResourceIndex])
1068                                 ? images[optionalResourceIndex]->GetDesc()
1069                                 : desc;
1070     auto handle = StoreAllocation(store, { ResourceDescriptor { finalDesc }, name, {}, RenderHandleType::GPU_IMAGE,
1071                                              optionalResourceIndex, additionalHandleFlags })
1072                       .handle;
1073 #if (RENDER_VALIDATION_ENABLED == 1)
1074     if ((additionalHandleFlags & CORE_RESOURCE_HANDLE_PLATFORM_CONVERSION) &&
1075         !RenderHandleUtil::IsPlatformConversionResource(handle.GetHandle())) {
1076         PLUGIN_LOG_ONCE_W("core_validation_create_view_plat_conversion",
1077             "RENDER_VALIDATION: platform conversion needing resource cannot replace existing resource handle (name: "
1078             "%s)",
1079             name.data());
1080     }
1081 #endif
1082     return handle;
1083 }
1084 
Create(const GpuImageDesc & desc,const array_view<const uint8_t> data,const array_view<const BufferImageCopy> bufferImageCopies)1085 RenderHandleReference GpuResourceManager::Create(const GpuImageDesc& desc, const array_view<const uint8_t> data,
1086     const array_view<const BufferImageCopy> bufferImageCopies)
1087 {
1088     return Create({}, desc, data, bufferImageCopies);
1089 }
1090 
Create(const GpuImageDesc & desc,const array_view<const uint8_t> data)1091 RenderHandleReference GpuResourceManager::Create(const GpuImageDesc& desc, const array_view<const uint8_t> data)
1092 {
1093     return Create({}, desc, data);
1094 }
1095 
Create(const GpuImageDesc & desc,IImageContainer::Ptr image)1096 RenderHandleReference GpuResourceManager::Create(const GpuImageDesc& desc, IImageContainer::Ptr image)
1097 {
1098     return Create({}, desc, move(image));
1099 }
1100 
GetOrCreate(const string_view name,const GpuSamplerDesc & desc)1101 RenderHandleReference GpuResourceManager::GetOrCreate(const string_view name, const GpuSamplerDesc& desc)
1102 {
1103     RenderHandleReference handle;
1104     {
1105         PerManagerStore& store = samplerStore_;
1106         const auto lock = std::lock_guard(store.clientMutex);
1107         // check if present (not locked inside)
1108         handle = GetHandleNoLock(store, name);
1109         if (!handle) {
1110             handle = StoreAllocation(
1111                 store, { ResourceDescriptor { desc }, name, {}, RenderHandleType::GPU_SAMPLER, ~0u, 0u })
1112                          .handle;
1113         }
1114     }
1115     return handle;
1116 }
1117 
Create(const string_view name,const GpuSamplerDesc & desc)1118 RenderHandleReference GpuResourceManager::Create(const string_view name, const GpuSamplerDesc& desc)
1119 {
1120     PerManagerStore& store = samplerStore_;
1121     const auto lock = std::lock_guard(store.clientMutex);
1122 
1123     return StoreAllocation(store, { ResourceDescriptor { desc }, name, {}, RenderHandleType::GPU_SAMPLER, ~0u, 0u })
1124         .handle;
1125 }
1126 
Create(const RenderHandleReference & replacedHandle,const GpuSamplerDesc & desc)1127 RenderHandleReference GpuResourceManager::Create(
1128     const RenderHandleReference& replacedHandle, const GpuSamplerDesc& desc)
1129 {
1130     const RenderHandle rawHandle = replacedHandle.GetHandle();
1131 #if (RENDER_VALIDATION_ENABLED == 1)
1132     const bool valid = RenderHandleUtil::IsValid(rawHandle);
1133     const RenderHandleType type = RenderHandleUtil::GetHandleType(rawHandle);
1134     if (valid && (type != RenderHandleType::GPU_SAMPLER)) {
1135         PLUGIN_LOG_E("RENDER_VALIDATION: trying to replace a non GPU sampler handle (type: %u) with GpuSamplerDesc",
1136             (uint32_t)type);
1137     }
1138 #endif
1139     PerManagerStore& store = samplerStore_;
1140     const auto lock = std::lock_guard(store.clientMutex);
1141 
1142     return StoreAllocation(
1143         store, { ResourceDescriptor { desc }, {}, rawHandle, RenderHandleType::GPU_SAMPLER, ~0u, 0u })
1144         .handle;
1145 }
1146 
Create(const GpuSamplerDesc & desc)1147 RenderHandleReference GpuResourceManager::Create(const GpuSamplerDesc& desc)
1148 {
1149     return Create("", desc);
1150 }
1151 
CreateAccelerationStructure(const BASE_NS::string_view name,const RenderHandle & replacedHandle,const GpuAccelerationStructureDesc & desc)1152 GpuResourceManager::StoreAllocationData GpuResourceManager::CreateAccelerationStructure(
1153     const BASE_NS::string_view name, const RenderHandle& replacedHandle, const GpuAccelerationStructureDesc& desc)
1154 {
1155     PerManagerStore& store = bufferStore_;
1156 #if (RENDER_VALIDATION_ENABLED == 1)
1157     ValidateGpuAccelerationStructureDesc(desc);
1158 #endif
1159     GpuAccelerationStructureDesc validatedDesc = desc;
1160     validatedDesc.bufferDesc.usageFlags |= defaultBufferUsageFlags_;
1161     validatedDesc.bufferDesc.byteSize = Math::max(validatedDesc.bufferDesc.byteSize, 1u),
1162     validatedDesc.bufferDesc.usageFlags |= CORE_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT;
1163 
1164     constexpr auto additionalBufferFlags = CORE_RESOURCE_HANDLE_ACCELERATION_STRUCTURE;
1165     return StoreAllocation(store, { ResourceDescriptor { validatedDesc }, name, replacedHandle,
1166                                       RenderHandleType::GPU_BUFFER, ~0u, additionalBufferFlags });
1167 }
1168 
Create(const GpuAccelerationStructureDesc & desc)1169 RenderHandleReference GpuResourceManager::Create(const GpuAccelerationStructureDesc& desc)
1170 {
1171     PerManagerStore& store = bufferStore_;
1172     const auto lock = std::lock_guard(store.clientMutex);
1173 
1174     return CreateAccelerationStructure("", {}, desc).handle;
1175 }
1176 
Create(const string_view name,const GpuAccelerationStructureDesc & desc)1177 RenderHandleReference GpuResourceManager::Create(const string_view name, const GpuAccelerationStructureDesc& desc)
1178 {
1179     PerManagerStore& store = bufferStore_;
1180     const auto lock = std::lock_guard(store.clientMutex);
1181 
1182     return CreateAccelerationStructure(name, {}, desc).handle;
1183 }
1184 
Create(const RenderHandleReference & replacedHandle,const GpuAccelerationStructureDesc & desc)1185 RenderHandleReference GpuResourceManager::Create(
1186     const RenderHandleReference& replacedHandle, const GpuAccelerationStructureDesc& desc)
1187 {
1188     const RenderHandle rawHandle = replacedHandle.GetHandle();
1189 #if (RENDER_VALIDATION_ENABLED == 1)
1190     const bool valid = RenderHandleUtil::IsValid(rawHandle);
1191     const RenderHandleType type = RenderHandleUtil::GetHandleType(rawHandle);
1192     if (valid &&
1193         ((type != RenderHandleType::GPU_BUFFER) || (!RenderHandleUtil::IsGpuAccelerationStructure(rawHandle)))) {
1194         PLUGIN_LOG_E("RENDER_VALIDATION: trying to replace a non GPU acceleration structure handle (type: %u) with "
1195                      "GpuAccelerationStructureDesc",
1196             (uint32_t)type);
1197     }
1198 #endif
1199     PerManagerStore& store = bufferStore_;
1200     const auto lock = std::lock_guard(store.clientMutex);
1201 
1202     return CreateAccelerationStructure("", rawHandle, desc).handle;
1203 }
1204 
CreateSwapchainImage(const RenderHandleReference & replacedHandle,const BASE_NS::string_view name,const GpuImageDesc & desc)1205 RenderHandleReference GpuResourceManager::CreateSwapchainImage(
1206     const RenderHandleReference& replacedHandle, const BASE_NS::string_view name, const GpuImageDesc& desc)
1207 {
1208 #if (RENDER_VALIDATION_ENABLED == 1)
1209     ValidateGpuImageDesc(desc, "");
1210 #endif
1211 
1212     PerManagerStore& store = imageStore_;
1213     const auto lock = std::lock_guard(store.clientMutex);
1214 
1215     const uint32_t addFlags = RenderHandleInfoFlagBits::CORE_RESOURCE_HANDLE_SWAPCHAIN_RESOURCE;
1216     // NOTE: no mips for swapchains
1217     // TODO: NOTE: allocation type is undefined
1218     const StoreAllocationInfo info {
1219         ResourceDescriptor { GpuImageDesc {
1220             desc.imageType,
1221             desc.imageViewType,
1222             device_.GetFormatOrFallback(desc.format),
1223             (desc.imageTiling > ImageTiling::CORE_IMAGE_TILING_LINEAR) ? ImageTiling::CORE_IMAGE_TILING_OPTIMAL
1224                                                                        : desc.imageTiling,
1225             (desc.usageFlags & GpuResourceDescFlagValidation::ALL_GPU_IMAGE_USAGE_FLAGS) | defaultImageUsageFlags_,
1226             ((desc.memoryPropertyFlags != 0) ? desc.memoryPropertyFlags
1227                                              : MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &
1228                 GpuResourceDescFlagValidation::ALL_MEMORY_PROPERTY_FLAGS,
1229             desc.createFlags & GpuResourceDescFlagValidation::ALL_IMAGE_CREATE_FLAGS,
1230             desc.engineCreationFlags,
1231             Math::min(MAX_IMAGE_EXTENT, Math::max(1u, desc.width)),
1232             Math::min(MAX_IMAGE_EXTENT, Math::max(1u, desc.height)),
1233             Math::min(MAX_IMAGE_EXTENT, Math::max(1u, desc.depth)),
1234             1u, // hard-coded mip count
1235             Math::max(1u, desc.layerCount),
1236             Math::max(1u, desc.sampleCountFlags),
1237             desc.componentMapping,
1238         } },
1239         name, replacedHandle.GetHandle(), RenderHandleType::GPU_IMAGE, ~0u, addFlags, AllocType::UNDEFINED
1240     };
1241     if (info.descriptor.imageDescriptor.format == Format::BASE_FORMAT_UNDEFINED) {
1242         PLUGIN_LOG_E("Undefined image BASE_FORMAT_UNDEFINED (input format %u)", static_cast<uint32_t>(desc.format));
1243         return {};
1244     }
1245 
1246     return StoreAllocation(store, info).handle;
1247 }
1248 
CreateShallowHandle(const GpuImageDesc & desc)1249 RenderHandleReference GpuResourceManager::CreateShallowHandle(const GpuImageDesc& desc)
1250 {
1251     PerManagerStore& store = imageStore_;
1252     const auto lock = std::lock_guard(store.clientMutex);
1253 
1254 #if (RENDER_VALIDATION_ENABLED == 1)
1255     ValidateGpuImageDesc(desc, "");
1256 #endif
1257 
1258     const uint32_t addFlags = RenderHandleInfoFlagBits::CORE_RESOURCE_HANDLE_SHALLOW_RESOURCE;
1259     const StoreAllocationInfo info {
1260         ResourceDescriptor { GpuImageDesc {
1261             desc.imageType,
1262             desc.imageViewType,
1263             device_.GetFormatOrFallback(desc.format),
1264             (desc.imageTiling > ImageTiling::CORE_IMAGE_TILING_LINEAR) ? ImageTiling::CORE_IMAGE_TILING_OPTIMAL
1265                                                                        : desc.imageTiling,
1266             (desc.usageFlags & GpuResourceDescFlagValidation::ALL_GPU_IMAGE_USAGE_FLAGS) | defaultImageUsageFlags_,
1267             ((desc.memoryPropertyFlags != 0) ? desc.memoryPropertyFlags
1268                                              : MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &
1269                 GpuResourceDescFlagValidation::ALL_MEMORY_PROPERTY_FLAGS,
1270             desc.createFlags & GpuResourceDescFlagValidation::ALL_IMAGE_CREATE_FLAGS,
1271             desc.engineCreationFlags,
1272             Math::min(MAX_IMAGE_EXTENT, Math::max(1u, desc.width)),
1273             Math::min(MAX_IMAGE_EXTENT, Math::max(1u, desc.height)),
1274             Math::min(MAX_IMAGE_EXTENT, Math::max(1u, desc.depth)),
1275             Math::max(1u,
1276                 Math::min(desc.mipCount,
1277                     static_cast<uint32_t>(std::log2f(static_cast<float>(Math::max(desc.width, desc.height)))) + 1u)),
1278             Math::max(1u, desc.layerCount),
1279             Math::max(1u, desc.sampleCountFlags),
1280             desc.componentMapping,
1281         } },
1282         "", {}, RenderHandleType::GPU_IMAGE, ~0u, addFlags, AllocType::UNDEFINED
1283     };
1284     if (info.descriptor.imageDescriptor.format == Format::BASE_FORMAT_UNDEFINED) {
1285         PLUGIN_LOG_E("Undefined image BASE_FORMAT_UNDEFINED (input format %u)", static_cast<uint32_t>(desc.format));
1286         return {};
1287     }
1288 
1289     return StoreAllocation(store, info).handle;
1290 }
1291 
1292 // has staging lock and possible gpu buffer lock inside
RemoveStagingOperations(const OperationDescription & destroyAlloc)1293 void GpuResourceManager::RemoveStagingOperations(const OperationDescription& destroyAlloc)
1294 {
1295     // remove possible stagings
1296     const RenderHandleType handleType = RenderHandleUtil::GetHandleType(destroyAlloc.handle);
1297     if (((handleType == RenderHandleType::GPU_BUFFER) || (handleType == RenderHandleType::GPU_IMAGE)) &&
1298         (destroyAlloc.optionalStagingCopyType != StagingCopyStruct::CopyType::UNDEFINED)) {
1299         auto const lockStaging = std::lock_guard(stagingMutex_);
1300 
1301         auto invalidateStagingCopy = [](const OperationDescription& alloc, vector<StagingCopyStruct>& vecRef) {
1302             PLUGIN_ASSERT(alloc.optionalStagingVectorIndex < vecRef.size());
1303             vecRef[alloc.optionalStagingVectorIndex].srcHandle = {};
1304             vecRef[alloc.optionalStagingVectorIndex].dstHandle = {};
1305             vecRef[alloc.optionalStagingVectorIndex].invalidOperation = true;
1306         };
1307 
1308         if (destroyAlloc.optionalStagingCopyType == StagingCopyStruct::CopyType::BUFFER_TO_BUFFER) {
1309             invalidateStagingCopy(destroyAlloc, stagingOperations_.bufferToBuffer);
1310         } else if (destroyAlloc.optionalStagingCopyType == StagingCopyStruct::CopyType::BUFFER_TO_IMAGE) {
1311             invalidateStagingCopy(destroyAlloc, stagingOperations_.bufferToImage);
1312         } else if (destroyAlloc.optionalStagingCopyType == StagingCopyStruct::CopyType::IMAGE_TO_BUFFER) {
1313             invalidateStagingCopy(destroyAlloc, stagingOperations_.imageToBuffer);
1314         } else if (destroyAlloc.optionalStagingCopyType == StagingCopyStruct::CopyType::IMAGE_TO_IMAGE) {
1315             invalidateStagingCopy(destroyAlloc, stagingOperations_.imageToImage);
1316         } else if (destroyAlloc.optionalStagingCopyType == StagingCopyStruct::CopyType::CPU_TO_BUFFER) {
1317             invalidateStagingCopy(destroyAlloc, stagingOperations_.cpuToBuffer);
1318         } else {
1319             PLUGIN_ASSERT(false);
1320         }
1321     }
1322 
1323     // NOTE: we do not clean-up/invalidate copy operations stagingOperations_.cpuToBuffer ATM
1324     // it is user's responsibility do not use handle that you've destroyed
1325 }
1326 
1327 // needs to be locked from outside
1328 // staging cannot be locked when called
Destroy(PerManagerStore & store,const RenderHandle & handle)1329 void GpuResourceManager::Destroy(PerManagerStore& store, const RenderHandle& handle)
1330 {
1331 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
1332     PLUGIN_LOG_E("gpu resource deallocation %" PRIx64, handle.id);
1333 #endif
1334 
1335     const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1336     if (arrayIndex >= store.clientHandles.size()) {
1337         return;
1338     }
1339     if (!(store.clientHandles[arrayIndex])) {
1340         return; // early out if re-destroying the same handle
1341     }
1342 #if (RENDER_VALIDATION_ENABLED == 1)
1343     const uint32_t currGeneration =
1344         RenderHandleUtil::GetGenerationIndexPart(store.clientHandles[arrayIndex].GetHandle());
1345     const uint32_t destroyHandleGeneration = RenderHandleUtil::GetGenerationIndexPart(handle);
1346     if (currGeneration != destroyHandleGeneration) {
1347         PLUGIN_LOG_W("RENDER_VALIDATION: destroy handle is not the current generation (destroy:%u != current:%u)",
1348             currGeneration, destroyHandleGeneration);
1349     }
1350 #endif
1351 
1352     if (const uint32_t hasNameId = RenderHandleUtil::GetHasNamePart(handle); hasNameId != 0U) {
1353         // remove name if present
1354         if (auto const pos = std::find_if(store.nameToClientIndex.begin(), store.nameToClientIndex.end(),
1355             [arrayIndex](auto const& nameToHandle) { return nameToHandle.second == arrayIndex; });
1356             pos != store.nameToClientIndex.end()) {
1357             store.nameToClientIndex.erase(pos);
1358         }
1359     }
1360 
1361     // we do not set default values to GpuXDesc (we leave the old data, it won't be used)
1362     // old code: store.descriptions[arrayIndex] = {};
1363     // invalidate handle, noticed when trying to re-destroy (early-out in the beginning of the if)
1364     store.clientHandles[arrayIndex] = {};
1365 
1366     // if the handle is already found and it's an alloc we do not want to allocate and then deallocate
1367     if (const uint32_t pendingArrIndex = store.additionalData[arrayIndex].indexToPendingData;
1368         pendingArrIndex != INVALID_PENDING_INDEX) {
1369         // NOTE: check valid assert here (if called before resources are created)
1370         if (pendingArrIndex < store.pendingData.allocations.size()) {
1371             auto& ref = store.pendingData.allocations[pendingArrIndex];
1372             if (ref.allocType == AllocType::ALLOC) {
1373                 ref.allocType = AllocType::REMOVED;
1374                 RemoveStagingOperations(ref);
1375             }
1376         }
1377     } else {
1378         PLUGIN_ASSERT(store.additionalData[arrayIndex].indexToPendingData == INVALID_PENDING_INDEX);
1379         store.additionalData[arrayIndex] = { 0, static_cast<uint32_t>(store.pendingData.allocations.size()) };
1380         store.pendingData.allocations.emplace_back(
1381             handle, ResourceDescriptor { GpuBufferDesc {} }, AllocType::DEALLOC, static_cast<uint32_t>(~0u));
1382         // there cannot be staging operations because pendingData was not found
1383         // all other operations to destroyable handle are user's responsibility
1384     }
1385 }
1386 
1387 // needs to be locked when called
DestroyImmediate(PerManagerStore & store,const RenderHandle & handle)1388 void GpuResourceManager::DestroyImmediate(PerManagerStore& store, const RenderHandle& handle)
1389 {
1390     if (RenderHandleUtil::IsValid(handle)) { // found, Destroy immediate
1391         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1392         if (arrayIndex < (uint32_t)store.gpuHandles.size()) {
1393             store.mgr->DestroyImmediate(arrayIndex);
1394             store.clientHandles[arrayIndex] = {};
1395             store.additionalData[arrayIndex] = {};
1396             store.gpuHandles[arrayIndex] = InvalidateWithGeneration(store.gpuHandles[arrayIndex]);
1397         }
1398     }
1399 }
1400 
Destroy(const RenderHandle & handle)1401 void GpuResourceManager::Destroy(const RenderHandle& handle)
1402 {
1403     if (RenderHandleUtil::IsValid(handle)) {
1404         const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
1405         if (handleType == RenderHandleType::GPU_BUFFER) {
1406             const auto clientLock = std::lock_guard(bufferStore_.clientMutex);
1407             Destroy(bufferStore_, handle);
1408         } else if (handleType == RenderHandleType::GPU_IMAGE) {
1409             const auto clientLock = std::lock_guard(imageStore_.clientMutex);
1410             Destroy(imageStore_, handle);
1411         } else if (handleType == RenderHandleType::GPU_SAMPLER) {
1412             const auto clientLock = std::lock_guard(samplerStore_.clientMutex);
1413             Destroy(samplerStore_, handle);
1414         } else {
1415             PLUGIN_LOG_I("invalid gpu resource handle : %" PRIu64, handle.id);
1416         }
1417     }
1418 }
1419 
1420 // needs to be locked outside
GetHandleNoLock(const PerManagerStore & store,const string_view name)1421 RenderHandleReference GpuResourceManager::GetHandleNoLock(const PerManagerStore& store, const string_view name)
1422 {
1423     if (name.empty()) { // early out before lock
1424         return RenderHandleReference {};
1425     }
1426 
1427     if (auto const pos = store.nameToClientIndex.find(name); pos != store.nameToClientIndex.end()) {
1428         PLUGIN_ASSERT(pos->second < static_cast<uint32_t>(store.clientHandles.size()));
1429         return store.clientHandles[pos->second];
1430     }
1431     // NOTE: This is used in some places to check if the GPU resource is found
1432     // therefore no error prints here
1433     return RenderHandleReference {};
1434 }
1435 
GetHandle(const PerManagerStore & store,const string_view name)1436 RenderHandleReference GpuResourceManager::GetHandle(const PerManagerStore& store, const string_view name)
1437 {
1438     if (name.empty()) { // early out before lock
1439         return RenderHandleReference {};
1440     }
1441 
1442     auto const clientLock = std::shared_lock(store.clientMutex);
1443     if (auto const pos = store.nameToClientIndex.find(name); pos != store.nameToClientIndex.end()) {
1444         PLUGIN_ASSERT(pos->second < static_cast<uint32_t>(store.clientHandles.size()));
1445         return store.clientHandles[pos->second];
1446     }
1447     // NOTE: This is used in some places to check if the GPU resource is found
1448     // therefore no error prints here
1449     return RenderHandleReference {};
1450 }
1451 
GetRawHandle(const PerManagerStore & store,const string_view name)1452 RenderHandle GpuResourceManager::GetRawHandle(const PerManagerStore& store, const string_view name)
1453 {
1454     if (name.empty()) { // early out before lock
1455         return RenderHandle {};
1456     }
1457 
1458     auto const clientLock = std::shared_lock(store.clientMutex);
1459     if (auto const pos = store.nameToClientIndex.find(name); pos != store.nameToClientIndex.end()) {
1460         PLUGIN_ASSERT(pos->second < static_cast<uint32_t>(store.clientHandles.size()));
1461         return store.clientHandles[pos->second].GetHandle();
1462     }
1463     // NOTE: This is used in some places to check if the GPU resource is found
1464     // therefore no error prints here
1465     return RenderHandle {};
1466 }
1467 
HasNamedResource(const PerManagerStore & store,const string_view name)1468 bool GpuResourceManager::HasNamedResource(const PerManagerStore& store, const string_view name)
1469 {
1470     if (name.empty()) { // early out before lock
1471         return false;
1472     }
1473 
1474     auto const clientLock = std::shared_lock(store.clientMutex);
1475     if (auto const pos = store.nameToClientIndex.find(name); pos != store.nameToClientIndex.end()) {
1476         PLUGIN_ASSERT(pos->second < static_cast<uint32_t>(store.clientHandles.size()));
1477         return true;
1478     }
1479     return false;
1480 }
1481 
GetBufferHandle(const string_view name) const1482 RenderHandleReference GpuResourceManager::GetBufferHandle(const string_view name) const
1483 {
1484     return GetHandle(bufferStore_, name);
1485 }
1486 
GetImageHandle(const string_view name) const1487 RenderHandleReference GpuResourceManager::GetImageHandle(const string_view name) const
1488 {
1489     return GetHandle(imageStore_, name);
1490 }
1491 
GetSamplerHandle(const string_view name) const1492 RenderHandleReference GpuResourceManager::GetSamplerHandle(const string_view name) const
1493 {
1494     return GetHandle(samplerStore_, name);
1495 }
1496 
HasBuffer(const BASE_NS::string_view name) const1497 bool GpuResourceManager::HasBuffer(const BASE_NS::string_view name) const
1498 {
1499     return HasNamedResource(bufferStore_, name);
1500 }
1501 
HasImage(const BASE_NS::string_view name) const1502 bool GpuResourceManager::HasImage(const BASE_NS::string_view name) const
1503 {
1504     return HasNamedResource(imageStore_, name);
1505 }
1506 
HasSampler(const BASE_NS::string_view name) const1507 bool GpuResourceManager::HasSampler(const BASE_NS::string_view name) const
1508 {
1509     return HasNamedResource(samplerStore_, name);
1510 }
1511 
GetBufferRawHandle(const string_view name) const1512 RenderHandle GpuResourceManager::GetBufferRawHandle(const string_view name) const
1513 {
1514     return GetRawHandle(bufferStore_, name);
1515 }
1516 
GetImageRawHandle(const string_view name) const1517 RenderHandle GpuResourceManager::GetImageRawHandle(const string_view name) const
1518 {
1519     return GetRawHandle(imageStore_, name);
1520 }
1521 
GetSamplerRawHandle(const string_view name) const1522 RenderHandle GpuResourceManager::GetSamplerRawHandle(const string_view name) const
1523 {
1524     return GetRawHandle(samplerStore_, name);
1525 }
1526 
GetBufferDescriptor(const RenderHandle & handle) const1527 GpuBufferDesc GpuResourceManager::GetBufferDescriptor(const RenderHandle& handle) const
1528 {
1529     if (!IsGpuBuffer(handle)) {
1530         return GpuBufferDesc {};
1531     }
1532     {
1533         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1534         const PerManagerStore& store = bufferStore_;
1535         auto const clientLock = std::shared_lock(store.clientMutex);
1536         if (arrayIndex < (uint32_t)store.descriptions.size()) {
1537             return store.descriptions[arrayIndex].combinedBufDescriptor.bufferDesc;
1538         }
1539     }
1540     return GpuBufferDesc {};
1541 }
1542 
GetBufferDescriptor(const RenderHandleReference & handle) const1543 GpuBufferDesc GpuResourceManager::GetBufferDescriptor(const RenderHandleReference& handle) const
1544 {
1545     return GetBufferDescriptor(handle.GetHandle());
1546 }
1547 
GetImageDescriptor(const RenderHandle & handle) const1548 GpuImageDesc GpuResourceManager::GetImageDescriptor(const RenderHandle& handle) const
1549 {
1550     if (!IsGpuImage(handle)) {
1551         return GpuImageDesc {};
1552     }
1553     {
1554         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1555         const PerManagerStore& store = imageStore_;
1556         auto const clientLock = std::shared_lock(store.clientMutex);
1557         if (arrayIndex < (uint32_t)store.descriptions.size()) {
1558             return store.descriptions[arrayIndex].imageDescriptor;
1559         }
1560     }
1561     return GpuImageDesc {};
1562 }
1563 
GetImageDescriptor(const RenderHandleReference & handle) const1564 GpuImageDesc GpuResourceManager::GetImageDescriptor(const RenderHandleReference& handle) const
1565 {
1566     return GetImageDescriptor(handle.GetHandle());
1567 }
1568 
GetSamplerDescriptor(const RenderHandle & handle) const1569 GpuSamplerDesc GpuResourceManager::GetSamplerDescriptor(const RenderHandle& handle) const
1570 {
1571     if (!IsGpuSampler(handle)) {
1572         return GpuSamplerDesc {};
1573     }
1574     {
1575         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1576         const PerManagerStore& store = samplerStore_;
1577         auto const clientLock = std::shared_lock(store.clientMutex);
1578         if (arrayIndex < (uint32_t)store.descriptions.size()) {
1579             return store.descriptions[arrayIndex].samplerDescriptor;
1580         }
1581     }
1582     return GpuSamplerDesc {};
1583 }
1584 
GetSamplerDescriptor(const RenderHandleReference & handle) const1585 GpuSamplerDesc GpuResourceManager::GetSamplerDescriptor(const RenderHandleReference& handle) const
1586 {
1587     return GetSamplerDescriptor(handle.GetHandle());
1588 }
1589 
GetAccelerationStructureDescriptor(const RenderHandle & handle) const1590 GpuAccelerationStructureDesc GpuResourceManager::GetAccelerationStructureDescriptor(const RenderHandle& handle) const
1591 {
1592     if (!IsGpuAccelerationStructure(handle)) {
1593         return GpuAccelerationStructureDesc {};
1594     }
1595     {
1596         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1597         const PerManagerStore& store = bufferStore_;
1598         auto const clientLock = std::shared_lock(store.clientMutex);
1599         if (arrayIndex < (uint32_t)store.descriptions.size()) {
1600             return store.descriptions[arrayIndex].combinedBufDescriptor;
1601         }
1602     }
1603     return GpuAccelerationStructureDesc {};
1604 }
1605 
GetAccelerationStructureDescriptor(const RenderHandleReference & handle) const1606 GpuAccelerationStructureDesc GpuResourceManager::GetAccelerationStructureDescriptor(
1607     const RenderHandleReference& handle) const
1608 {
1609     return GetAccelerationStructureDescriptor(handle.GetHandle());
1610 }
1611 
GetName(const RenderHandle & handle) const1612 string GpuResourceManager::GetName(const RenderHandle& handle) const
1613 {
1614     if (RenderHandleUtil::GetHasNamePart(handle) != 0) {
1615         const PerManagerStore* store = nullptr;
1616         const RenderHandleType handleType = RenderHandleUtil::GetHandleType(handle);
1617         if (handleType == RenderHandleType::GPU_BUFFER) {
1618             store = &bufferStore_;
1619         } else if (handleType == RenderHandleType::GPU_IMAGE) {
1620             store = &imageStore_;
1621         } else if (handleType == RenderHandleType::GPU_SAMPLER) {
1622             store = &samplerStore_;
1623         }
1624         if (store) {
1625             const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
1626             for (const auto& iter : store->nameToClientIndex) {
1627                 if (arrayIndex == iter.second) {
1628                     return iter.first;
1629                 }
1630             }
1631         }
1632     }
1633     return {};
1634 }
1635 
GetName(const RenderHandleReference & handle) const1636 string GpuResourceManager::GetName(const RenderHandleReference& handle) const
1637 {
1638     return GetName(handle.GetHandle());
1639 }
1640 
GetHandles(const PerManagerStore & store)1641 vector<RenderHandleReference> GpuResourceManager::GetHandles(const PerManagerStore& store)
1642 {
1643     const auto lock = std::shared_lock(store.clientMutex);
1644 
1645     vector<RenderHandleReference> res;
1646     res.reserve(store.clientHandles.size());
1647     for (const auto& ref : store.clientHandles) {
1648         if (ref) {
1649             res.push_back(ref);
1650         }
1651     }
1652     return res;
1653 }
1654 
GetRawHandles(const PerManagerStore & store)1655 vector<RenderHandle> GpuResourceManager::GetRawHandles(const PerManagerStore& store)
1656 {
1657     const auto lock = std::shared_lock(store.clientMutex);
1658 
1659     vector<RenderHandle> res;
1660     res.reserve(store.clientHandles.size());
1661     for (const auto& ref : store.clientHandles) {
1662         if (ref) {
1663             res.push_back(ref.GetHandle());
1664         }
1665     }
1666     return res;
1667 }
1668 
GetBufferHandles() const1669 vector<RenderHandleReference> GpuResourceManager::GetBufferHandles() const
1670 {
1671     return GetHandles(bufferStore_);
1672 }
1673 
GetImageHandles() const1674 vector<RenderHandleReference> GpuResourceManager::GetImageHandles() const
1675 {
1676     return GetHandles(imageStore_);
1677 }
1678 
GetSamplerHandles() const1679 vector<RenderHandleReference> GpuResourceManager::GetSamplerHandles() const
1680 {
1681     return GetHandles(samplerStore_);
1682 }
1683 
GetRawBufferHandles() const1684 vector<RenderHandle> GpuResourceManager::GetRawBufferHandles() const
1685 {
1686     return GetRawHandles(bufferStore_);
1687 }
1688 
GetRawImageHandles() const1689 vector<RenderHandle> GpuResourceManager::GetRawImageHandles() const
1690 {
1691     return GetRawHandles(imageStore_);
1692 }
1693 
GetRawSamplerHandles() const1694 vector<RenderHandle> GpuResourceManager::GetRawSamplerHandles() const
1695 {
1696     return GetRawHandles(samplerStore_);
1697 }
1698 
SetDefaultGpuBufferCreationFlags(const BufferUsageFlags usageFlags)1699 void GpuResourceManager::SetDefaultGpuBufferCreationFlags(const BufferUsageFlags usageFlags)
1700 {
1701     defaultBufferUsageFlags_ = usageFlags;
1702 }
1703 
SetDefaultGpuImageCreationFlags(const ImageUsageFlags usageFlags)1704 void GpuResourceManager::SetDefaultGpuImageCreationFlags(const ImageUsageFlags usageFlags)
1705 {
1706     defaultImageUsageFlags_ = usageFlags;
1707 }
1708 
CreateGpuResource(const OperationDescription & op,const uint32_t arrayIndex,const RenderHandleType resourceType,const uintptr_t preCreatedResVec)1709 void GpuResourceManager::CreateGpuResource(const OperationDescription& op, const uint32_t arrayIndex,
1710     const RenderHandleType resourceType, const uintptr_t preCreatedResVec)
1711 {
1712     if (resourceType == RenderHandleType::GPU_BUFFER) {
1713         PLUGIN_ASSERT(preCreatedResVec);
1714         if (RenderHandleUtil::IsGpuAccelerationStructure(op.handle)) {
1715             PLUGIN_ASSERT(op.optionalResourceIndex == ~0u);
1716             gpuBufferMgr_->Create<GpuAccelerationStructureDesc>(arrayIndex,
1717                 op.descriptor.combinedBufDescriptor.bufferDesc, {}, true, op.descriptor.combinedBufDescriptor);
1718         } else {
1719             if (op.optionalResourceIndex != ~0u) {
1720                 BufferVector& res = *(reinterpret_cast<BufferVector*>(reinterpret_cast<void*>(preCreatedResVec)));
1721                 gpuBufferMgr_->Create<GpuAccelerationStructureDesc>(arrayIndex,
1722                     op.descriptor.combinedBufDescriptor.bufferDesc, move(res[op.optionalResourceIndex]), false,
1723                     op.descriptor.combinedBufDescriptor);
1724             } else {
1725                 gpuBufferMgr_->Create<GpuAccelerationStructureDesc>(arrayIndex,
1726                     op.descriptor.combinedBufDescriptor.bufferDesc, {}, false, op.descriptor.combinedBufDescriptor);
1727             }
1728         }
1729     } else if (resourceType == RenderHandleType::GPU_IMAGE) {
1730         PLUGIN_ASSERT(preCreatedResVec);
1731         if (op.optionalResourceIndex != ~0u) {
1732             ImageVector& images = *(reinterpret_cast<ImageVector*>(reinterpret_cast<void*>(preCreatedResVec)));
1733             gpuImageMgr_->Create<uint32_t>(
1734                 arrayIndex, op.descriptor.imageDescriptor, move(images[op.optionalResourceIndex]), false, 0);
1735         } else {
1736             gpuImageMgr_->Create<uint32_t>(arrayIndex, op.descriptor.imageDescriptor, {}, false, 0);
1737         }
1738     } else if (resourceType == RenderHandleType::GPU_SAMPLER) {
1739         PLUGIN_ASSERT(preCreatedResVec == 0);
1740         PLUGIN_ASSERT(op.optionalResourceIndex == ~0u);
1741         gpuSamplerMgr_->Create<uint32_t>(arrayIndex, op.descriptor.samplerDescriptor, {}, false, 0);
1742     }
1743 }
1744 
1745 // needs to be locked when called, and call only for valid gpu handles
DestroyGpuResource(const OperationDescription & operation,const uint32_t arrayIndex,const RenderHandleType resourceType,PerManagerStore & store)1746 void GpuResourceManager::DestroyGpuResource(const OperationDescription& operation, const uint32_t arrayIndex,
1747     const RenderHandleType resourceType, PerManagerStore& store)
1748 {
1749     store.mgr->Destroy(arrayIndex);
1750     PLUGIN_ASSERT(arrayIndex < static_cast<uint32_t>(store.gpuHandles.size()));
1751     store.clientHandles[arrayIndex] = {};
1752     store.additionalData[arrayIndex] = {};
1753     store.gpuHandles[arrayIndex] = InvalidateWithGeneration(store.gpuHandles[arrayIndex]);
1754 }
1755 
HandlePendingRemappings(const vector<RemapDescription> & pendingShallowRemappings,vector<EngineResourceHandle> & gpuHandles)1756 void GpuResourceManager::HandlePendingRemappings(
1757     const vector<RemapDescription>& pendingShallowRemappings, vector<EngineResourceHandle>& gpuHandles)
1758 {
1759     for (auto const& shallowRemap : pendingShallowRemappings) {
1760         // find the gpu handle where the client handle wants to point to
1761         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(shallowRemap.resourceClientHandle);
1762         if (arrayIndex < gpuHandles.size()) {
1763             const EngineResourceHandle gpuHandle = gpuHandles[arrayIndex];
1764 
1765             const bool validGpuHandle = RenderHandleUtil::IsValid(gpuHandle);
1766             const uint32_t remapArrayIndex = RenderHandleUtil::GetIndexPart(shallowRemap.shallowClientHandle);
1767             if (validGpuHandle && (remapArrayIndex < (uint32_t)gpuHandles.size())) {
1768                 gpuHandles[remapArrayIndex] = gpuHandle;
1769             } else {
1770                 PLUGIN_LOG_E("gpuimage handle remapping failed; client handle not found");
1771             }
1772         }
1773     }
1774 }
1775 
HandlePendingAllocationsImpl(const bool isFrameEnd)1776 void GpuResourceManager::HandlePendingAllocationsImpl(const bool isFrameEnd)
1777 {
1778     HandleStorePendingAllocations(isFrameEnd, bufferStore_);
1779     HandleStorePendingAllocations(isFrameEnd, imageStore_);
1780     HandleStorePendingAllocations(isFrameEnd, samplerStore_);
1781 
1782 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
1783     ProcessDebugTags();
1784 #endif
1785 }
1786 
HandleRemoved(uint32_t arrayIndex,const OperationDescription & operation)1787 void GpuResourceManager::PerManagerStore::HandleRemoved(uint32_t arrayIndex, const OperationDescription& operation)
1788 {
1789     PLUGIN_ASSERT(arrayIndex < static_cast<uint32_t>(clientHandles.size()));
1790     availableHandleIds.push_back(operation.handle.id);
1791     clientHandles[arrayIndex] = {};
1792     additionalData[arrayIndex] = {};
1793 }
1794 
HandleAlloc(uint32_t arrayIndex,const OperationDescription & operation)1795 void GpuResourceManager::PerManagerStore::HandleAlloc(uint32_t arrayIndex, const OperationDescription& operation)
1796 {
1797     PLUGIN_ASSERT(arrayIndex < static_cast<uint32_t>(gpuHandles.size()));
1798     // NOTE: this is essential to get correct, this maps render pass etc. hashing
1799     // if the generation counter is old there might vulkan image layout issues etc.
1800     const EngineResourceHandle gpuHandle = UnpackNewHandle(gpuHandles[arrayIndex], handleType, arrayIndex);
1801 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
1802     LogGpuResource(operation.handle, gpuHandle);
1803 #endif
1804     gpuHandles[arrayIndex] = gpuHandle;
1805 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
1806     debugTagAllocations.push_back(operation.handle);
1807 #endif
1808 }
1809 
HandleDealloc(uint32_t arrayIndex,const OperationDescription & operation,const bool isFrameEnd)1810 bool GpuResourceManager::PerManagerStore::HandleDealloc(
1811     uint32_t arrayIndex, const OperationDescription& operation, const bool isFrameEnd)
1812 {
1813     if (RenderHandleUtil::IsDeferredDestroy(operation.handle) && (!isFrameEnd)) {
1814         // push deferred destroys back to wait for the end of the frame destruction
1815         pendingData.allocations.push_back(operation);
1816         return false;
1817     }
1818     availableHandleIds.push_back(operation.handle.id);
1819     if (RenderHandleUtil::IsShallowResource(operation.handle)) {
1820         PLUGIN_ASSERT(arrayIndex < static_cast<uint32_t>(clientHandles.size()));
1821         PLUGIN_ASSERT(arrayIndex < static_cast<uint32_t>(gpuHandles.size()));
1822         // shallow handles do not destroy the actual GPU resource
1823         // there's always the real handle which handles the destruction based on references
1824         clientHandles[arrayIndex] = {};
1825         additionalData[arrayIndex] = {};
1826         // shallow handle invalidated with default (the generation is not correct anyhow)
1827         gpuHandles[arrayIndex] = {};
1828         return false;
1829     }
1830     return true;
1831 }
1832 
HandleStorePendingAllocations(const bool isFrameEnd,PerManagerStore & store)1833 void GpuResourceManager::HandleStorePendingAllocations(const bool isFrameEnd, PerManagerStore& store)
1834 {
1835     store.clientMutex.lock();
1836     // protect GPU memory allocations
1837     allocationMutex_.lock();
1838     // check for handle destructions
1839     for (const auto& handleRef : store.clientHandles) {
1840         if (handleRef && (handleRef.GetRefCount() <= 1)) {
1841             Destroy(store, handleRef.GetHandle());
1842         }
1843     }
1844 
1845     const auto pendingAllocations = move(store.pendingData.allocations);
1846     auto pendingBuffers = move(store.pendingData.buffers);
1847     auto pendingImages = move(store.pendingData.images);
1848     const auto pendingRemaps = move(store.pendingData.remaps);
1849     uintptr_t pendingRes = 0; // ptr to pending resource vector
1850     if (store.handleType == RenderHandleType::GPU_BUFFER) {
1851         pendingRes = reinterpret_cast<uintptr_t>(static_cast<void*>(&pendingBuffers));
1852     } else if (store.handleType == RenderHandleType::GPU_IMAGE) {
1853         pendingRes = reinterpret_cast<uintptr_t>(static_cast<void*>(&pendingImages));
1854     }
1855 
1856     // increase the gpu handle vector sizes if needed
1857     if (store.clientHandles.size() > store.gpuHandles.size()) {
1858         store.gpuHandles.resize(store.clientHandles.size());
1859         store.mgr->Resize(store.clientHandles.size());
1860     }
1861 
1862     for (auto const& allocation : pendingAllocations) {
1863         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(allocation.handle);
1864         // NOTE: needs to be cleared here
1865         store.additionalData[arrayIndex].indexToPendingData = ~0u;
1866         // NOTE: immediately created resource replacing should be prevented (ptr might be present still)
1867         if (allocation.allocType == AllocType::REMOVED) {
1868             store.HandleRemoved(arrayIndex, allocation);
1869             continue;
1870         }
1871 
1872         // first allocation, then dealloc, with dealloc we need to check for deferred destruction
1873         if (allocation.allocType == AllocType::ALLOC) {
1874             store.HandleAlloc(arrayIndex, allocation);
1875             CreateGpuResource(allocation, arrayIndex, store.handleType, pendingRes);
1876         } else if (allocation.allocType == AllocType::DEALLOC) {
1877             if (store.HandleDealloc(arrayIndex, allocation, isFrameEnd)) {
1878                 DestroyGpuResource(allocation, arrayIndex, store.handleType, store);
1879             }
1880         }
1881         // there might be undefined type, e.g. for shallow handles
1882 
1883         // render graph frame state reset for trackable and not auto reset frame states
1884         // with alloc there might be a replace which needs this as well as with dealloc
1885         if (RenderHandleUtil::IsDynamicResource(allocation.handle) &&
1886             (!RenderHandleUtil::IsResetOnFrameBorders(allocation.handle))) {
1887             PLUGIN_ASSERT((store.handleType == RenderHandleType::GPU_BUFFER) ||
1888                           (store.handleType == RenderHandleType::GPU_IMAGE));
1889             clientHandleStateDestroy_.resources.push_back(allocation.handle);
1890         }
1891     }
1892 
1893     // inside mutex (calls device)
1894     store.mgr->HandlePendingDeallocations();
1895 
1896     allocationMutex_.unlock();
1897     // although the pendingData was moved and doesn't need locks anymore, other parts of the store are modified
1898     // as well so we need to hold the lock until here.
1899     store.clientMutex.unlock();
1900 
1901     if (store.handleType == RenderHandleType::GPU_IMAGE) {
1902         // no lock needed for gpuHandles access
1903         HandlePendingRemappings(pendingRemaps, store.gpuHandles);
1904     }
1905 }
1906 
HandlePendingAllocations()1907 void GpuResourceManager::HandlePendingAllocations()
1908 {
1909     HandlePendingAllocationsImpl(false);
1910 }
1911 
EndFrame()1912 void GpuResourceManager::EndFrame()
1913 {
1914     DestroyFrameStaging();
1915     HandlePendingAllocationsImpl(true);
1916 }
1917 
RenderBackendImmediateRemapGpuImageHandle(const RenderHandle & clientHandle,const RenderHandle & clientHandleGpuResource)1918 void GpuResourceManager::RenderBackendImmediateRemapGpuImageHandle(
1919     const RenderHandle& clientHandle, const RenderHandle& clientHandleGpuResource)
1920 {
1921     const uint32_t clientArrayIndex = RenderHandleUtil::GetIndexPart(clientHandle);
1922     const uint32_t clientResourceArrayIndex = RenderHandleUtil::GetIndexPart(clientHandleGpuResource);
1923     const bool areGpuImages = (RenderHandleUtil::GetHandleType(clientHandle) == RenderHandleType::GPU_IMAGE) &&
1924                               (RenderHandleUtil::GetHandleType(clientHandleGpuResource) == RenderHandleType::GPU_IMAGE);
1925     if (areGpuImages) {
1926         PerManagerStore& store = imageStore_;
1927         auto const clientLock = std::lock_guard(store.clientMutex);
1928 
1929         if ((clientArrayIndex < store.gpuHandles.size()) && (clientResourceArrayIndex < store.gpuHandles.size())) {
1930             // NOTE: old owned gpu resource should be destroyed
1931             PLUGIN_ASSERT(RenderHandleUtil::IsValid(store.gpuHandles[clientResourceArrayIndex]));
1932 
1933             store.gpuHandles[clientArrayIndex] = store.gpuHandles[clientResourceArrayIndex];
1934             store.descriptions[clientArrayIndex] = store.descriptions[clientResourceArrayIndex];
1935         } else {
1936             PLUGIN_LOG_E("invalid backend gpu image remapping indices");
1937         }
1938     } else {
1939         PLUGIN_LOG_E("invalid backend gpu image remapping handles");
1940     }
1941 }
1942 
LockFrameStagingData()1943 void GpuResourceManager::LockFrameStagingData()
1944 {
1945     {
1946         std::lock_guard lock(stagingMutex_);
1947         perFrameStagingData_ = move(stagingOperations_);
1948         stagingOperations_ = {};
1949     }
1950 
1951     // create frame staging buffers and set handles for staging
1952     {
1953         std::lock_guard lock(bufferStore_.clientMutex);
1954 
1955         // handle render time reserved gpu buffer
1956         {
1957             auto& rtrgb = renderTimeReservedGpuBuffer_;
1958             if (rtrgb.neededByteSize > 0U) {
1959                 if ((!rtrgb.handle) || (rtrgb.storedByteSize < rtrgb.neededByteSize)) {
1960                     // over-allocate
1961                     rtrgb.storedByteSize = rtrgb.neededByteSize + Align(rtrgb.neededByteSize / 8U, BUFFER_ALIGNMENT);
1962                     // re-create
1963                     rtrgb.handle = CreateBuffer({}, rtrgb.baseHandle, GetMapBufferDesc(rtrgb.storedByteSize)).handle;
1964                     rtrgb.baseHandle = rtrgb.handle.GetHandle();
1965                 }
1966                 rtrgb.neededByteSize = 0U;
1967                 rtrgb.executeValues.swap(rtrgb.values);
1968                 rtrgb.mappedData = nullptr;
1969             } else {
1970                 // clear always the resource if no usage
1971                 rtrgb = {};
1972             }
1973         }
1974 
1975         if (perFrameStagingData_.stagingByteSize > 0U) {
1976             perFrameStagingBuffers_.push_back(
1977                 CreateStagingBuffer(GetStagingBufferDesc(perFrameStagingData_.stagingByteSize)));
1978             perFrameStagingData_.stagingBuffer = perFrameStagingBuffers_.back().GetHandle();
1979         }
1980 
1981         perFrameStagingBuffers_.reserve(
1982             perFrameStagingData_.bufferToBuffer.size() + perFrameStagingData_.bufferToImage.size());
1983         for (auto& ref : perFrameStagingData_.bufferToBuffer) {
1984             if ((!ref.invalidOperation) && (ref.stagingBufferByteSize > 0)) {
1985                 ref.srcHandle = perFrameStagingBuffers_.back();
1986             }
1987         }
1988         for (auto& ref : perFrameStagingData_.bufferToImage) {
1989             if ((!ref.invalidOperation) && (ref.stagingBufferByteSize > 0)) {
1990                 ref.srcHandle = perFrameStagingBuffers_.back();
1991             }
1992         }
1993     }
1994     {
1995         auto const clientLock = std::lock_guard(imageStore_.clientMutex);
1996         // create image scaling targets and set handles
1997         perFrameStagingScalingImages_.resize(perFrameStagingData_.scalingImageData.scalingImages.size());
1998         for (size_t idx = 0; idx < perFrameStagingData_.scalingImageData.scalingImages.size(); ++idx) {
1999             auto& scalingImageRef = perFrameStagingData_.scalingImageData.scalingImages[idx];
2000             perFrameStagingScalingImages_[idx] = CreateImage({}, {},
2001                 GetStagingScalingImageDesc(scalingImageRef.format, scalingImageRef.maxWidth, scalingImageRef.maxHeight))
2002                                                      .handle;
2003             scalingImageRef.handle = perFrameStagingScalingImages_[idx];
2004         }
2005     }
2006 }
2007 
DestroyFrameStaging()2008 void GpuResourceManager::DestroyFrameStaging()
2009 {
2010     // explicit destruction of staging resources
2011     {
2012         PerManagerStore& store = bufferStore_;
2013         auto const clientLock = std::lock_guard(store.clientMutex);
2014         for (const auto& handleRef : perFrameStagingBuffers_) {
2015             Destroy(store, handleRef.GetHandle());
2016         }
2017         perFrameStagingBuffers_.clear();
2018     }
2019     {
2020         PerManagerStore& store = imageStore_;
2021         auto const clientLock = std::lock_guard(store.clientMutex);
2022         for (const auto& handleRef : perFrameStagingScalingImages_) {
2023             Destroy(store, handleRef.GetHandle());
2024         }
2025         perFrameStagingScalingImages_.clear();
2026     }
2027 }
2028 
HasStagingData() const2029 bool GpuResourceManager::HasStagingData() const
2030 {
2031     if (perFrameStagingData_.bufferToBuffer.empty() && perFrameStagingData_.bufferToImage.empty() &&
2032         perFrameStagingData_.imageToBuffer.empty() && perFrameStagingData_.imageToImage.empty() &&
2033         perFrameStagingData_.cpuToBuffer.empty() && perFrameStagingData_.bufferCopies.empty() &&
2034         perFrameStagingData_.bufferImageCopies.empty() && perFrameStagingData_.imageCopies.empty()) {
2035         return false;
2036     } else {
2037         return true;
2038     }
2039 }
2040 
ConsumeStagingData()2041 StagingConsumeStruct GpuResourceManager::ConsumeStagingData()
2042 {
2043     StagingConsumeStruct staging = move(perFrameStagingData_);
2044     return staging;
2045 }
2046 
ConsumeStateDestroyData()2047 GpuResourceManager::StateDestroyConsumeStruct GpuResourceManager::ConsumeStateDestroyData()
2048 {
2049     StateDestroyConsumeStruct srcs = move(clientHandleStateDestroy_);
2050     return srcs;
2051 }
2052 
MapBuffer(const RenderHandle & handle) const2053 void* GpuResourceManager::MapBuffer(const RenderHandle& handle) const
2054 {
2055     if (GpuBuffer* buffer = GetBuffer(handle); buffer) {
2056         return buffer->Map();
2057     }
2058     return nullptr;
2059 }
2060 
MapBuffer(const RenderHandleReference & handle) const2061 void* GpuResourceManager::MapBuffer(const RenderHandleReference& handle) const
2062 {
2063     return MapBuffer(handle.GetHandle());
2064 }
2065 
MapBufferMemory(const RenderHandle & handle) const2066 void* GpuResourceManager::MapBufferMemory(const RenderHandle& handle) const
2067 {
2068     const bool isOutsideRendererMappable = RenderHandleUtil::IsMappableOutsideRenderer(handle);
2069     void* data = nullptr;
2070     if (isOutsideRendererMappable) {
2071         const bool isCreatedImmediate = RenderHandleUtil::IsImmediatelyCreated(handle);
2072         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
2073         const auto clientLock = std::lock_guard(bufferStore_.clientMutex);
2074         if (isCreatedImmediate && (arrayIndex < static_cast<uint32_t>(bufferStore_.clientHandles.size()))) {
2075 #if (RENDER_VALIDATION_ENABLED == 1)
2076             if (!bufferStore_.additionalData[arrayIndex].resourcePtr) {
2077                 PLUGIN_LOG_E("RENDER_VALIDATION: invalid pointer with mappable GPU buffer MapBufferMemory");
2078             }
2079 #endif
2080             if (bufferStore_.additionalData[arrayIndex].resourcePtr) {
2081                 data = (reinterpret_cast<GpuBuffer*>(bufferStore_.additionalData[arrayIndex].resourcePtr))->MapMemory();
2082             }
2083         }
2084     } else if (GpuBuffer* buffer = GetBuffer(handle); buffer) {
2085         data = buffer->MapMemory();
2086     }
2087     return data;
2088 }
2089 
MapBufferMemory(const RenderHandleReference & handle) const2090 void* GpuResourceManager::MapBufferMemory(const RenderHandleReference& handle) const
2091 {
2092     return MapBufferMemory(handle.GetHandle());
2093 }
2094 
UnmapBuffer(const RenderHandle & handle) const2095 void GpuResourceManager::UnmapBuffer(const RenderHandle& handle) const
2096 {
2097     const bool isOutsideRendererMappable = RenderHandleUtil::IsMappableOutsideRenderer(handle);
2098     if (isOutsideRendererMappable) {
2099         const bool isCreatedImmediate = RenderHandleUtil::IsImmediatelyCreated(handle);
2100         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
2101         const auto clientLock = std::lock_guard(bufferStore_.clientMutex);
2102         if (isCreatedImmediate && (arrayIndex < static_cast<uint32_t>(bufferStore_.clientHandles.size()))) {
2103 #if (RENDER_VALIDATION_ENABLED == 1)
2104             if (!bufferStore_.additionalData[arrayIndex].resourcePtr) {
2105                 PLUGIN_LOG_E("RENDER_VALIDATION: invalid pointer with mappable GPU buffer UnmapBuffer");
2106             }
2107 #endif
2108             if (bufferStore_.additionalData[arrayIndex].resourcePtr) {
2109                 (reinterpret_cast<GpuBuffer*>(bufferStore_.additionalData[arrayIndex].resourcePtr))->Unmap();
2110             }
2111         }
2112     } else if (const GpuBuffer* buffer = GetBuffer(handle); buffer) {
2113         buffer->Unmap();
2114     }
2115 }
2116 
UnmapBuffer(const RenderHandleReference & handle) const2117 void GpuResourceManager::UnmapBuffer(const RenderHandleReference& handle) const
2118 {
2119     return UnmapBuffer(handle.GetHandle());
2120 }
2121 
2122 // must be locked when called
CommitPendingData(PerManagerStore & store)2123 GpuResourceManager::PendingData GpuResourceManager::CommitPendingData(PerManagerStore& store)
2124 {
2125     return { move(store.pendingData.allocations), move(store.pendingData.buffers), move(store.pendingData.images),
2126         move(store.pendingData.remaps) };
2127 }
2128 
DebugPrintValidCounts()2129 void GpuResourceManager::DebugPrintValidCounts()
2130 {
2131 #if (RENDER_VALIDATION_ENABLED == 1)
2132     PLUGIN_LOG_D("GPU buffer count: %u", static_cast<uint32_t>(gpuBufferMgr_->GetValidResourceCount()));
2133     PLUGIN_LOG_D("GPU image count: %u", static_cast<uint32_t>(gpuImageMgr_->GetValidResourceCount()));
2134     PLUGIN_LOG_D("GPU sampler count: %u", static_cast<uint32_t>(gpuSamplerMgr_->GetValidResourceCount()));
2135 #endif
2136 }
2137 
WaitForIdleAndDestroyGpuResources()2138 void GpuResourceManager::WaitForIdleAndDestroyGpuResources()
2139 {
2140     PLUGIN_LOG_D("WFIADGR thread id: %" PRIu64, (uint64_t)std::hash<std::thread::id> {}(std::this_thread::get_id()));
2141     device_.Activate();
2142     device_.WaitForIdle();
2143 
2144     // 1. immediate Destroy all the handles that are to be destroyed
2145     // 2. throw away everything else that's pending
2146     auto DestroyPendingData = [this](PerManagerStore& store) {
2147         const auto lock = std::lock_guard(store.clientMutex);
2148         const auto allocLock = std::lock_guard(allocationMutex_);
2149 
2150         auto pd = CommitPendingData(store);
2151         if (store.clientHandles.size() > store.gpuHandles.size()) {
2152             store.gpuHandles.resize(store.clientHandles.size());
2153             store.mgr->Resize(store.clientHandles.size());
2154         }
2155 
2156 #if (RENDER_VALIDATION_ENABLED == 1)
2157         uint32_t dc = 0;
2158 #endif
2159         for (const auto& ref : pd.allocations) {
2160             if (ref.allocType == AllocType::DEALLOC) {
2161                 store.availableHandleIds.push_back(ref.handle.id);
2162                 DestroyImmediate(store, ref.handle);
2163                 // render graph frame state reset for trackable and not auto reset frame states
2164                 if (RenderHandleUtil::IsDynamicResource(ref.handle) &&
2165                     (!RenderHandleUtil::IsResetOnFrameBorders(ref.handle))) {
2166                     PLUGIN_ASSERT((store.handleType == RenderHandleType::GPU_BUFFER) ||
2167                                   (store.handleType == RenderHandleType::GPU_IMAGE));
2168                     clientHandleStateDestroy_.resources.push_back(ref.handle);
2169                 }
2170 #if (RENDER_VALIDATION_ENABLED == 1)
2171                 dc++;
2172             } else if (ref.allocType == AllocType::REMOVED) {
2173                 dc++;
2174 #endif
2175             }
2176         }
2177 #if (RENDER_VALIDATION_ENABLED == 1)
2178         PLUGIN_LOG_D("WFIADGR: d: %u r (type:%u)", dc, uint32_t(store.handleType));
2179         PLUGIN_LOG_D("WFIADGR: pa cl: %u (t:%u)", (uint32_t)pd.allocations.size() - dc, uint32_t(store.handleType));
2180 #endif
2181 
2182         // inside mutex (calls device)
2183         store.mgr->HandlePendingDeallocationsImmediate();
2184     };
2185 
2186     DestroyPendingData(bufferStore_);
2187     DestroyPendingData(imageStore_);
2188     DestroyPendingData(samplerStore_);
2189 
2190     // make sure that all staging resources are forcefully destroyed
2191     LockFrameStagingData();
2192     ConsumeStagingData(); // consume cpu data
2193     DestroyFrameStaging();
2194 
2195     {
2196         // additional possible staging buffer clean-up
2197         auto& store = bufferStore_;
2198         const auto lock = std::lock_guard(store.clientMutex);
2199         const auto allocLock = std::lock_guard(allocationMutex_);
2200         store.mgr->HandlePendingDeallocationsImmediate();
2201     }
2202 
2203     DebugPrintValidCounts();
2204 
2205     device_.Deactivate();
2206 }
2207 
GetGpuHandle(const PerManagerStore & store,const RenderHandle & clientHandle)2208 EngineResourceHandle GpuResourceManager::GetGpuHandle(const PerManagerStore& store, const RenderHandle& clientHandle)
2209 {
2210     const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(clientHandle);
2211     if (arrayIndex < (uint32_t)store.gpuHandles.size()) {
2212         // NOTE: separate GPU handle generation counter might not
2213         // be exact when using shallow handles (i.e. counter is zero always after shallow handles)
2214 #if (RENDER_VALIDATION_ENABLED == 1)
2215         if (!RenderHandleUtil::IsValid(store.gpuHandles[arrayIndex])) {
2216             PLUGIN_LOG_E("RENDER_VALIDATION : invalid gpu handle %" PRIx64, clientHandle.id);
2217         }
2218 #endif
2219         return store.gpuHandles[arrayIndex];
2220     } else {
2221         PLUGIN_LOG_E("No gpu resource handle for client handle : %" PRIx64, clientHandle.id);
2222         return EngineResourceHandle {};
2223     }
2224 }
2225 
GetGpuHandle(const RenderHandle & clientHandle) const2226 EngineResourceHandle GpuResourceManager::GetGpuHandle(const RenderHandle& clientHandle) const
2227 {
2228     const RenderHandleType handleType = RenderHandleUtil::GetHandleType(clientHandle);
2229     if (handleType == RenderHandleType::GPU_BUFFER) {
2230         return GetGpuHandle(bufferStore_, clientHandle);
2231     } else if (handleType == RenderHandleType::GPU_IMAGE) {
2232         return GetGpuHandle(imageStore_, clientHandle);
2233     } else if (handleType == RenderHandleType::GPU_SAMPLER) {
2234         return GetGpuHandle(samplerStore_, clientHandle);
2235     } else {
2236         return {};
2237     }
2238 }
2239 
GetBuffer(const RenderHandle & handle) const2240 GpuBuffer* GpuResourceManager::GetBuffer(const RenderHandle& handle) const
2241 {
2242     const EngineResourceHandle resHandle = GetGpuHandle(bufferStore_, handle);
2243     return gpuBufferMgr_->Get(RenderHandleUtil::GetIndexPart(resHandle));
2244 }
2245 
GetImage(const RenderHandle & handle) const2246 GpuImage* GpuResourceManager::GetImage(const RenderHandle& handle) const
2247 {
2248     const EngineResourceHandle resHandle = GetGpuHandle(imageStore_, handle);
2249     return gpuImageMgr_->Get(RenderHandleUtil::GetIndexPart(resHandle));
2250 }
2251 
GetSampler(const RenderHandle & handle) const2252 GpuSampler* GpuResourceManager::GetSampler(const RenderHandle& handle) const
2253 {
2254     const EngineResourceHandle resHandle = GetGpuHandle(samplerStore_, handle);
2255     return gpuSamplerMgr_->Get(RenderHandleUtil::GetIndexPart(resHandle));
2256 }
2257 
GetBufferHandleCount() const2258 uint32_t GpuResourceManager::GetBufferHandleCount() const
2259 {
2260     return static_cast<uint32_t>(bufferStore_.gpuHandles.size());
2261 }
2262 
GetImageHandleCount() const2263 uint32_t GpuResourceManager::GetImageHandleCount() const
2264 {
2265     return static_cast<uint32_t>(imageStore_.gpuHandles.size());
2266 }
2267 
CreateClientHandle(const RenderHandleType type,const ResourceDescriptor & resourceDescriptor,const uint64_t handleId,const uint32_t hasNameId,const uint32_t additionalInfoFlags)2268 RenderHandle GpuResourceManager::CreateClientHandle(const RenderHandleType type,
2269     const ResourceDescriptor& resourceDescriptor, const uint64_t handleId, const uint32_t hasNameId,
2270     const uint32_t additionalInfoFlags)
2271 {
2272     RenderHandle handle;
2273 
2274     const uint32_t index = RenderHandleUtil::GetIndexPart(handleId);
2275     const uint32_t generationIndex = RenderHandleUtil::GetGenerationIndexPart(handleId) + 1; // next gen
2276     if (type == RenderHandleType::GPU_BUFFER) {
2277         // NOTE: additional flags for GPU acceleration structure might be needed
2278         const auto& rd = resourceDescriptor.combinedBufDescriptor.bufferDesc;
2279         RenderHandleInfoFlags infoFlags = (rd.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_DYNAMIC_BARRIERS)
2280                                               ? CORE_RESOURCE_HANDLE_DYNAMIC_TRACK
2281                                               : 0u;
2282         infoFlags |= (rd.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE)
2283                          ? CORE_RESOURCE_HANDLE_IMMEDIATELY_CREATED
2284                          : 0;
2285         infoFlags |= (rd.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_DEFERRED_DESTROY)
2286                          ? CORE_RESOURCE_HANDLE_DEFERRED_DESTROY
2287                          : 0;
2288         infoFlags |= (rd.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_MAP_OUTSIDE_RENDERER)
2289                          ? CORE_RESOURCE_HANDLE_MAP_OUTSIDE_RENDERER
2290                          : 0;
2291         // NOTE: currently tagged as shallow resource with dynamic ring buffer (offsets)
2292         infoFlags |= (rd.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER)
2293                          ? CORE_RESOURCE_HANDLE_SHALLOW_RESOURCE
2294                          : 0;
2295         infoFlags |= additionalInfoFlags;
2296         handle = RenderHandleUtil::CreateGpuResourceHandle(type, infoFlags, index, generationIndex, hasNameId);
2297     } else if (type == RenderHandleType::GPU_IMAGE) {
2298         const auto& rd = resourceDescriptor.imageDescriptor;
2299         RenderHandleInfoFlags infoFlags {};
2300         infoFlags |= (rd.engineCreationFlags & CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS)
2301                          ? CORE_RESOURCE_HANDLE_DYNAMIC_TRACK
2302                          : 0u;
2303         infoFlags |= (rd.engineCreationFlags & CORE_ENGINE_IMAGE_CREATION_DEFERRED_DESTROY)
2304                          ? CORE_RESOURCE_HANDLE_DEFERRED_DESTROY
2305                          : 0;
2306         infoFlags |= ((rd.engineCreationFlags & CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS) &&
2307                          (resourceDescriptor.imageDescriptor.mipCount > 1U))
2308                          ? CORE_RESOURCE_HANDLE_DYNAMIC_ADDITIONAL_STATE
2309                          : 0u;
2310         // force transient attachments to be state reset on frame borders
2311         infoFlags |= ((rd.engineCreationFlags & CORE_ENGINE_IMAGE_CREATION_RESET_STATE_ON_FRAME_BORDERS) ||
2312                          (rd.usageFlags & CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT))
2313                          ? CORE_RESOURCE_HANDLE_RESET_ON_FRAME_BORDERS
2314                          : 0u;
2315         infoFlags |= GetAdditionalImageFlagsFromFormat(rd.format);
2316         infoFlags |= additionalInfoFlags;
2317         handle = RenderHandleUtil::CreateGpuResourceHandle(type, infoFlags, index, generationIndex, hasNameId);
2318     } else if (type == RenderHandleType::GPU_SAMPLER) {
2319         handle = RenderHandleUtil::CreateGpuResourceHandle(type, 0, index, generationIndex, hasNameId);
2320     }
2321     return handle;
2322 }
2323 
2324 // needs to be locked when called
GetNextAvailableHandleId(PerManagerStore & store)2325 uint64_t GpuResourceManager::GetNextAvailableHandleId(PerManagerStore& store)
2326 {
2327     uint64_t handleId = INVALID_RESOURCE_HANDLE;
2328     auto& availableHandleIds = store.availableHandleIds;
2329     if (!availableHandleIds.empty()) {
2330         handleId = availableHandleIds.back();
2331         availableHandleIds.pop_back();
2332     } else {
2333         handleId = static_cast<uint32_t>(store.clientHandles.size())
2334                    << RenderHandleUtil::RES_HANDLE_ID_SHIFT; // next idx
2335     }
2336     return handleId;
2337 }
2338 
2339 // needs to be locked when called
2340 // staging cannot be locked when called
StoreAllocation(PerManagerStore & store,const StoreAllocationInfo & info)2341 GpuResourceManager::StoreAllocationData GpuResourceManager::StoreAllocation(
2342     PerManagerStore& store, const StoreAllocationInfo& info)
2343 {
2344     // NOTE: PerManagerStore gpu handles cannot be touched here
2345     StoreAllocationData data;
2346 
2347     // there cannot be both (valid name and a valid replaced handle)
2348     const uint32_t replaceArrayIndex = RenderHandleUtil::GetIndexPart(info.replacedHandle);
2349     bool hasReplaceHandle = (replaceArrayIndex < (uint32_t)store.clientHandles.size());
2350     uint32_t hasNameId = (!info.name.empty()) ? 1u : 0u;
2351     if (hasReplaceHandle) {
2352         data.handle = store.clientHandles[replaceArrayIndex];
2353         // re-use the name if it was present
2354         hasNameId = RenderHandleUtil::GetHasNamePart(data.handle.GetHandle());
2355         // NOTE: should be documented better, and prevented
2356         PLUGIN_ASSERT_MSG(!RenderHandleUtil::IsDeferredDestroy(data.handle.GetHandle()),
2357             "deferred desctruction resources cannot be replaced");
2358         if (RenderHandleUtil::IsValid(data.handle.GetHandle())) {
2359             // valid handle and reference counter, re-use the same ref count object, CreateClientHandle increases gen
2360             PLUGIN_ASSERT(data.handle.GetCounter());
2361             data.handle = RenderHandleReference(CreateClientHandle(info.type, info.descriptor,
2362                 data.handle.GetHandle().id, hasNameId, info.addHandleFlags), data.handle.GetCounter());
2363         } else {
2364 #if (RENDER_VALIDATION_ENABLED == 1)
2365             PLUGIN_LOG_E("RENDER_VALIDATION: invalid replaced handle given to GPU resource manager, creating new");
2366 #endif
2367             const uint64_t handleId = GetNextAvailableHandleId(store);
2368             data.handle = RenderHandleReference(
2369                 CreateClientHandle(info.type, info.descriptor, handleId, hasNameId, info.addHandleFlags),
2370                 IRenderReferenceCounter::Ptr(new RenderReferenceCounter()));
2371             hasReplaceHandle = false;
2372             if (hasNameId) {
2373                 // NOTE: should remove old name if it was in use
2374                 store.nameToClientIndex[info.name] = RenderHandleUtil::GetIndexPart(data.handle.GetHandle());
2375             }
2376         }
2377     } else if (hasNameId != 0u) {
2378         // in some cases the handle might be invalid even though it is found
2379         if (auto const iter = store.nameToClientIndex.find(info.name); iter != store.nameToClientIndex.cend()) {
2380             PLUGIN_ASSERT(iter->second < static_cast<uint32_t>(store.clientHandles.size()));
2381             data.handle = store.clientHandles[iter->second];
2382             PLUGIN_ASSERT_MSG(!RenderHandleUtil::IsDeferredDestroy(data.handle.GetHandle()),
2383                 "deferred desctruction resources cannot be replaced");
2384             data.handle = RenderHandleReference(CreateClientHandle(info.type, info.descriptor,
2385                 data.handle.GetHandle().id, hasNameId, info.addHandleFlags), data.handle.GetCounter());
2386         }
2387         if (!data.handle) {
2388             const uint64_t handleId = GetNextAvailableHandleId(store);
2389             data.handle = RenderHandleReference(
2390                 CreateClientHandle(info.type, info.descriptor, handleId, hasNameId, info.addHandleFlags),
2391                 IRenderReferenceCounter::Ptr(new RenderReferenceCounter()));
2392             store.nameToClientIndex[info.name] = RenderHandleUtil::GetIndexPart(data.handle.GetHandle());
2393         }
2394     } else {
2395         const uint64_t handleId = GetNextAvailableHandleId(store);
2396         data.handle = RenderHandleReference(
2397             CreateClientHandle(info.type, info.descriptor, handleId, hasNameId, info.addHandleFlags),
2398             IRenderReferenceCounter::Ptr(new RenderReferenceCounter()));
2399     }
2400 
2401     PLUGIN_ASSERT(data.handle);
2402     const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(data.handle.GetHandle());
2403     PLUGIN_ASSERT(store.clientHandles.size() == store.descriptions.size());
2404     PLUGIN_ASSERT(store.clientHandles.size() == store.additionalData.size());
2405     if (arrayIndex >= (uint32_t)store.clientHandles.size()) {
2406         store.clientHandles.push_back(data.handle);
2407         store.additionalData.push_back({});
2408         store.descriptions.push_back(info.descriptor);
2409     } else {
2410         store.clientHandles[arrayIndex] = data.handle;
2411         // store.additionalData[arrayIndex] cannot be cleared here (staging cleaned based on this)
2412         store.descriptions[arrayIndex] = info.descriptor;
2413     }
2414 
2415 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
2416     PLUGIN_LOG_E("gpu resource allocation %" PRIx64 " (name: %s)", data.handle.GetHandle().id, info.name.data());
2417 #endif
2418 
2419     // store allocation for GPU allocation
2420 
2421     // needs to find the allocation and replace
2422     if (hasReplaceHandle || (hasNameId != 0)) {
2423         if (const uint32_t pendingArrIndex = store.additionalData[arrayIndex].indexToPendingData;
2424             (pendingArrIndex != INVALID_PENDING_INDEX) && (pendingArrIndex < store.pendingData.allocations.size())) {
2425             data.allocationIndex = pendingArrIndex;
2426         }
2427     }
2428     if (data.allocationIndex == ~0u) {
2429         data.allocationIndex = store.pendingData.allocations.size();
2430         store.additionalData[arrayIndex].indexToPendingData = static_cast<uint32_t>(data.allocationIndex);
2431         store.pendingData.allocations.emplace_back(
2432             data.handle.GetHandle(), info.descriptor, info.allocType, info.optResourceIndex);
2433     } else { // quite rare case and slow path
2434         // replace this frame's allocation
2435         auto& allocOp = store.pendingData.allocations[data.allocationIndex];
2436         // invalid flag should be only needed and all the allocations would be done later
2437         // i.e. create staging buffers and fetch based on index in render node staging
2438         RemoveStagingOperations(allocOp);
2439         store.pendingData.allocations[data.allocationIndex] = { data.handle.GetHandle(), info.descriptor,
2440             info.allocType, info.optResourceIndex };
2441     }
2442 
2443     return data;
2444 }
2445 
IsGpuBuffer(const RenderHandleReference & handle) const2446 bool GpuResourceManager::IsGpuBuffer(const RenderHandleReference& handle) const
2447 {
2448     return IsGpuBuffer(handle.GetHandle());
2449 }
2450 
IsGpuImage(const RenderHandleReference & handle) const2451 bool GpuResourceManager::IsGpuImage(const RenderHandleReference& handle) const
2452 {
2453     return IsGpuImage(handle.GetHandle());
2454 }
2455 
IsGpuSampler(const RenderHandleReference & handle) const2456 bool GpuResourceManager::IsGpuSampler(const RenderHandleReference& handle) const
2457 {
2458     return IsGpuSampler(handle.GetHandle());
2459 }
2460 
IsGpuAccelerationStructure(const RenderHandleReference & handle) const2461 bool GpuResourceManager::IsGpuAccelerationStructure(const RenderHandleReference& handle) const
2462 {
2463     return IsGpuAccelerationStructure(handle.GetHandle());
2464 }
2465 
IsSwapchain(const RenderHandleReference & handle) const2466 bool GpuResourceManager::IsSwapchain(const RenderHandleReference& handle) const
2467 {
2468     return IsSwapchain(handle.GetHandle());
2469 }
2470 
IsMappableOutsideRender(const RenderHandleReference & handle) const2471 bool GpuResourceManager::IsMappableOutsideRender(const RenderHandleReference& handle) const
2472 {
2473     return RenderHandleUtil::IsMappableOutsideRenderer(handle.GetHandle());
2474 }
2475 
IsGpuBuffer(const RenderHandle & handle) const2476 bool GpuResourceManager::IsGpuBuffer(const RenderHandle& handle) const
2477 {
2478     return RenderHandleUtil::IsGpuBuffer(handle);
2479 }
2480 
IsGpuImage(const RenderHandle & handle) const2481 bool GpuResourceManager::IsGpuImage(const RenderHandle& handle) const
2482 {
2483     return RenderHandleUtil::IsGpuImage(handle);
2484 }
2485 
IsGpuSampler(const RenderHandle & handle) const2486 bool GpuResourceManager::IsGpuSampler(const RenderHandle& handle) const
2487 {
2488     return RenderHandleUtil::IsGpuSampler(handle);
2489 }
2490 
IsGpuAccelerationStructure(const RenderHandle & handle) const2491 bool GpuResourceManager::IsGpuAccelerationStructure(const RenderHandle& handle) const
2492 {
2493     return RenderHandleUtil::IsGpuAccelerationStructure(handle);
2494 }
2495 
IsSwapchain(const RenderHandle & handle) const2496 bool GpuResourceManager::IsSwapchain(const RenderHandle& handle) const
2497 {
2498     return RenderHandleUtil::IsSwapchain(handle);
2499 }
2500 
IsValid(const RenderHandle & handle) const2501 bool GpuResourceManager::IsValid(const RenderHandle& handle) const
2502 {
2503     return RenderHandleUtil::IsValid(handle);
2504 }
2505 
GetFormatProperties(const RenderHandle & handle) const2506 FormatProperties GpuResourceManager::GetFormatProperties(const RenderHandle& handle) const
2507 {
2508     const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
2509     Format format = Format::BASE_FORMAT_UNDEFINED;
2510     if (type == RenderHandleType::GPU_BUFFER) {
2511         const GpuBufferDesc desc = GetBufferDescriptor(handle);
2512         format = desc.format;
2513     } else if (type == RenderHandleType::GPU_IMAGE) {
2514         const GpuImageDesc desc = GetImageDescriptor(handle);
2515         format = desc.format;
2516     }
2517     return device_.GetFormatProperties(format);
2518 }
2519 
GetFormatProperties(const RenderHandleReference & handle) const2520 FormatProperties GpuResourceManager::GetFormatProperties(const RenderHandleReference& handle) const
2521 {
2522     return GetFormatProperties(handle.GetHandle());
2523 }
2524 
GetFormatProperties(const Format format) const2525 FormatProperties GpuResourceManager::GetFormatProperties(const Format format) const
2526 {
2527     return device_.GetFormatProperties(format);
2528 }
2529 
GetImageAspectFlags(const RenderHandleReference & handle) const2530 ImageAspectFlags GpuResourceManager::GetImageAspectFlags(const RenderHandleReference& handle) const
2531 {
2532     return GetImageAspectFlags(handle.GetHandle());
2533 }
2534 
GetImageAspectFlags(const RenderHandle & handle) const2535 ImageAspectFlags GpuResourceManager::GetImageAspectFlags(const RenderHandle& handle) const
2536 {
2537     const RenderHandleType type = RenderHandleUtil::GetHandleType(handle);
2538     Format format = Format::BASE_FORMAT_UNDEFINED;
2539     if (type == RenderHandleType::GPU_BUFFER) {
2540         const GpuBufferDesc desc = GetBufferDescriptor(handle);
2541         format = desc.format;
2542     } else if (type == RenderHandleType::GPU_IMAGE) {
2543         const GpuImageDesc desc = GetImageDescriptor(handle);
2544         format = desc.format;
2545     }
2546     return GetImageAspectFlags(format);
2547 }
2548 
GetImageAspectFlags(const BASE_NS::Format format) const2549 ImageAspectFlags GpuResourceManager::GetImageAspectFlags(const BASE_NS::Format format) const
2550 {
2551     ImageAspectFlags flags {};
2552     const bool isDepthFormat = ((format == BASE_FORMAT_D16_UNORM) || (format == BASE_FORMAT_X8_D24_UNORM_PACK32) ||
2553                                 (format == BASE_FORMAT_D32_SFLOAT) || (format == BASE_FORMAT_D16_UNORM_S8_UINT) ||
2554                                 (format == BASE_FORMAT_D24_UNORM_S8_UINT));
2555     if (isDepthFormat) {
2556         flags |= ImageAspectFlagBits::CORE_IMAGE_ASPECT_DEPTH_BIT;
2557 
2558         const bool isStencilFormat =
2559             ((format == BASE_FORMAT_S8_UINT) || (format == BASE_FORMAT_D16_UNORM_S8_UINT) ||
2560                 (format == BASE_FORMAT_D24_UNORM_S8_UINT) || (format == BASE_FORMAT_D32_SFLOAT_S8_UINT));
2561         if (isStencilFormat) {
2562             flags |= ImageAspectFlagBits::CORE_IMAGE_ASPECT_STENCIL_BIT;
2563         }
2564 
2565     } else if (format == BASE_FORMAT_S8_UINT) {
2566         flags |= ImageAspectFlagBits::CORE_IMAGE_ASPECT_STENCIL_BIT;
2567     } else if (format != BASE_FORMAT_UNDEFINED) {
2568         flags |= ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT;
2569     }
2570 
2571     return flags;
2572 }
2573 
GetColorSpaceFlags() const2574 ColorSpaceFlags GpuResourceManager::GetColorSpaceFlags() const
2575 {
2576     return device_.GetColorSpaceFlags();
2577 }
2578 
GetColorSpaceFormat(const Format format,const ColorSpaceFlags colorSpaceFlags) const2579 Format GpuResourceManager::GetColorSpaceFormat(const Format format, const ColorSpaceFlags colorSpaceFlags) const
2580 {
2581     return device_.GetColorSpaceFormat(format, colorSpaceFlags);
2582 }
2583 
GetSurfaceTransformFlags(const RenderHandleReference & handle) const2584 SurfaceTransformFlags GpuResourceManager::GetSurfaceTransformFlags(const RenderHandleReference& handle) const
2585 {
2586     return GetSurfaceTransformFlags(handle.GetHandle());
2587 }
2588 
GetSurfaceTransformFlags(const RenderHandle & handle) const2589 SurfaceTransformFlags GpuResourceManager::GetSurfaceTransformFlags(const RenderHandle& handle) const
2590 {
2591     if (IsSwapchain(handle)) {
2592         return device_.GetSurfaceTransformFlags(handle);
2593     } else {
2594         return 0u;
2595     }
2596 }
2597 
MapRenderTimeGpuBuffers()2598 void GpuResourceManager::MapRenderTimeGpuBuffers()
2599 {
2600     if (RenderHandleUtil::IsValid(renderTimeReservedGpuBuffer_.baseHandle)) {
2601         renderTimeReservedGpuBuffer_.mappedData = MapBuffer(renderTimeReservedGpuBuffer_.baseHandle);
2602     }
2603 }
2604 
UnmapRenderTimeGpuBuffers() const2605 void GpuResourceManager::UnmapRenderTimeGpuBuffers() const
2606 {
2607     if (RenderHandleUtil::IsValid(renderTimeReservedGpuBuffer_.baseHandle)) {
2608         UnmapBuffer(renderTimeReservedGpuBuffer_.baseHandle);
2609     }
2610 }
2611 
ReserveRenderTimeGpuBuffer(const uint32_t byteSize)2612 RenderHandle GpuResourceManager::ReserveRenderTimeGpuBuffer(const uint32_t byteSize)
2613 {
2614     if (renderTimeState_ != RenderTimeState::RENDER_PRE_EXECUTE) {
2615 #if (RENDER_VALIDATION_ENABLED == 1)
2616         PLUGIN_LOG_ONCE_W(
2617             "ReserveRenderTimeGpuBuffer_RENDER", "ReserveRenderTimeGpuBuffer can only be called in PreExecuteFrame()");
2618 #endif
2619         return {};
2620     }
2621 
2622     const uint32_t currOffset = renderTimeReservedGpuBuffer_.neededByteSize;
2623     const auto currIndex = static_cast<uint32_t>(renderTimeReservedGpuBuffer_.values.size());
2624 
2625     const uint32_t fullByteSize = Align(byteSize, BUFFER_ALIGNMENT);
2626 
2627     renderTimeReservedGpuBuffer_.neededByteSize += fullByteSize;
2628     // store only the needed bytesize
2629     renderTimeReservedGpuBuffer_.values.push_back({ currOffset, byteSize });
2630 
2631     constexpr RenderHandleInfoFlags infoFlags {
2632         RenderHandleInfoFlagBits::CORE_RESOURCE_HANDLE_RENDER_TIME_MAPPED_GPU_BUFFER
2633     };
2634     return RenderHandleUtil::CreateGpuResourceHandle(RenderHandleType::GPU_BUFFER, infoFlags, currIndex, 0xffU, 0U);
2635 }
2636 
AcquireRenderTimeGpuBuffer(const RenderHandle handle) const2637 IRenderNodeGpuResourceManager::MappedGpuBufferData GpuResourceManager::AcquireRenderTimeGpuBuffer(
2638     const RenderHandle handle) const
2639 {
2640     IRenderNodeGpuResourceManager::MappedGpuBufferData mgbd;
2641     if (renderTimeState_ != RenderTimeState::RENDER_EXECUTE) {
2642 #if (RENDER_VALIDATION_ENABLED == 1)
2643         PLUGIN_LOG_ONCE_W(
2644             "AcquireRenderTimeGpuBuffer_RENDER", "AcquireRenderTimeGpuBuffer can only be called in ExecuteFrame()");
2645 #endif
2646         return mgbd;
2647     } else if (RenderHandleUtil::GetAdditionalData(handle) &
2648                RenderHandleInfoFlagBits::CORE_RESOURCE_HANDLE_RENDER_TIME_MAPPED_GPU_BUFFER) {
2649         const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
2650         if (index < static_cast<uint32_t>(renderTimeReservedGpuBuffer_.executeValues.size())) {
2651             const auto& ref = renderTimeReservedGpuBuffer_.executeValues[index];
2652             mgbd.bindingByteOffset = ref.byteOffset;
2653             mgbd.byteSize = ref.byteSize;
2654             mgbd.data = static_cast<uint8_t*>(renderTimeReservedGpuBuffer_.mappedData) + ref.byteOffset;
2655             mgbd.handle = renderTimeReservedGpuBuffer_.baseHandle;
2656         }
2657     }
2658     return mgbd;
2659 }
2660 
SetState(const RenderTimeState rts)2661 void GpuResourceManager::SetState(const RenderTimeState rts)
2662 {
2663     renderTimeState_ = rts;
2664 }
2665 
CreateGpuImageDesc(const CORE_NS::IImageContainer::ImageDesc & desc) const2666 GpuImageDesc GpuResourceManager::CreateGpuImageDesc(const CORE_NS::IImageContainer::ImageDesc& desc) const
2667 {
2668     GpuImageDesc gpuImageDesc;
2669     // default values for loaded images
2670     gpuImageDesc.imageTiling = CORE_IMAGE_TILING_OPTIMAL;
2671     gpuImageDesc.usageFlags |= CORE_IMAGE_USAGE_SAMPLED_BIT | CORE_IMAGE_USAGE_TRANSFER_DST_BIT;
2672     gpuImageDesc.memoryPropertyFlags = CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
2673 
2674     if (desc.imageFlags & IImageContainer::ImageFlags::FLAGS_CUBEMAP_BIT) {
2675         gpuImageDesc.createFlags |= ImageCreateFlagBits::CORE_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
2676     }
2677     if ((desc.imageFlags & IImageContainer::ImageFlags::FLAGS_REQUESTING_MIPMAPS_BIT) && (desc.mipCount > 1)) {
2678         gpuImageDesc.engineCreationFlags |= EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_GENERATE_MIPS;
2679         gpuImageDesc.usageFlags |= CORE_IMAGE_USAGE_TRANSFER_SRC_BIT;
2680     }
2681     gpuImageDesc.imageType = static_cast<RENDER_NS::ImageType>(desc.imageType);
2682     gpuImageDesc.imageViewType = static_cast<RENDER_NS::ImageViewType>(desc.imageViewType);
2683     gpuImageDesc.format = desc.format;
2684     gpuImageDesc.width = desc.width;
2685     gpuImageDesc.height = desc.height;
2686     gpuImageDesc.depth = desc.depth;
2687     gpuImageDesc.mipCount = desc.mipCount;
2688     gpuImageDesc.layerCount = desc.layerCount;
2689     return gpuImageDesc;
2690 }
2691 
GetGpuResourceCache() const2692 IGpuResourceCache& GpuResourceManager::GetGpuResourceCache() const
2693 {
2694     return *gpuResourceCache_;
2695 }
2696 
2697 #if (RENDER_VULKAN_VALIDATION_ENABLED == 1)
ProcessDebugTags()2698 void GpuResourceManager::ProcessDebugTags()
2699 {
2700     // NOTE: there's a minor possibility that client data has changed before these are locked
2701     // but the GPU resource is the correct one
2702     // define CORE_EXTENT_DEBUG_GPU_RESOURCE_MGR_NAMES for more precise debugging
2703 #if defined(CORE_EXTENT_DEBUG_GPU_RESOURCE_MGR_NAMES)
2704     const auto frameIdx = to_string(device_.GetFrameCount());
2705 #endif
2706     auto AddDebugTags = [&](PerManagerStore& store, const RenderHandleType handleType) {
2707         const auto lock = std::lock_guard(store.clientMutex);
2708         vector<RenderHandle> allocs = move(store.debugTagAllocations);
2709         for (const auto& handle : allocs) {
2710             if (RenderHandleUtil::GetHasNamePart(handle) == 0) {
2711                 continue;
2712             }
2713             const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
2714             string name = GetName(store.clientHandles[arrayIndex].GetHandle());
2715 #if defined(CORE_EXTENT_DEBUG_GPU_RESOURCE_MGR_NAMES)
2716             const auto extentName =
2717                 "_chandle:" + to_string(handle.id) + "_idx:" + to_string(arrayIndex) + "_fr:" + frameIdx;
2718             name += extentName;
2719 #endif
2720             if (handleType == RenderHandleType::GPU_BUFFER) {
2721                 GpuResourceUtil::DebugBufferName(device_, *gpuBufferMgr_->Get(arrayIndex), name);
2722             } else if (handleType == RenderHandleType::GPU_IMAGE) {
2723                 GpuResourceUtil::DebugImageName(device_, *gpuImageMgr_->Get(arrayIndex), name);
2724             } else if (handleType == RenderHandleType::GPU_SAMPLER) {
2725                 GpuResourceUtil::DebugSamplerName(device_, *gpuSamplerMgr_->Get(arrayIndex), name);
2726             }
2727         }
2728     };
2729     AddDebugTags(bufferStore_, RenderHandleType::GPU_BUFFER);
2730     AddDebugTags(imageStore_, RenderHandleType::GPU_IMAGE);
2731     AddDebugTags(samplerStore_, RenderHandleType::GPU_SAMPLER);
2732 }
2733 #endif
2734 
RenderNodeGpuResourceManager(GpuResourceManager & gpuResourceManager)2735 RenderNodeGpuResourceManager::RenderNodeGpuResourceManager(GpuResourceManager& gpuResourceManager)
2736     : gpuResourceMgr_(gpuResourceManager)
2737 {}
2738 
2739 RenderNodeGpuResourceManager::~RenderNodeGpuResourceManager() = default;
2740 
Get(const RenderHandle & handle) const2741 RenderHandleReference RenderNodeGpuResourceManager::Get(const RenderHandle& handle) const
2742 {
2743     return gpuResourceMgr_.Get(handle);
2744 }
2745 
GetRawHandle(const RenderHandle & handle) const2746 RenderHandle RenderNodeGpuResourceManager::GetRawHandle(const RenderHandle& handle) const
2747 {
2748     return gpuResourceMgr_.GetRawHandle(handle);
2749 }
2750 
Create(const GpuBufferDesc & desc)2751 RenderHandleReference RenderNodeGpuResourceManager::Create(const GpuBufferDesc& desc)
2752 {
2753     return gpuResourceMgr_.Create(desc);
2754 }
2755 
Create(const string_view name,const GpuBufferDesc & desc)2756 RenderHandleReference RenderNodeGpuResourceManager::Create(const string_view name, const GpuBufferDesc& desc)
2757 {
2758     return gpuResourceMgr_.Create(name, desc);
2759 }
2760 
Create(const RenderHandleReference & handle,const GpuBufferDesc & desc)2761 RenderHandleReference RenderNodeGpuResourceManager::Create(
2762     const RenderHandleReference& handle, const GpuBufferDesc& desc)
2763 {
2764     return gpuResourceMgr_.Create(handle, desc);
2765 }
2766 
Create(const string_view name,const GpuBufferDesc & desc,const array_view<const uint8_t> data)2767 RenderHandleReference RenderNodeGpuResourceManager::Create(
2768     const string_view name, const GpuBufferDesc& desc, const array_view<const uint8_t> data)
2769 {
2770     return gpuResourceMgr_.Create(name, desc, data);
2771 }
2772 
Create(const GpuImageDesc & desc)2773 RenderHandleReference RenderNodeGpuResourceManager::Create(const GpuImageDesc& desc)
2774 {
2775     return gpuResourceMgr_.Create(desc);
2776 }
2777 
Create(const string_view name,const GpuImageDesc & desc)2778 RenderHandleReference RenderNodeGpuResourceManager::Create(const string_view name, const GpuImageDesc& desc)
2779 {
2780     return gpuResourceMgr_.Create(name, desc);
2781 }
2782 
Create(const RenderHandleReference & handle,const GpuImageDesc & desc)2783 RenderHandleReference RenderNodeGpuResourceManager::Create(
2784     const RenderHandleReference& handle, const GpuImageDesc& desc)
2785 {
2786     return gpuResourceMgr_.Create(handle, desc);
2787 }
2788 
Create(const string_view name,const GpuImageDesc & desc,const array_view<const uint8_t> data)2789 RenderHandleReference RenderNodeGpuResourceManager::Create(
2790     const string_view name, const GpuImageDesc& desc, const array_view<const uint8_t> data)
2791 {
2792     return gpuResourceMgr_.Create(name, desc, data);
2793 }
2794 
Create(const string_view name,const GpuSamplerDesc & desc)2795 RenderHandleReference RenderNodeGpuResourceManager::Create(const string_view name, const GpuSamplerDesc& desc)
2796 {
2797     return gpuResourceMgr_.Create(name, desc);
2798 }
2799 
Create(const RenderHandleReference & handle,const GpuSamplerDesc & desc)2800 RenderHandleReference RenderNodeGpuResourceManager::Create(
2801     const RenderHandleReference& handle, const GpuSamplerDesc& desc)
2802 {
2803     return gpuResourceMgr_.Create(handle, desc);
2804 }
2805 
Create(const GpuSamplerDesc & desc)2806 RenderHandleReference RenderNodeGpuResourceManager::Create(const GpuSamplerDesc& desc)
2807 {
2808     return gpuResourceMgr_.Create(desc);
2809 }
2810 
Create(const string_view name,const GpuAccelerationStructureDesc & desc)2811 RenderHandleReference RenderNodeGpuResourceManager::Create(
2812     const string_view name, const GpuAccelerationStructureDesc& desc)
2813 {
2814     return gpuResourceMgr_.Create(name, desc);
2815 }
2816 
Create(const RenderHandleReference & handle,const GpuAccelerationStructureDesc & desc)2817 RenderHandleReference RenderNodeGpuResourceManager::Create(
2818     const RenderHandleReference& handle, const GpuAccelerationStructureDesc& desc)
2819 {
2820     return gpuResourceMgr_.Create(handle, desc);
2821 }
2822 
Create(const GpuAccelerationStructureDesc & desc)2823 RenderHandleReference RenderNodeGpuResourceManager::Create(const GpuAccelerationStructureDesc& desc)
2824 {
2825     return gpuResourceMgr_.Create(desc);
2826 }
2827 
GetBufferHandle(const string_view name) const2828 RenderHandle RenderNodeGpuResourceManager::GetBufferHandle(const string_view name) const
2829 {
2830     return gpuResourceMgr_.GetBufferRawHandle(name);
2831 }
2832 
GetImageHandle(const string_view name) const2833 RenderHandle RenderNodeGpuResourceManager::GetImageHandle(const string_view name) const
2834 {
2835     return gpuResourceMgr_.GetImageRawHandle(name);
2836 }
2837 
GetSamplerHandle(const string_view name) const2838 RenderHandle RenderNodeGpuResourceManager::GetSamplerHandle(const string_view name) const
2839 {
2840     return gpuResourceMgr_.GetSamplerRawHandle(name);
2841 }
2842 
GetBufferDescriptor(const RenderHandle & handle) const2843 GpuBufferDesc RenderNodeGpuResourceManager::GetBufferDescriptor(const RenderHandle& handle) const
2844 {
2845     return gpuResourceMgr_.GetBufferDescriptor(handle);
2846 }
2847 
GetImageDescriptor(const RenderHandle & handle) const2848 GpuImageDesc RenderNodeGpuResourceManager::GetImageDescriptor(const RenderHandle& handle) const
2849 {
2850     return gpuResourceMgr_.GetImageDescriptor(handle);
2851 }
2852 
GetSamplerDescriptor(const RenderHandle & handle) const2853 GpuSamplerDesc RenderNodeGpuResourceManager::GetSamplerDescriptor(const RenderHandle& handle) const
2854 {
2855     return gpuResourceMgr_.GetSamplerDescriptor(handle);
2856 }
2857 
GetAccelerationStructureDescriptor(const RenderHandle & handle) const2858 GpuAccelerationStructureDesc RenderNodeGpuResourceManager::GetAccelerationStructureDescriptor(
2859     const RenderHandle& handle) const
2860 {
2861     return gpuResourceMgr_.GetAccelerationStructureDescriptor(handle);
2862 }
2863 
HasStagingData() const2864 bool RenderNodeGpuResourceManager::HasStagingData() const
2865 {
2866     return gpuResourceMgr_.HasStagingData();
2867 }
2868 
ConsumeStagingData()2869 StagingConsumeStruct RenderNodeGpuResourceManager::ConsumeStagingData()
2870 {
2871     return gpuResourceMgr_.ConsumeStagingData();
2872 }
2873 
MapBuffer(const RenderHandle & handle) const2874 void* RenderNodeGpuResourceManager::MapBuffer(const RenderHandle& handle) const
2875 {
2876     return gpuResourceMgr_.MapBuffer(handle);
2877 }
2878 
MapBufferMemory(const RenderHandle & handle) const2879 void* RenderNodeGpuResourceManager::MapBufferMemory(const RenderHandle& handle) const
2880 {
2881     return gpuResourceMgr_.MapBufferMemory(handle);
2882 }
2883 
UnmapBuffer(const RenderHandle & handle) const2884 void RenderNodeGpuResourceManager::UnmapBuffer(const RenderHandle& handle) const
2885 {
2886     gpuResourceMgr_.UnmapBuffer(handle);
2887 }
2888 
GetGpuResourceManager()2889 GpuResourceManager& RenderNodeGpuResourceManager::GetGpuResourceManager()
2890 {
2891     return gpuResourceMgr_;
2892 }
2893 
IsValid(const RenderHandle & handle) const2894 bool RenderNodeGpuResourceManager::IsValid(const RenderHandle& handle) const
2895 {
2896     return RenderHandleUtil::IsValid(handle);
2897 }
2898 
IsGpuBuffer(const RenderHandle & handle) const2899 bool RenderNodeGpuResourceManager::IsGpuBuffer(const RenderHandle& handle) const
2900 {
2901     return RenderHandleUtil::IsGpuBuffer(handle);
2902 }
2903 
IsGpuImage(const RenderHandle & handle) const2904 bool RenderNodeGpuResourceManager::IsGpuImage(const RenderHandle& handle) const
2905 {
2906     return RenderHandleUtil::IsGpuImage(handle);
2907 }
2908 
IsGpuSampler(const RenderHandle & handle) const2909 bool RenderNodeGpuResourceManager::IsGpuSampler(const RenderHandle& handle) const
2910 {
2911     return RenderHandleUtil::IsGpuSampler(handle);
2912 }
2913 
IsGpuAccelerationStructure(const RenderHandle & handle) const2914 bool RenderNodeGpuResourceManager::IsGpuAccelerationStructure(const RenderHandle& handle) const
2915 {
2916     return RenderHandleUtil::IsGpuAccelerationStructure(handle);
2917 }
2918 
IsSwapchain(const RenderHandle & handle) const2919 bool RenderNodeGpuResourceManager::IsSwapchain(const RenderHandle& handle) const
2920 {
2921     return RenderHandleUtil::IsSwapchain(handle);
2922 }
2923 
GetFormatProperties(const RenderHandle & handle) const2924 FormatProperties RenderNodeGpuResourceManager::GetFormatProperties(const RenderHandle& handle) const
2925 {
2926     return gpuResourceMgr_.GetFormatProperties(handle);
2927 }
2928 
GetFormatProperties(const Format format) const2929 FormatProperties RenderNodeGpuResourceManager::GetFormatProperties(const Format format) const
2930 {
2931     return gpuResourceMgr_.GetFormatProperties(format);
2932 }
2933 
GetImageAspectFlags(const RenderHandle & handle) const2934 ImageAspectFlags RenderNodeGpuResourceManager::GetImageAspectFlags(const RenderHandle& handle) const
2935 {
2936     return gpuResourceMgr_.GetImageAspectFlags(handle);
2937 }
2938 
GetImageAspectFlags(const Format format) const2939 ImageAspectFlags RenderNodeGpuResourceManager::GetImageAspectFlags(const Format format) const
2940 {
2941     return gpuResourceMgr_.GetImageAspectFlags(format);
2942 }
2943 
GetColorSpaceFlags() const2944 ColorSpaceFlags RenderNodeGpuResourceManager::GetColorSpaceFlags() const
2945 {
2946     return gpuResourceMgr_.GetColorSpaceFlags();
2947 }
2948 
GetColorSpaceFormat(const Format format,const ColorSpaceFlags colorSpaceFlags) const2949 Format RenderNodeGpuResourceManager::GetColorSpaceFormat(
2950     const Format format, const ColorSpaceFlags colorSpaceFlags) const
2951 {
2952     return gpuResourceMgr_.GetColorSpaceFormat(format, colorSpaceFlags);
2953 }
2954 
GetSurfaceTransformFlags(const RenderHandle & handle) const2955 SurfaceTransformFlags RenderNodeGpuResourceManager::GetSurfaceTransformFlags(const RenderHandle& handle) const
2956 {
2957     return gpuResourceMgr_.GetSurfaceTransformFlags(handle);
2958 }
2959 
GetName(const RenderHandle & handle) const2960 string RenderNodeGpuResourceManager::GetName(const RenderHandle& handle) const
2961 {
2962     return gpuResourceMgr_.GetName(handle);
2963 }
2964 
GetBufferHandles() const2965 vector<RenderHandle> RenderNodeGpuResourceManager::GetBufferHandles() const
2966 {
2967     return gpuResourceMgr_.GetRawBufferHandles();
2968 }
2969 
GetImageHandles() const2970 vector<RenderHandle> RenderNodeGpuResourceManager::GetImageHandles() const
2971 {
2972     return gpuResourceMgr_.GetRawImageHandles();
2973 }
2974 
GetSamplerHandles() const2975 vector<RenderHandle> RenderNodeGpuResourceManager::GetSamplerHandles() const
2976 {
2977     return gpuResourceMgr_.GetRawSamplerHandles();
2978 }
2979 
GetGpuResourceCache() const2980 IGpuResourceCache& RenderNodeGpuResourceManager::GetGpuResourceCache() const
2981 {
2982     return gpuResourceMgr_.GetGpuResourceCache();
2983 }
2984 
ReserveGpuBuffer(const uint32_t byteSize)2985 RenderHandle RenderNodeGpuResourceManager::ReserveGpuBuffer(const uint32_t byteSize)
2986 {
2987     return gpuResourceMgr_.ReserveRenderTimeGpuBuffer(byteSize);
2988 }
2989 
AcquireGpubuffer(const RenderHandle handle)2990 RenderNodeGpuResourceManager::MappedGpuBufferData RenderNodeGpuResourceManager::AcquireGpubuffer(
2991     const RenderHandle handle)
2992 {
2993     return gpuResourceMgr_.AcquireRenderTimeGpuBuffer(handle);
2994 }
2995 
2996 RENDER_END_NAMESPACE()
2997