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