From 7c6b0740e2dc45ce2150a85867a16751f3436a11 Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Mon, 19 Jan 2026 16:47:44 +0000 Subject: [PATCH 01/15] updated vulkan device --- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 54 +++++++++++++--------- ZEngine/ZEngine/Hardwares/VulkanDevice.h | 3 +- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index 5eff9d9e..db996066 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -191,11 +191,17 @@ namespace ZEngine::Hardwares physical_device_properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; physical_device_properties2.pNext = &indexing_properties; - VkPhysicalDeviceFeatures physical_device_feature; vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties); vkGetPhysicalDeviceProperties2(physical_device, &physical_device_properties2); - vkGetPhysicalDeviceFeatures(physical_device, &physical_device_feature); + + + VkPhysicalDeviceDescriptorIndexingFeatures descriptor_indexing_features = {}; + descriptor_indexing_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + VkPhysicalDeviceFeatures2 physical_device_feature = {}; + physical_device_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + physical_device_feature.pNext = &descriptor_indexing_features; + vkGetPhysicalDeviceFeatures2(physical_device, &physical_device_feature); if (/*(physical_device_feature.geometryShader == VK_TRUE) && (physical_device_feature.samplerAnisotropy == VK_TRUE) && */ ((physical_device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) || (physical_device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU))) { @@ -203,6 +209,9 @@ namespace ZEngine::Hardwares PhysicalDeviceProperties = physical_device_properties; PhysicalDeviceDescriptorIndexingProperties = indexing_properties; PhysicalDeviceFeature = physical_device_feature; + PhysicalDeviceSupportDescriptorUpdateAfterBind = (descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind == VK_TRUE && + descriptor_indexing_features.descriptorBindingPartiallyBound == VK_TRUE && + descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending == VK_TRUE); vkGetPhysicalDeviceMemoryProperties(PhysicalDevice, &PhysicalDeviceMemoryProperties); break; } @@ -287,26 +296,10 @@ namespace ZEngine::Hardwares queue_create_info.queueCount = 1; queue_create_info.pNext = nullptr; } + /* * Enabling some features */ - PhysicalDeviceFeature.drawIndirectFirstInstance = VK_TRUE; - PhysicalDeviceFeature.multiDrawIndirect = VK_TRUE; - PhysicalDeviceFeature.shaderSampledImageArrayDynamicIndexing = VK_TRUE; - - VkPhysicalDeviceDescriptorIndexingFeaturesEXT physical_device_descriptor_indexing_features = {}; - physical_device_descriptor_indexing_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; - physical_device_descriptor_indexing_features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; - physical_device_descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE; - physical_device_descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending = VK_TRUE; - physical_device_descriptor_indexing_features.descriptorBindingPartiallyBound = VK_TRUE; - physical_device_descriptor_indexing_features.runtimeDescriptorArray = VK_TRUE; - - VkPhysicalDeviceFeatures2 device_features_2 = {}; - device_features_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - device_features_2.pNext = &physical_device_descriptor_indexing_features; - device_features_2.features = PhysicalDeviceFeature; - VkDeviceCreateInfo device_create_info = {}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.queueCreateInfoCount = queue_create_info_collection.size(); @@ -314,6 +307,25 @@ namespace ZEngine::Hardwares device_create_info.enabledExtensionCount = static_cast(requested_device_extension_layer_name_collection.size()); device_create_info.ppEnabledExtensionNames = (requested_device_extension_layer_name_collection.size() > 0) ? requested_device_extension_layer_name_collection.data() : nullptr; device_create_info.pEnabledFeatures = nullptr; + + + VkPhysicalDeviceDescriptorIndexingFeatures physical_device_descriptor_indexing_features = {}; + physical_device_descriptor_indexing_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + VkPhysicalDeviceFeatures2 device_features_2 = {}; + device_features_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + device_features_2.features.drawIndirectFirstInstance = PhysicalDeviceFeature.features.drawIndirectFirstInstance; + device_features_2.features.multiDrawIndirect = PhysicalDeviceFeature.features.multiDrawIndirect; + if (PhysicalDeviceSupportDescriptorUpdateAfterBind) + { + physical_device_descriptor_indexing_features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; + physical_device_descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE; + physical_device_descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending = VK_TRUE; + physical_device_descriptor_indexing_features.descriptorBindingPartiallyBound = VK_TRUE; + physical_device_descriptor_indexing_features.runtimeDescriptorArray = VK_TRUE; + + device_features_2.pNext = &physical_device_descriptor_indexing_features; + } + device_create_info.pNext = &device_features_2; ZENGINE_VALIDATE_ASSERT(vkCreateDevice(PhysicalDevice, &device_create_info, nullptr, &LogicalDevice) == VK_SUCCESS, "Failed to create GPU logical device") @@ -893,8 +905,8 @@ namespace ZEngine::Hardwares sampler_create_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_create_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_create_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler_create_info.anisotropyEnable = PhysicalDeviceFeature.samplerAnisotropy; - sampler_create_info.maxAnisotropy = PhysicalDeviceFeature.samplerAnisotropy ? PhysicalDeviceProperties.limits.maxSamplerAnisotropy : 1.0f; + sampler_create_info.anisotropyEnable = PhysicalDeviceFeature.features.samplerAnisotropy; + sampler_create_info.maxAnisotropy = PhysicalDeviceFeature.features.samplerAnisotropy ? PhysicalDeviceProperties.limits.maxSamplerAnisotropy : 1.0f; sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; sampler_create_info.unnormalizedCoordinates = VK_FALSE; sampler_create_info.compareEnable = VK_FALSE; diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.h b/ZEngine/ZEngine/Hardwares/VulkanDevice.h index 5b200fea..0fc648a1 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.h +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.h @@ -535,6 +535,7 @@ namespace ZEngine::Hardwares struct VulkanDevice { bool HasSeperateTransfertQueueFamily = false; + bool PhysicalDeviceSupportDescriptorUpdateAfterBind = false; const char* ApplicationName = "Tetragrama"; const char* EngineName = "ZEngine"; uint32_t SwapchainImageCount = 3; @@ -555,7 +556,7 @@ namespace ZEngine::Hardwares VkPhysicalDeviceDescriptorIndexingProperties PhysicalDeviceDescriptorIndexingProperties = {}; VkDevice LogicalDevice = VK_NULL_HANDLE; VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE; - VkPhysicalDeviceFeatures PhysicalDeviceFeature = {}; + VkPhysicalDeviceFeatures2 PhysicalDeviceFeature = {}; VkPhysicalDeviceMemoryProperties PhysicalDeviceMemoryProperties = {}; VkSwapchainKHR SwapchainHandle = VK_NULL_HANDLE; VmaAllocator VmaAllocatorValue = nullptr; From d7324d0ee45aa32650a01687d6add95323450264 Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Tue, 20 Jan 2026 02:51:24 +0900 Subject: [PATCH 02/15] added update-after-bind detection --- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 65 +++++------ ZEngine/ZEngine/Hardwares/VulkanDevice.h | 116 +++++++++---------- ZEngine/ZEngine/Rendering/Shaders/Shader.cpp | 52 +++++++-- 3 files changed, 134 insertions(+), 99 deletions(-) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index db996066..8c6b384d 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -191,27 +191,23 @@ namespace ZEngine::Hardwares physical_device_properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; physical_device_properties2.pNext = &indexing_properties; - vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties); vkGetPhysicalDeviceProperties2(physical_device, &physical_device_properties2); - VkPhysicalDeviceDescriptorIndexingFeatures descriptor_indexing_features = {}; - descriptor_indexing_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; - VkPhysicalDeviceFeatures2 physical_device_feature = {}; - physical_device_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - physical_device_feature.pNext = &descriptor_indexing_features; + descriptor_indexing_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + VkPhysicalDeviceFeatures2 physical_device_feature = {}; + physical_device_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + physical_device_feature.pNext = &descriptor_indexing_features; vkGetPhysicalDeviceFeatures2(physical_device, &physical_device_feature); if (/*(physical_device_feature.geometryShader == VK_TRUE) && (physical_device_feature.samplerAnisotropy == VK_TRUE) && */ ((physical_device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) || (physical_device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU))) { - PhysicalDevice = physical_device; - PhysicalDeviceProperties = physical_device_properties; - PhysicalDeviceDescriptorIndexingProperties = indexing_properties; - PhysicalDeviceFeature = physical_device_feature; - PhysicalDeviceSupportDescriptorUpdateAfterBind = (descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind == VK_TRUE && - descriptor_indexing_features.descriptorBindingPartiallyBound == VK_TRUE && - descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending == VK_TRUE); + PhysicalDevice = physical_device; + PhysicalDeviceProperties = physical_device_properties; + PhysicalDeviceDescriptorIndexingProperties = indexing_properties; + PhysicalDeviceFeature = physical_device_feature; + PhysicalDeviceSupportDescriptorUpdateAfterBind = (descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind == VK_TRUE && descriptor_indexing_features.descriptorBindingPartiallyBound == VK_TRUE && descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending == VK_TRUE); vkGetPhysicalDeviceMemoryProperties(PhysicalDevice, &PhysicalDeviceMemoryProperties); break; } @@ -296,37 +292,38 @@ namespace ZEngine::Hardwares queue_create_info.queueCount = 1; queue_create_info.pNext = nullptr; } - + /* * Enabling some features */ - VkDeviceCreateInfo device_create_info = {}; - device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device_create_info.queueCreateInfoCount = queue_create_info_collection.size(); - device_create_info.pQueueCreateInfos = queue_create_info_collection.data(); - device_create_info.enabledExtensionCount = static_cast(requested_device_extension_layer_name_collection.size()); - device_create_info.ppEnabledExtensionNames = (requested_device_extension_layer_name_collection.size() > 0) ? requested_device_extension_layer_name_collection.data() : nullptr; - device_create_info.pEnabledFeatures = nullptr; - + VkDeviceCreateInfo device_create_info = {}; + device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + device_create_info.queueCreateInfoCount = queue_create_info_collection.size(); + device_create_info.pQueueCreateInfos = queue_create_info_collection.data(); + device_create_info.enabledExtensionCount = static_cast(requested_device_extension_layer_name_collection.size()); + device_create_info.ppEnabledExtensionNames = (requested_device_extension_layer_name_collection.size() > 0) ? requested_device_extension_layer_name_collection.data() : nullptr; + device_create_info.pEnabledFeatures = nullptr; VkPhysicalDeviceDescriptorIndexingFeatures physical_device_descriptor_indexing_features = {}; - physical_device_descriptor_indexing_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; - VkPhysicalDeviceFeatures2 device_features_2 = {}; - device_features_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - device_features_2.features.drawIndirectFirstInstance = PhysicalDeviceFeature.features.drawIndirectFirstInstance; - device_features_2.features.multiDrawIndirect = PhysicalDeviceFeature.features.multiDrawIndirect; + physical_device_descriptor_indexing_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + VkPhysicalDeviceFeatures2 device_features_2 = {}; + device_features_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + device_features_2.features.drawIndirectFirstInstance = PhysicalDeviceFeature.features.drawIndirectFirstInstance; + device_features_2.features.multiDrawIndirect = PhysicalDeviceFeature.features.multiDrawIndirect; + device_features_2.features.samplerAnisotropy = PhysicalDeviceFeature.features.samplerAnisotropy; + device_features_2.features.shaderInt64 = PhysicalDeviceFeature.features.shaderInt64; if (PhysicalDeviceSupportDescriptorUpdateAfterBind) { - physical_device_descriptor_indexing_features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; - physical_device_descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE; - physical_device_descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending = VK_TRUE; - physical_device_descriptor_indexing_features.descriptorBindingPartiallyBound = VK_TRUE; - physical_device_descriptor_indexing_features.runtimeDescriptorArray = VK_TRUE; + physical_device_descriptor_indexing_features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; + physical_device_descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE; + physical_device_descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending = VK_TRUE; + physical_device_descriptor_indexing_features.descriptorBindingPartiallyBound = VK_TRUE; + physical_device_descriptor_indexing_features.runtimeDescriptorArray = VK_TRUE; - device_features_2.pNext = &physical_device_descriptor_indexing_features; + device_features_2.pNext = &physical_device_descriptor_indexing_features; } - device_create_info.pNext = &device_features_2; + device_create_info.pNext = &device_features_2; ZENGINE_VALIDATE_ASSERT(vkCreateDevice(PhysicalDevice, &device_create_info, nullptr, &LogicalDevice) == VK_SUCCESS, "Failed to create GPU logical device") diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.h b/ZEngine/ZEngine/Hardwares/VulkanDevice.h index 0fc648a1..d90c1a99 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.h +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.h @@ -534,64 +534,64 @@ namespace ZEngine::Hardwares */ struct VulkanDevice { - bool HasSeperateTransfertQueueFamily = false; - bool PhysicalDeviceSupportDescriptorUpdateAfterBind = false; - const char* ApplicationName = "Tetragrama"; - const char* EngineName = "ZEngine"; - uint32_t SwapchainImageCount = 3; - uint32_t SwapchainImageIndex = std::numeric_limits::max(); - uint32_t CurrentFrameIndex = std::numeric_limits::max(); - uint32_t PreviousFrameIndex = std::numeric_limits::max(); - uint32_t SwapchainImageWidth = std::numeric_limits::max(); - uint32_t SwapchainImageHeight = std::numeric_limits::max(); - uint32_t GraphicFamilyIndex = std::numeric_limits::max(); - uint32_t TransferFamilyIndex = std::numeric_limits::max(); - uint32_t EnqueuedCommandbufferIndex = 0; - uint32_t WriteDescriptorSetIndex = 0; - VkInstance Instance = VK_NULL_HANDLE; - VkSurfaceKHR Surface = VK_NULL_HANDLE; - VkSurfaceFormatKHR SurfaceFormat = {}; - VkPresentModeKHR PresentMode = {}; - VkPhysicalDeviceProperties PhysicalDeviceProperties = {}; - VkPhysicalDeviceDescriptorIndexingProperties PhysicalDeviceDescriptorIndexingProperties = {}; - VkDevice LogicalDevice = VK_NULL_HANDLE; - VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE; - VkPhysicalDeviceFeatures2 PhysicalDeviceFeature = {}; - VkPhysicalDeviceMemoryProperties PhysicalDeviceMemoryProperties = {}; - VkSwapchainKHR SwapchainHandle = VK_NULL_HANDLE; - VmaAllocator VmaAllocatorValue = nullptr; - Core::Containers::Array DefaultDepthFormats = {}; - Rendering::Renderers::RenderPasses::Attachment* SwapchainAttachment = {}; - Core::Containers::Array SwapchainImageViews = {}; - Core::Containers::Array SwapchainFramebuffers = {}; - Core::Containers::Array SwapchainAcquiredSemaphores = {}; - Core::Containers::Array SwapchainRenderCompleteSemaphores = {}; - Core::Containers::Array SwapchainSignalFences = {}; - Core::Containers::Array EnqueuedCommandbuffers = {}; - Core::Containers::HashMap> ShaderCaches = {}; - std::set WriteBindlessDescriptorSetRequests = {}; - Rendering::Textures::TextureHandleManager GlobalTextures = {}; - Helpers::HandleManager Image2DBufferManager = {}; - Helpers::ThreadSafeQueue TextureHandleToUpdates = {}; - Helpers::ThreadSafeQueue TextureHandleToDispose = {}; - Helpers::HandleManager ShaderManager = {}; - Helpers::HandleManager VertexBufferSetManager = {}; - Helpers::HandleManager StorageBufferSetManager = {}; - Helpers::HandleManager IndirectBufferSetManager = {}; - Helpers::HandleManager IndexBufferSetManager = {}; - Helpers::HandleManager UniformBufferSetManager = {}; - Helpers::HandleManager DirtyResources = {}; - Helpers::HandleManager DirtyBuffers = {}; - Helpers::HandleManager DirtyBufferImages = {}; - std::atomic_bool RunningDirtyCollector = true; - std::atomic_uint IdleFrameCount = 0; - std::atomic_uint IdleFrameThreshold = SwapchainImageCount * 3 * 3; - std::condition_variable DirtyCollectorCond = {}; - std::mutex DirtyMutex = {}; - std::mutex Mutex = {}; - Windows::CoreWindow* CurrentWindow = nullptr; - ZEngine::Core::Memory::ArenaAllocator* Arena = nullptr; - AsyncResourceLoaderPtr AsyncResLoader = nullptr; + bool HasSeperateTransfertQueueFamily = false; + bool PhysicalDeviceSupportDescriptorUpdateAfterBind = false; + const char* ApplicationName = "Tetragrama"; + const char* EngineName = "ZEngine"; + uint32_t SwapchainImageCount = 3; + uint32_t SwapchainImageIndex = std::numeric_limits::max(); + uint32_t CurrentFrameIndex = std::numeric_limits::max(); + uint32_t PreviousFrameIndex = std::numeric_limits::max(); + uint32_t SwapchainImageWidth = std::numeric_limits::max(); + uint32_t SwapchainImageHeight = std::numeric_limits::max(); + uint32_t GraphicFamilyIndex = std::numeric_limits::max(); + uint32_t TransferFamilyIndex = std::numeric_limits::max(); + uint32_t EnqueuedCommandbufferIndex = 0; + uint32_t WriteDescriptorSetIndex = 0; + VkInstance Instance = VK_NULL_HANDLE; + VkSurfaceKHR Surface = VK_NULL_HANDLE; + VkSurfaceFormatKHR SurfaceFormat = {}; + VkPresentModeKHR PresentMode = {}; + VkPhysicalDeviceProperties PhysicalDeviceProperties = {}; + VkPhysicalDeviceDescriptorIndexingProperties PhysicalDeviceDescriptorIndexingProperties = {}; + VkDevice LogicalDevice = VK_NULL_HANDLE; + VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE; + VkPhysicalDeviceFeatures2 PhysicalDeviceFeature = {}; + VkPhysicalDeviceMemoryProperties PhysicalDeviceMemoryProperties = {}; + VkSwapchainKHR SwapchainHandle = VK_NULL_HANDLE; + VmaAllocator VmaAllocatorValue = nullptr; + Core::Containers::Array DefaultDepthFormats = {}; + Rendering::Renderers::RenderPasses::Attachment* SwapchainAttachment = {}; + Core::Containers::Array SwapchainImageViews = {}; + Core::Containers::Array SwapchainFramebuffers = {}; + Core::Containers::Array SwapchainAcquiredSemaphores = {}; + Core::Containers::Array SwapchainRenderCompleteSemaphores = {}; + Core::Containers::Array SwapchainSignalFences = {}; + Core::Containers::Array EnqueuedCommandbuffers = {}; + Core::Containers::HashMap> ShaderCaches = {}; + std::set WriteBindlessDescriptorSetRequests = {}; + Rendering::Textures::TextureHandleManager GlobalTextures = {}; + Helpers::HandleManager Image2DBufferManager = {}; + Helpers::ThreadSafeQueue TextureHandleToUpdates = {}; + Helpers::ThreadSafeQueue TextureHandleToDispose = {}; + Helpers::HandleManager ShaderManager = {}; + Helpers::HandleManager VertexBufferSetManager = {}; + Helpers::HandleManager StorageBufferSetManager = {}; + Helpers::HandleManager IndirectBufferSetManager = {}; + Helpers::HandleManager IndexBufferSetManager = {}; + Helpers::HandleManager UniformBufferSetManager = {}; + Helpers::HandleManager DirtyResources = {}; + Helpers::HandleManager DirtyBuffers = {}; + Helpers::HandleManager DirtyBufferImages = {}; + std::atomic_bool RunningDirtyCollector = true; + std::atomic_uint IdleFrameCount = 0; + std::atomic_uint IdleFrameThreshold = SwapchainImageCount * 3 * 3; + std::condition_variable DirtyCollectorCond = {}; + std::mutex DirtyMutex = {}; + std::mutex Mutex = {}; + Windows::CoreWindow* CurrentWindow = nullptr; + ZEngine::Core::Memory::ArenaAllocator* Arena = nullptr; + AsyncResourceLoaderPtr AsyncResLoader = nullptr; void Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, Windows::CoreWindow* const window); void Deinitialize(); diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp index 909aae71..efe5d75c 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp @@ -216,7 +216,37 @@ namespace ZEngine::Rendering::Shaders count = type.array[0]; if (count == 0) // Unsized arrays { - count = m_device->PhysicalDeviceDescriptorIndexingProperties.maxPerStageDescriptorUpdateAfterBindSamplers - 1; + /* + * Unsized arrays require descriptor update-after-bind support + * If device doesn't support it, we fall back to a reasonable maximum + */ + if (m_device->PhysicalDeviceSupportDescriptorUpdateAfterBind) + { + count = m_device->PhysicalDeviceDescriptorIndexingProperties.maxPerStageDescriptorUpdateAfterBindSamplers - 1; + } + else + { + /* + * Fallback: derive a safe maximum from device properties when possible + * Otherwise fall back to a conservative hard limit. + */ + uint32_t fallback_count = 4096; + if (m_device->PhysicalDeviceDescriptorIndexingProperties.maxPerStageDescriptorUpdateAfterBindSamplers > 1) + { + fallback_count = static_cast(m_device->PhysicalDeviceDescriptorIndexingProperties.maxPerStageDescriptorUpdateAfterBindSamplers - 1); + if (fallback_count > 4096) + { + fallback_count = 4096; // cap to reasonable upper bound + } + } + + count = fallback_count; + ZENGINE_CORE_WARN( + "Shader {} uses unsized sampler arrays but device does not support descriptor update-after-bind. " + "Using fallback size of {} descriptors. For full bindless rendering support, use GPUs with descriptor-indexing support.", + m_specification.VertexFilename ? m_specification.VertexFilename : m_specification.FragmentFilename, + count) + } } } @@ -289,12 +319,20 @@ namespace ZEngine::Rendering::Shaders binding_flags_collection.init(&LocalArena, layout_binding_collection.size(), layout_binding_collection.size()); for (uint32_t i = 0; i < layout_binding_collection.size(); ++i) { - if ((layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || (layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)) + if (m_device->PhysicalDeviceSupportDescriptorUpdateAfterBind) { - binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT; - continue; + if ((layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || (layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)) + { + binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT; + continue; + } + binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT; + } + else + { + // Fallback for devices that don't support update-after-bind + binding_flags_collection[i] = 0; } - binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT; } VkDescriptorSetLayoutBindingFlagsCreateInfo binding_flags_create_info = {}; @@ -308,7 +346,7 @@ namespace ZEngine::Rendering::Shaders descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; descriptor_set_layout_create_info.bindingCount = layout_binding_collection.size(); descriptor_set_layout_create_info.pBindings = layout_binding_collection.data(); - descriptor_set_layout_create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; + descriptor_set_layout_create_info.flags = m_device->PhysicalDeviceSupportDescriptorUpdateAfterBind ? VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT : 0; descriptor_set_layout_create_info.pNext = &binding_flags_create_info; VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; @@ -348,7 +386,7 @@ namespace ZEngine::Rendering::Shaders VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; + pool_info.flags = m_device->PhysicalDeviceSupportDescriptorUpdateAfterBind ? VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT : 0; pool_info.maxSets = m_device->SwapchainImageCount * pool_size_collection.size() * m_specification.OverloadMaxSet; pool_info.poolSizeCount = pool_size_collection.size(); pool_info.pPoolSizes = pool_size_collection.data(); From 6dec3111003aa732492e6b26618f17343db9514c Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Tue, 20 Jan 2026 11:34:53 +0900 Subject: [PATCH 03/15] fixed binding name cmp ops --- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 5 +++-- ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp | 2 +- ZEngine/ZEngine/Rendering/Shaders/Shader.cpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index 8c6b384d..95ab807e 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -1103,8 +1103,9 @@ namespace ZEngine::Hardwares if (image_count != SwapchainImageCount) { ZENGINE_CORE_WARN("Max Swapchain image count supported is {}, but requested {}", image_count, SwapchainImageCount); - SwapchainImageCount = image_count; - ZENGINE_CORE_WARN("Swapchain image count has changed from {} to {}", SwapchainImageCount, image_count); + auto old_swapchain_image_count = SwapchainImageCount; + SwapchainImageCount = image_count; + ZENGINE_CORE_WARN("Swapchain image count has changed from {} to {}", old_swapchain_image_count, image_count); } if (SwapchainImageViews.capacity() <= 0) diff --git a/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp b/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp index 2f23a86e..458c00a7 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp @@ -85,7 +85,7 @@ namespace ZEngine::Rendering::Renderers // RenderGraph->AddCallbackPass("Skybox Pass", skybox_pass); RenderGraph->AddCallbackPass("Grid Pass", grid_pass); RenderGraph->AddCallbackPass("G-Buffer Pass", gbuffer_pass); - // RenderGraph->AddCallbackPass("Lighting Pass", lighting_pass); + // RenderGraph->AddCallbackPass("Lighting Pass", lighting_pass); RenderGraph->Setup(); RenderGraph->Compile(); diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp index efe5d75c..faf70158 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp @@ -266,7 +266,7 @@ namespace ZEngine::Rendering::Shaders for (const auto& layout_binding : LayoutBindingSpecificationMap) { const auto& binding_specification_collection = layout_binding.second; - auto find_it = std::find_if(binding_specification_collection.begin(), binding_specification_collection.end(), [&](const LayoutBindingSpecification& spec) { return Helpers::secure_strcmp(spec.Name, name); }); + auto find_it = std::find_if(binding_specification_collection.begin(), binding_specification_collection.end(), [&](const LayoutBindingSpecification& spec) { return Helpers::secure_strcmp(spec.Name, name) == 0; }); if (find_it != std::end(binding_specification_collection)) { From 52a8bf6a3965c889972027d22dfedc21a1009918 Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Tue, 20 Jan 2026 16:06:56 +0000 Subject: [PATCH 04/15] updated bindless logic --- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 27 ++++++++++++++++---- ZEngine/ZEngine/Hardwares/VulkanDevice.h | 3 ++- ZEngine/ZEngine/Rendering/Shaders/Shader.cpp | 23 ++++++++++------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index 95ab807e..1af57b75 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -207,7 +207,18 @@ namespace ZEngine::Hardwares PhysicalDeviceProperties = physical_device_properties; PhysicalDeviceDescriptorIndexingProperties = indexing_properties; PhysicalDeviceFeature = physical_device_feature; - PhysicalDeviceSupportDescriptorUpdateAfterBind = (descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind == VK_TRUE && descriptor_indexing_features.descriptorBindingPartiallyBound == VK_TRUE && descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending == VK_TRUE); + PhysicalDeviceSupportSampledImageBindless = ( + descriptor_indexing_features.runtimeDescriptorArray == VK_TRUE && + descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind == VK_TRUE && + descriptor_indexing_features.descriptorBindingPartiallyBound == VK_TRUE && + descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending == VK_TRUE && + descriptor_indexing_features.descriptorIndexing == VK_TRUE + ); + PhysicalDeviceSupportStorageBufferBindless = ( + descriptor_indexing_features.runtimeDescriptorArray == VK_TRUE && + descriptor_indexing_features.descriptorBindingPartiallyBound == VK_TRUE && + descriptor_indexing_features.descriptorIndexing == VK_TRUE + ); vkGetPhysicalDeviceMemoryProperties(PhysicalDevice, &PhysicalDeviceMemoryProperties); break; } @@ -312,13 +323,19 @@ namespace ZEngine::Hardwares device_features_2.features.multiDrawIndirect = PhysicalDeviceFeature.features.multiDrawIndirect; device_features_2.features.samplerAnisotropy = PhysicalDeviceFeature.features.samplerAnisotropy; device_features_2.features.shaderInt64 = PhysicalDeviceFeature.features.shaderInt64; - if (PhysicalDeviceSupportDescriptorUpdateAfterBind) + + if (PhysicalDeviceSupportSampledImageBindless || PhysicalDeviceSupportStorageBufferBindless) { - physical_device_descriptor_indexing_features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; - physical_device_descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE; - physical_device_descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending = VK_TRUE; + if (PhysicalDeviceSupportSampledImageBindless) + { + physical_device_descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending = VK_TRUE; + physical_device_descriptor_indexing_features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; + physical_device_descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE; + } + physical_device_descriptor_indexing_features.descriptorBindingPartiallyBound = VK_TRUE; physical_device_descriptor_indexing_features.runtimeDescriptorArray = VK_TRUE; + physical_device_descriptor_indexing_features.descriptorIndexing = VK_TRUE; device_features_2.pNext = &physical_device_descriptor_indexing_features; } diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.h b/ZEngine/ZEngine/Hardwares/VulkanDevice.h index d90c1a99..3762c99a 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.h +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.h @@ -535,7 +535,8 @@ namespace ZEngine::Hardwares struct VulkanDevice { bool HasSeperateTransfertQueueFamily = false; - bool PhysicalDeviceSupportDescriptorUpdateAfterBind = false; + bool PhysicalDeviceSupportSampledImageBindless = false; + bool PhysicalDeviceSupportStorageBufferBindless = false; const char* ApplicationName = "Tetragrama"; const char* EngineName = "ZEngine"; uint32_t SwapchainImageCount = 3; diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp index faf70158..3c8f84db 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp @@ -220,7 +220,7 @@ namespace ZEngine::Rendering::Shaders * Unsized arrays require descriptor update-after-bind support * If device doesn't support it, we fall back to a reasonable maximum */ - if (m_device->PhysicalDeviceSupportDescriptorUpdateAfterBind) + if (m_device->PhysicalDeviceSupportSampledImageBindless) { count = m_device->PhysicalDeviceDescriptorIndexingProperties.maxPerStageDescriptorUpdateAfterBindSamplers - 1; } @@ -319,14 +319,15 @@ namespace ZEngine::Rendering::Shaders binding_flags_collection.init(&LocalArena, layout_binding_collection.size(), layout_binding_collection.size()); for (uint32_t i = 0; i < layout_binding_collection.size(); ++i) { - if (m_device->PhysicalDeviceSupportDescriptorUpdateAfterBind) + if (m_device->PhysicalDeviceSupportSampledImageBindless + && ((layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || (layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE))) { - if ((layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || (layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)) - { binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT; continue; - } - binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT; + } + else if (m_device->PhysicalDeviceSupportStorageBufferBindless && (layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)) + { + binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; } else { @@ -346,8 +347,12 @@ namespace ZEngine::Rendering::Shaders descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; descriptor_set_layout_create_info.bindingCount = layout_binding_collection.size(); descriptor_set_layout_create_info.pBindings = layout_binding_collection.data(); - descriptor_set_layout_create_info.flags = m_device->PhysicalDeviceSupportDescriptorUpdateAfterBind ? VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT : 0; - descriptor_set_layout_create_info.pNext = &binding_flags_create_info; + + if (m_device->PhysicalDeviceSupportSampledImageBindless) + { + descriptor_set_layout_create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; + descriptor_set_layout_create_info.pNext = &binding_flags_create_info; + } VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; ZENGINE_VALIDATE_ASSERT(vkCreateDescriptorSetLayout(m_device->LogicalDevice, &descriptor_set_layout_create_info, nullptr, &descriptor_set_layout) == VK_SUCCESS, "Failed to create DescriptorSetLayout") @@ -386,7 +391,7 @@ namespace ZEngine::Rendering::Shaders VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.flags = m_device->PhysicalDeviceSupportDescriptorUpdateAfterBind ? VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT : 0; + pool_info.flags = m_device->PhysicalDeviceSupportSampledImageBindless ? VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT : 0; pool_info.maxSets = m_device->SwapchainImageCount * pool_size_collection.size() * m_specification.OverloadMaxSet; pool_info.poolSizeCount = pool_size_collection.size(); pool_info.pPoolSizes = pool_size_collection.data(); From 8ca0cc02477ecc6a62ccfd90bf4bb5dd85756926 Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Wed, 21 Jan 2026 01:22:05 +0900 Subject: [PATCH 05/15] fixed missing props --- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 31 ++--- ZEngine/ZEngine/Hardwares/VulkanDevice.h | 118 +++++++++---------- ZEngine/ZEngine/Rendering/Shaders/Shader.cpp | 15 ++- 3 files changed, 76 insertions(+), 88 deletions(-) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index 1af57b75..6fe29e76 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -203,22 +203,12 @@ namespace ZEngine::Hardwares if (/*(physical_device_feature.geometryShader == VK_TRUE) && (physical_device_feature.samplerAnisotropy == VK_TRUE) && */ ((physical_device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) || (physical_device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU))) { - PhysicalDevice = physical_device; - PhysicalDeviceProperties = physical_device_properties; - PhysicalDeviceDescriptorIndexingProperties = indexing_properties; - PhysicalDeviceFeature = physical_device_feature; - PhysicalDeviceSupportSampledImageBindless = ( - descriptor_indexing_features.runtimeDescriptorArray == VK_TRUE && - descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind == VK_TRUE && - descriptor_indexing_features.descriptorBindingPartiallyBound == VK_TRUE && - descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending == VK_TRUE && - descriptor_indexing_features.descriptorIndexing == VK_TRUE - ); - PhysicalDeviceSupportStorageBufferBindless = ( - descriptor_indexing_features.runtimeDescriptorArray == VK_TRUE && - descriptor_indexing_features.descriptorBindingPartiallyBound == VK_TRUE && - descriptor_indexing_features.descriptorIndexing == VK_TRUE - ); + PhysicalDevice = physical_device; + PhysicalDeviceProperties = physical_device_properties; + PhysicalDeviceDescriptorIndexingProperties = indexing_properties; + PhysicalDeviceFeature = physical_device_feature; + PhysicalDeviceSupportSampledImageBindless = (descriptor_indexing_features.runtimeDescriptorArray == VK_TRUE && descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind == VK_TRUE && descriptor_indexing_features.descriptorBindingPartiallyBound == VK_TRUE && descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending == VK_TRUE); + PhysicalDeviceSupportStorageBufferBindless = (descriptor_indexing_features.runtimeDescriptorArray == VK_TRUE && descriptor_indexing_features.descriptorBindingPartiallyBound == VK_TRUE); vkGetPhysicalDeviceMemoryProperties(PhysicalDevice, &PhysicalDeviceMemoryProperties); break; } @@ -332,12 +322,11 @@ namespace ZEngine::Hardwares physical_device_descriptor_indexing_features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; physical_device_descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE; } - - physical_device_descriptor_indexing_features.descriptorBindingPartiallyBound = VK_TRUE; - physical_device_descriptor_indexing_features.runtimeDescriptorArray = VK_TRUE; - physical_device_descriptor_indexing_features.descriptorIndexing = VK_TRUE; - device_features_2.pNext = &physical_device_descriptor_indexing_features; + physical_device_descriptor_indexing_features.descriptorBindingPartiallyBound = VK_TRUE; + physical_device_descriptor_indexing_features.runtimeDescriptorArray = VK_TRUE; + + device_features_2.pNext = &physical_device_descriptor_indexing_features; } device_create_info.pNext = &device_features_2; diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.h b/ZEngine/ZEngine/Hardwares/VulkanDevice.h index 3762c99a..019307dc 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.h +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.h @@ -534,65 +534,65 @@ namespace ZEngine::Hardwares */ struct VulkanDevice { - bool HasSeperateTransfertQueueFamily = false; - bool PhysicalDeviceSupportSampledImageBindless = false; - bool PhysicalDeviceSupportStorageBufferBindless = false; - const char* ApplicationName = "Tetragrama"; - const char* EngineName = "ZEngine"; - uint32_t SwapchainImageCount = 3; - uint32_t SwapchainImageIndex = std::numeric_limits::max(); - uint32_t CurrentFrameIndex = std::numeric_limits::max(); - uint32_t PreviousFrameIndex = std::numeric_limits::max(); - uint32_t SwapchainImageWidth = std::numeric_limits::max(); - uint32_t SwapchainImageHeight = std::numeric_limits::max(); - uint32_t GraphicFamilyIndex = std::numeric_limits::max(); - uint32_t TransferFamilyIndex = std::numeric_limits::max(); - uint32_t EnqueuedCommandbufferIndex = 0; - uint32_t WriteDescriptorSetIndex = 0; - VkInstance Instance = VK_NULL_HANDLE; - VkSurfaceKHR Surface = VK_NULL_HANDLE; - VkSurfaceFormatKHR SurfaceFormat = {}; - VkPresentModeKHR PresentMode = {}; - VkPhysicalDeviceProperties PhysicalDeviceProperties = {}; - VkPhysicalDeviceDescriptorIndexingProperties PhysicalDeviceDescriptorIndexingProperties = {}; - VkDevice LogicalDevice = VK_NULL_HANDLE; - VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE; - VkPhysicalDeviceFeatures2 PhysicalDeviceFeature = {}; - VkPhysicalDeviceMemoryProperties PhysicalDeviceMemoryProperties = {}; - VkSwapchainKHR SwapchainHandle = VK_NULL_HANDLE; - VmaAllocator VmaAllocatorValue = nullptr; - Core::Containers::Array DefaultDepthFormats = {}; - Rendering::Renderers::RenderPasses::Attachment* SwapchainAttachment = {}; - Core::Containers::Array SwapchainImageViews = {}; - Core::Containers::Array SwapchainFramebuffers = {}; - Core::Containers::Array SwapchainAcquiredSemaphores = {}; - Core::Containers::Array SwapchainRenderCompleteSemaphores = {}; - Core::Containers::Array SwapchainSignalFences = {}; - Core::Containers::Array EnqueuedCommandbuffers = {}; - Core::Containers::HashMap> ShaderCaches = {}; - std::set WriteBindlessDescriptorSetRequests = {}; - Rendering::Textures::TextureHandleManager GlobalTextures = {}; - Helpers::HandleManager Image2DBufferManager = {}; - Helpers::ThreadSafeQueue TextureHandleToUpdates = {}; - Helpers::ThreadSafeQueue TextureHandleToDispose = {}; - Helpers::HandleManager ShaderManager = {}; - Helpers::HandleManager VertexBufferSetManager = {}; - Helpers::HandleManager StorageBufferSetManager = {}; - Helpers::HandleManager IndirectBufferSetManager = {}; - Helpers::HandleManager IndexBufferSetManager = {}; - Helpers::HandleManager UniformBufferSetManager = {}; - Helpers::HandleManager DirtyResources = {}; - Helpers::HandleManager DirtyBuffers = {}; - Helpers::HandleManager DirtyBufferImages = {}; - std::atomic_bool RunningDirtyCollector = true; - std::atomic_uint IdleFrameCount = 0; - std::atomic_uint IdleFrameThreshold = SwapchainImageCount * 3 * 3; - std::condition_variable DirtyCollectorCond = {}; - std::mutex DirtyMutex = {}; - std::mutex Mutex = {}; - Windows::CoreWindow* CurrentWindow = nullptr; - ZEngine::Core::Memory::ArenaAllocator* Arena = nullptr; - AsyncResourceLoaderPtr AsyncResLoader = nullptr; + bool HasSeperateTransfertQueueFamily = false; + bool PhysicalDeviceSupportSampledImageBindless = false; + bool PhysicalDeviceSupportStorageBufferBindless = false; + const char* ApplicationName = "Tetragrama"; + const char* EngineName = "ZEngine"; + uint32_t SwapchainImageCount = 3; + uint32_t SwapchainImageIndex = std::numeric_limits::max(); + uint32_t CurrentFrameIndex = std::numeric_limits::max(); + uint32_t PreviousFrameIndex = std::numeric_limits::max(); + uint32_t SwapchainImageWidth = std::numeric_limits::max(); + uint32_t SwapchainImageHeight = std::numeric_limits::max(); + uint32_t GraphicFamilyIndex = std::numeric_limits::max(); + uint32_t TransferFamilyIndex = std::numeric_limits::max(); + uint32_t EnqueuedCommandbufferIndex = 0; + uint32_t WriteDescriptorSetIndex = 0; + VkInstance Instance = VK_NULL_HANDLE; + VkSurfaceKHR Surface = VK_NULL_HANDLE; + VkSurfaceFormatKHR SurfaceFormat = {}; + VkPresentModeKHR PresentMode = {}; + VkPhysicalDeviceProperties PhysicalDeviceProperties = {}; + VkPhysicalDeviceDescriptorIndexingProperties PhysicalDeviceDescriptorIndexingProperties = {}; + VkDevice LogicalDevice = VK_NULL_HANDLE; + VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE; + VkPhysicalDeviceFeatures2 PhysicalDeviceFeature = {}; + VkPhysicalDeviceMemoryProperties PhysicalDeviceMemoryProperties = {}; + VkSwapchainKHR SwapchainHandle = VK_NULL_HANDLE; + VmaAllocator VmaAllocatorValue = nullptr; + Core::Containers::Array DefaultDepthFormats = {}; + Rendering::Renderers::RenderPasses::Attachment* SwapchainAttachment = {}; + Core::Containers::Array SwapchainImageViews = {}; + Core::Containers::Array SwapchainFramebuffers = {}; + Core::Containers::Array SwapchainAcquiredSemaphores = {}; + Core::Containers::Array SwapchainRenderCompleteSemaphores = {}; + Core::Containers::Array SwapchainSignalFences = {}; + Core::Containers::Array EnqueuedCommandbuffers = {}; + Core::Containers::HashMap> ShaderCaches = {}; + std::set WriteBindlessDescriptorSetRequests = {}; + Rendering::Textures::TextureHandleManager GlobalTextures = {}; + Helpers::HandleManager Image2DBufferManager = {}; + Helpers::ThreadSafeQueue TextureHandleToUpdates = {}; + Helpers::ThreadSafeQueue TextureHandleToDispose = {}; + Helpers::HandleManager ShaderManager = {}; + Helpers::HandleManager VertexBufferSetManager = {}; + Helpers::HandleManager StorageBufferSetManager = {}; + Helpers::HandleManager IndirectBufferSetManager = {}; + Helpers::HandleManager IndexBufferSetManager = {}; + Helpers::HandleManager UniformBufferSetManager = {}; + Helpers::HandleManager DirtyResources = {}; + Helpers::HandleManager DirtyBuffers = {}; + Helpers::HandleManager DirtyBufferImages = {}; + std::atomic_bool RunningDirtyCollector = true; + std::atomic_uint IdleFrameCount = 0; + std::atomic_uint IdleFrameThreshold = SwapchainImageCount * 3 * 3; + std::condition_variable DirtyCollectorCond = {}; + std::mutex DirtyMutex = {}; + std::mutex Mutex = {}; + Windows::CoreWindow* CurrentWindow = nullptr; + ZEngine::Core::Memory::ArenaAllocator* Arena = nullptr; + AsyncResourceLoaderPtr AsyncResLoader = nullptr; void Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, Windows::CoreWindow* const window); void Deinitialize(); diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp index 3c8f84db..ca313180 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp @@ -319,11 +319,10 @@ namespace ZEngine::Rendering::Shaders binding_flags_collection.init(&LocalArena, layout_binding_collection.size(), layout_binding_collection.size()); for (uint32_t i = 0; i < layout_binding_collection.size(); ++i) { - if (m_device->PhysicalDeviceSupportSampledImageBindless - && ((layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || (layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE))) + if (m_device->PhysicalDeviceSupportSampledImageBindless && ((layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || (layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE))) { - binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT; - continue; + binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT; + continue; } else if (m_device->PhysicalDeviceSupportStorageBufferBindless && (layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)) { @@ -347,14 +346,14 @@ namespace ZEngine::Rendering::Shaders descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; descriptor_set_layout_create_info.bindingCount = layout_binding_collection.size(); descriptor_set_layout_create_info.pBindings = layout_binding_collection.data(); - + if (m_device->PhysicalDeviceSupportSampledImageBindless) { - descriptor_set_layout_create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; - descriptor_set_layout_create_info.pNext = &binding_flags_create_info; + descriptor_set_layout_create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; + descriptor_set_layout_create_info.pNext = &binding_flags_create_info; } - VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; + VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; ZENGINE_VALIDATE_ASSERT(vkCreateDescriptorSetLayout(m_device->LogicalDevice, &descriptor_set_layout_create_info, nullptr, &descriptor_set_layout) == VK_SUCCESS, "Failed to create DescriptorSetLayout") DescriptorSetLayoutMap[binding_set] = std::move(descriptor_set_layout); From 9ba8690cf1bcd0ef4a234944ee351d6496d1743a Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Wed, 21 Jan 2026 01:51:25 +0900 Subject: [PATCH 06/15] simplified expr --- ZEngine/ZEngine/Rendering/Shaders/Shader.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp index ca313180..a84556f1 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp @@ -319,20 +319,15 @@ namespace ZEngine::Rendering::Shaders binding_flags_collection.init(&LocalArena, layout_binding_collection.size(), layout_binding_collection.size()); for (uint32_t i = 0; i < layout_binding_collection.size(); ++i) { + binding_flags_collection[i] = 0; // We zeroing as we iterate if (m_device->PhysicalDeviceSupportSampledImageBindless && ((layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || (layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE))) { binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT; - continue; } else if (m_device->PhysicalDeviceSupportStorageBufferBindless && (layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)) { binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; } - else - { - // Fallback for devices that don't support update-after-bind - binding_flags_collection[i] = 0; - } } VkDescriptorSetLayoutBindingFlagsCreateInfo binding_flags_create_info = {}; From 437ecfd4f0743831f365f3c4831dcef14c1ead15 Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Mon, 26 Jan 2026 22:13:17 +0900 Subject: [PATCH 07/15] reduced descriptorset usage --- Resources/Shaders/fragment_common.glsl | 2 +- Resources/Shaders/imgui.frag | 3 +- ZEngine/ZEngine/Core/Containers/HashMap.h | 97 +++----- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 128 +++++++++- ZEngine/ZEngine/Hardwares/VulkanDevice.h | 219 +++++++++--------- .../Rendering/Renderers/ImGUIRenderer.cpp | 4 +- .../Rendering/Renderers/RenderGraph.cpp | 6 +- ZEngine/ZEngine/Rendering/Shaders/Shader.cpp | 105 +++++---- ZEngine/ZEngine/Rendering/Shaders/Shader.h | 28 +-- 9 files changed, 350 insertions(+), 242 deletions(-) diff --git a/Resources/Shaders/fragment_common.glsl b/Resources/Shaders/fragment_common.glsl index 9da28f92..5bb2c05a 100644 --- a/Resources/Shaders/fragment_common.glsl +++ b/Resources/Shaders/fragment_common.glsl @@ -61,7 +61,7 @@ layout(std140, set = 0, binding = 5) readonly buffer MatSB } MaterialDataBuffer; -layout(set = 0, binding = 9) uniform sampler2D TextureArray[]; +layout(set = 1, binding = 0) uniform sampler2D TextureArray[]; MaterialData FetchMaterial(uint dataIndex) { diff --git a/Resources/Shaders/imgui.frag b/Resources/Shaders/imgui.frag index 1d95a80e..6ce0502e 100644 --- a/Resources/Shaders/imgui.frag +++ b/Resources/Shaders/imgui.frag @@ -3,7 +3,8 @@ #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable layout(location = 0) out vec4 fColor; -layout(set = 0, binding = 0) uniform sampler2D TextureArray[]; +layout(set = 0, binding = 0) uniform sampler2D _unused; +layout(set = 1, binding = 0) uniform sampler2D TextureArray[]; layout(location = 0) in struct { diff --git a/ZEngine/ZEngine/Core/Containers/HashMap.h b/ZEngine/ZEngine/Core/Containers/HashMap.h index 5d349a7d..4d74deec 100644 --- a/ZEngine/ZEngine/Core/Containers/HashMap.h +++ b/ZEngine/ZEngine/Core/Containers/HashMap.h @@ -32,17 +32,17 @@ namespace ZEngine::Core::Containers { public: using Entry = HashEntry; - using ArrayType = std::conditional_t, Array>; - using value_type = std::conditional_t, std::pair>; + using EntryPointer = std::conditional_t; + using value_type = std::conditional_t, std::pair>; using reference = value_type; using pointer = value_type*; - using iterator_category = std::forward_iterator_tag; + using iterator_category = std::input_iterator_tag; using difference_type = std::ptrdiff_t; // Constructs an iterator for the hash map's entries, starting at the given index. - // @param entries Reference to the array of hash map entries. + // @param entries Value to the array of hash map entries. // @param index Starting index for iteration. - HashMapIterator(ArrayType& entries, std::size_t index) : m_entries(entries), m_index(index) + HashMapIterator(EntryPointer entries, std::size_t index, std::size_t size) : m_entries(entries), m_index(index), m_size(size) { advance_to_valid(); } @@ -91,22 +91,22 @@ namespace ZEngine::Core::Containers // @return A pointer to a temporary key-value pair. pointer operator->() const { - static value_type temp = **this; - return &temp; + return std::addressof(**this); } private: // Advances the iterator to the next occupied entry, skipping empty or deleted entries. void advance_to_valid() { - while (m_index < m_entries.size() && m_entries[m_index].state != EntryState::Occupied) + while (m_index < m_size && m_entries[m_index].state != EntryState::Occupied) { ++m_index; } } - ArrayType& m_entries; - std::size_t m_index; + EntryPointer m_entries; + std::size_t m_index; + std::size_t m_size; }; template @@ -122,11 +122,11 @@ namespace ZEngine::Core::Containers // @param allocator Pointer to the arena allocator for memory management. // @param initial_capacity Initial number of slots (default: 16). // @param load_factor Maximum load factor before resizing (default: 0.75). - void init(Memory::ArenaAllocator* allocator, size_type initial_capacity = 32) + void init(Memory::ArenaAllocator* allocator, size_type initial_capacity = 16) { m_allocator = allocator; m_load_factor = 0.75f; - m_entries.init(m_allocator, initial_capacity, 0); + m_entries.init(m_allocator, initial_capacity); for (size_type i = 0; i < initial_capacity; ++i) { m_entries.push({}); @@ -146,12 +146,6 @@ namespace ZEngine::Core::Containers size_type index = probe_for_insert(key); auto& entry = m_entries[index]; - if (entry.state == EntryState::Occupied && key_equals(entry.key, key)) - { - entry.value = value; // Update existing key - return; - } - if (entry.state == EntryState::Empty || entry.state == EntryState::Deleted) { entry.key = key; @@ -161,15 +155,10 @@ namespace ZEngine::Core::Containers } else { - throw std::runtime_error("HashMap insert failed: table full"); + entry.value = value; } } - // Accesses or inserts a value for a key, returning a reference to the value. - // Inserts a default-constructed value if the key is not found. - // @param key The key to access or insert. - // @return Reference to the associated value. - // @throws std::runtime_error if the table is full and cannot be resized. V& operator[](const K& key) { maybe_grow(); @@ -184,11 +173,6 @@ namespace ZEngine::Core::Containers entry.state = EntryState::Occupied; ++m_size; } - else if (entry.state == EntryState::Occupied && entry.key != key) - { - throw std::runtime_error("HashMap insert failed: table full"); - } - return entry.value; } @@ -282,14 +266,14 @@ namespace ZEngine::Core::Containers // @note Iterators are invalidated by insert, remove, or reserve operations. iterator begin() { - return iterator(m_entries, 0); + return iterator(m_entries.data(), 0, m_entries.size()); } // Returns an iterator to the end of the hash map. // @return Iterator representing the past-the-end position. iterator end() { - return iterator(m_entries, m_entries.size()); + return iterator(m_entries.data(), m_entries.size(), m_entries.size()); } // Returns a const iterator to the first occupied entry. @@ -297,14 +281,14 @@ namespace ZEngine::Core::Containers // @note Iterators are invalidated by insert, remove, or reserve operations. const_iterator begin() const { - return const_iterator(m_entries, 0); + return const_iterator(m_entries.data(), 0, m_entries.size()); } // Returns a const iterator to the end of the hash map. // @return Const iterator representing the past-the-end position. const_iterator end() const { - return const_iterator(m_entries, m_entries.size()); + return const_iterator(m_entries.data(), m_entries.size(), m_entries.size()); } // Returns a const iterator to the first occupied entry (alias for begin() const). @@ -339,7 +323,7 @@ namespace ZEngine::Core::Containers { if (static_cast(m_size + 1) / m_entries.size() > m_load_factor) { - size_type new_capacity = std::max(16, m_entries.size() * 3 / 2); // Growth factor 1.5 + size_type new_capacity = std::max(16, static_cast(m_entries.size() * 1.5f)); // Growth factor 1.5 rehash(new_capacity); } } @@ -364,18 +348,20 @@ namespace ZEngine::Core::Containers { Array old_entries = m_entries; // Move to avoid copying m_entries = Array{}; - m_entries.init(m_allocator, new_capacity, 0); + m_entries.init(m_allocator, new_capacity); for (size_type i = 0; i < new_capacity; ++i) { m_entries.push({}); } m_size = 0; - for (const auto& entry : old_entries) + for (size_type i = 0; i < old_entries.size(); ++i) { - if (entry.state == EntryState::Occupied) + if (old_entries[i].state == EntryState::Occupied) { - insert(entry.key, entry.value); + size_type index = probe_for_insert(old_entries[i].key); + m_entries[index] = old_entries[i]; // Direct assignment + ++m_size; } } } @@ -386,8 +372,6 @@ namespace ZEngine::Core::Containers size_type probe_for_key(const K& key) const { size_type index = hash(key) % m_entries.size(); - size_type step = double_hash(key); - size_type start = index; size_type i = 0; do @@ -401,9 +385,9 @@ namespace ZEngine::Core::Containers { return index; } - index = (index + step) % m_entries.size(); ++i; - } while (index != start && i < m_entries.size()); + index = (index + i) % m_entries.size(); + } while (i < m_entries.size()); return size_type(-1); } @@ -415,47 +399,36 @@ namespace ZEngine::Core::Containers size_type probe_for_insert(const K& key) { size_type index = hash(key) % m_entries.size(); - size_type step = double_hash(key); - size_type start = index; size_type first_deleted = size_type(-1); size_type i = 0; do { auto& entry = m_entries[index]; + if (entry.state == EntryState::Occupied && key_equals(entry.key, key)) + { + return index; + } + if (entry.state == EntryState::Empty) { return (first_deleted != size_type(-1)) ? first_deleted : index; } + if (entry.state == EntryState::Deleted && first_deleted == size_type(-1)) { first_deleted = index; } - else if (entry.state == EntryState::Occupied && key_equals(entry.key, key)) - { - return index; - } - index = (index + step) % m_entries.size(); + ++i; - } while (index != start && i < m_entries.size()); + index = (index + i) % m_entries.size(); + } while (i < m_entries.size()); if (first_deleted != size_type(-1)) { return first_deleted; } - // Debug table state on failure - size_type empty_count = 0, deleted_count = 0, occupied_count = 0; - for (const auto& entry : m_entries) - { - if (entry.state == EntryState::Empty) - ++empty_count; - else if (entry.state == EntryState::Deleted) - ++deleted_count; - else if (entry.state == EntryState::Occupied) - ++occupied_count; - } - throw std::runtime_error("HashMap probe failed: table full"); } diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index 6fe29e76..50984234 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -27,17 +27,16 @@ namespace ZEngine::Hardwares { void VulkanDevice::Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, Windows::CoreWindow* const window) { - Arena = arena; - CurrentWindow = window; - AsyncResLoader = ZPushStructCtor(Arena, AsyncResourceLoader); + Arena = arena; + CurrentWindow = window; + ShaderReservedBindingSets = {1}; // Todo: we should introduce HashSet<> + AsyncResLoader = ZPushStructCtor(Arena, AsyncResourceLoader); DefaultDepthFormats.init(Arena, 3); DefaultDepthFormats.push(VK_FORMAT_D32_SFLOAT); DefaultDepthFormats.push(VK_FORMAT_D32_SFLOAT_S8_UINT); DefaultDepthFormats.push(VK_FORMAT_D24_UNORM_S8_UINT); - GlobalTextures.Initialize(arena, 600); - Image2DBufferManager.Initialize(arena, 600); ShaderManager.Initialize(arena, 300); VertexBufferSetManager.Initialize(arena, 300); StorageBufferSetManager.Initialize(arena, 300); @@ -441,6 +440,113 @@ namespace ZEngine::Hardwares } CreateSwapchain(); + /* + * Creating Global Descriptor Pool for : Textures + */ + MaxGlobalTexture = std::min(MaxGlobalTexture, PhysicalDeviceDescriptorIndexingProperties.maxDescriptorSetUpdateAfterBindSamplers - 1); + + GlobalTextures.Initialize(Arena, MaxGlobalTexture); + Image2DBufferManager.Initialize(Arena, MaxGlobalTexture); + ShaderReservedLayoutBindingSpecificationMap.init(Arena, 1); + + ShaderReservedLayoutBindingSpecificationMap[1].init(Arena, 1); + ShaderReservedLayoutBindingSpecificationMap[1].push(LayoutBindingSpecification{.Set = 1, .Binding = 0, .Count = MaxGlobalTexture, .Name = "TextureArray", .DescriptorTypeValue = DescriptorType::COMBINED_IMAGE_SAMPLER, .Flags = ShaderStageFlags::FRAGMENT}); + + ShaderReservedDescriptorSetMap.init(Arena, ShaderReservedLayoutBindingSpecificationMap.size()); + ShaderReservedDescriptorSetLayoutMap.init(Arena, ShaderReservedLayoutBindingSpecificationMap.size()); + + VkDescriptorPoolSize pool_sizes[] = { + {.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = (MaxGlobalTexture * SwapchainImageCount)} + }; + + for (const auto& layout_binding_set : ShaderReservedLayoutBindingSpecificationMap) + { + scratch = ZGetScratch(Arena); + + Array layout_bindings = {}; + + uint32_t binding_spec_count = layout_binding_set.second.size(); + layout_bindings.init(scratch.Arena, binding_spec_count, binding_spec_count); + for (uint32_t i = 0; i < binding_spec_count; ++i) + { + auto& binding_spec = layout_binding_set.second[i]; + + layout_bindings[i] = VkDescriptorSetLayoutBinding{.binding = binding_spec.Binding, .descriptorType = DescriptorTypeMap[VALUE_FROM_SPEC_MAP(binding_spec.DescriptorTypeValue)], .descriptorCount = binding_spec.Count, .stageFlags = ShaderStageFlagsMap[VALUE_FROM_SPEC_MAP(binding_spec.Flags)], .pImmutableSamplers = nullptr}; + } + + Array binding_flags = {}; + binding_flags.init(scratch.Arena, layout_bindings.size(), layout_bindings.size()); + + for (uint32_t i = 0; i < layout_bindings.size(); ++i) + { + binding_flags[i] = 0; // We zeroing as we iterate + + if (PhysicalDeviceSupportSampledImageBindless && ((layout_bindings[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || (layout_bindings[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE))) + { + binding_flags[i] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT; + } + else if (PhysicalDeviceSupportStorageBufferBindless && (layout_bindings[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)) + { + binding_flags[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; + } + } + VkDescriptorSetLayoutBindingFlagsCreateInfo binding_flags_create_info = {}; + binding_flags_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; + binding_flags_create_info.bindingCount = binding_flags.size(); + binding_flags_create_info.pBindingFlags = binding_flags.data(); + /* + * Creating SetLayout + */ + VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info = {}; + descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptor_set_layout_create_info.bindingCount = layout_bindings.size(); + descriptor_set_layout_create_info.pBindings = layout_bindings.data(); + if (PhysicalDeviceSupportSampledImageBindless) + { + descriptor_set_layout_create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; + descriptor_set_layout_create_info.pNext = &binding_flags_create_info; + } + VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; + ZENGINE_VALIDATE_ASSERT(vkCreateDescriptorSetLayout(LogicalDevice, &descriptor_set_layout_create_info, nullptr, &descriptor_set_layout) == VK_SUCCESS, "Failed to create DescriptorSetLayout") + + ZReleaseScratch(scratch); + + ShaderReservedDescriptorSetLayoutMap.insert(layout_binding_set.first, descriptor_set_layout); + } + + VkDescriptorPoolCreateInfo pool_info = {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; + pool_info.flags = PhysicalDeviceSupportSampledImageBindless ? VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT : 0; + pool_info.maxSets = SwapchainImageCount; + pool_info.poolSizeCount = sizeof(pool_sizes) / sizeof(VkDescriptorPoolSize); + pool_info.pPoolSizes = pool_sizes; + ZENGINE_VALIDATE_ASSERT(vkCreateDescriptorPool(LogicalDevice, &pool_info, nullptr, &GlobalDescriptorPoolHandle) == VK_SUCCESS, "Failed to create Global DescriptorPool") + + for (const auto& layout : ShaderReservedDescriptorSetLayoutMap) + { + ShaderReservedDescriptorSetMap[layout.first].init(Arena, SwapchainImageCount, SwapchainImageCount); + } + + scratch = ZGetScratch(Arena); + + for (const auto& layout : ShaderReservedDescriptorSetLayoutMap) + { + Array layout_set = {}; + layout_set.init(scratch.Arena, SwapchainImageCount, SwapchainImageCount); + for (uint32_t i = 0; i < SwapchainImageCount; ++i) + { + layout_set[i] = layout.second; + } + + VkDescriptorSetAllocateInfo descriptor_set_allocate_info = {}; + descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptor_set_allocate_info.descriptorPool = GlobalDescriptorPoolHandle; + descriptor_set_allocate_info.descriptorSetCount = SwapchainImageCount; + descriptor_set_allocate_info.pSetLayouts = layout_set.data(); + ZENGINE_VALIDATE_ASSERT(vkAllocateDescriptorSets(LogicalDevice, &descriptor_set_allocate_info, ShaderReservedDescriptorSetMap[layout.first].data()) == VK_SUCCESS, "Failed to create DescriptorSet") + } + + ZReleaseScratch(scratch); + AsyncResLoader->Initialize(this); ThreadPoolHelper::Submit([this] { DirtyCollector(); }); @@ -479,6 +585,18 @@ namespace ZEngine::Hardwares m_buffer_manager.Deinitialize(); + for (auto set_layout : ShaderReservedDescriptorSetLayoutMap) + { + EnqueueForDeletion(Rendering::DeviceResourceType::DESCRIPTORSETLAYOUT, set_layout.second); + } + ShaderReservedDescriptorSetLayoutMap.clear(); + + if (GlobalDescriptorPoolHandle) + { + EnqueueForDeletion(Rendering::DeviceResourceType::DESCRIPTORPOOL, GlobalDescriptorPoolHandle); + GlobalDescriptorPoolHandle = VK_NULL_HANDLE; + } + __cleanupBufferDirtyResource(); __cleanupBufferImageDirtyResource(); diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.h b/ZEngine/ZEngine/Hardwares/VulkanDevice.h index 019307dc..c4810f7d 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.h +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include // clang-format on @@ -534,112 +535,118 @@ namespace ZEngine::Hardwares */ struct VulkanDevice { - bool HasSeperateTransfertQueueFamily = false; - bool PhysicalDeviceSupportSampledImageBindless = false; - bool PhysicalDeviceSupportStorageBufferBindless = false; - const char* ApplicationName = "Tetragrama"; - const char* EngineName = "ZEngine"; - uint32_t SwapchainImageCount = 3; - uint32_t SwapchainImageIndex = std::numeric_limits::max(); - uint32_t CurrentFrameIndex = std::numeric_limits::max(); - uint32_t PreviousFrameIndex = std::numeric_limits::max(); - uint32_t SwapchainImageWidth = std::numeric_limits::max(); - uint32_t SwapchainImageHeight = std::numeric_limits::max(); - uint32_t GraphicFamilyIndex = std::numeric_limits::max(); - uint32_t TransferFamilyIndex = std::numeric_limits::max(); - uint32_t EnqueuedCommandbufferIndex = 0; - uint32_t WriteDescriptorSetIndex = 0; - VkInstance Instance = VK_NULL_HANDLE; - VkSurfaceKHR Surface = VK_NULL_HANDLE; - VkSurfaceFormatKHR SurfaceFormat = {}; - VkPresentModeKHR PresentMode = {}; - VkPhysicalDeviceProperties PhysicalDeviceProperties = {}; - VkPhysicalDeviceDescriptorIndexingProperties PhysicalDeviceDescriptorIndexingProperties = {}; - VkDevice LogicalDevice = VK_NULL_HANDLE; - VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE; - VkPhysicalDeviceFeatures2 PhysicalDeviceFeature = {}; - VkPhysicalDeviceMemoryProperties PhysicalDeviceMemoryProperties = {}; - VkSwapchainKHR SwapchainHandle = VK_NULL_HANDLE; - VmaAllocator VmaAllocatorValue = nullptr; - Core::Containers::Array DefaultDepthFormats = {}; - Rendering::Renderers::RenderPasses::Attachment* SwapchainAttachment = {}; - Core::Containers::Array SwapchainImageViews = {}; - Core::Containers::Array SwapchainFramebuffers = {}; - Core::Containers::Array SwapchainAcquiredSemaphores = {}; - Core::Containers::Array SwapchainRenderCompleteSemaphores = {}; - Core::Containers::Array SwapchainSignalFences = {}; - Core::Containers::Array EnqueuedCommandbuffers = {}; - Core::Containers::HashMap> ShaderCaches = {}; - std::set WriteBindlessDescriptorSetRequests = {}; - Rendering::Textures::TextureHandleManager GlobalTextures = {}; - Helpers::HandleManager Image2DBufferManager = {}; - Helpers::ThreadSafeQueue TextureHandleToUpdates = {}; - Helpers::ThreadSafeQueue TextureHandleToDispose = {}; - Helpers::HandleManager ShaderManager = {}; - Helpers::HandleManager VertexBufferSetManager = {}; - Helpers::HandleManager StorageBufferSetManager = {}; - Helpers::HandleManager IndirectBufferSetManager = {}; - Helpers::HandleManager IndexBufferSetManager = {}; - Helpers::HandleManager UniformBufferSetManager = {}; - Helpers::HandleManager DirtyResources = {}; - Helpers::HandleManager DirtyBuffers = {}; - Helpers::HandleManager DirtyBufferImages = {}; - std::atomic_bool RunningDirtyCollector = true; - std::atomic_uint IdleFrameCount = 0; - std::atomic_uint IdleFrameThreshold = SwapchainImageCount * 3 * 3; - std::condition_variable DirtyCollectorCond = {}; - std::mutex DirtyMutex = {}; - std::mutex Mutex = {}; - Windows::CoreWindow* CurrentWindow = nullptr; - ZEngine::Core::Memory::ArenaAllocator* Arena = nullptr; - AsyncResourceLoaderPtr AsyncResLoader = nullptr; - - void Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, Windows::CoreWindow* const window); - void Deinitialize(); - void Update(); - void Dispose(); - bool QueueSubmit(const VkPipelineStageFlags wait_stage_flag, CommandBuffer* const command_buffer, Rendering::Primitives::Semaphore* const signal_semaphore = nullptr, Rendering::Primitives::Fence* const fence = nullptr); - void EnqueueForDeletion(Rendering::DeviceResourceType resource_type, void* const resource_handle); - void EnqueueForDeletion(Rendering::DeviceResourceType resource_type, DirtyResource resource); - void EnqueueBufferForDeletion(BufferView& buffer); - void EnqueueBufferImageForDeletion(BufferImage& buffer); - QueueView GetQueue(Rendering::QueueType type); - void QueueWait(Rendering::QueueType type); - void QueueWaitAll(); - void MapAndCopyToMemory(BufferView& buffer, size_t data_size, const void* data); - BufferView CreateBuffer(VkDeviceSize byte_size, VkBufferUsageFlags buffer_usage, VmaAllocationCreateFlags vma_create_flags = 0); - void CopyBuffer(const BufferView& source, const BufferView& destination, VkDeviceSize byte_size, VkDeviceSize src_buffer_offset = 0u, VkDeviceSize dst_buffer_offset = 0u); - BufferImage CreateImage(uint32_t width, uint32_t height, VkImageType image_type, VkImageViewType image_view_type, VkFormat image_format, VkImageTiling image_tiling, VkImageLayout image_initial_layout, VkImageUsageFlags image_usage, VkSharingMode image_sharing_mode, VkSampleCountFlagBits image_sample_count, VkMemoryPropertyFlags requested_properties, VkImageAspectFlagBits image_aspect_flag, uint32_t layer_count = 1U, VkImageCreateFlags image_create_flag_bit = 0); - VkSampler CreateImageSampler(); - VkFormat FindSupportedFormat(Core::Containers::ArrayView format_collection, VkImageTiling image_tiling, VkFormatFeatureFlags feature_flags); - VkFormat FindDepthFormat(); - VkImageView CreateImageView(VkImage image, VkFormat image_format, VkImageViewType image_view_type, VkImageAspectFlagBits image_aspect_flag, uint32_t layer_count = 1U); - VkFramebuffer CreateFramebuffer(Core::Containers::ArrayView attachments, const VkRenderPass& render_pass, uint32_t width, uint32_t height, uint32_t layer_number = 1); - VertexBufferSetHandle CreateVertexBufferSet(); - StorageBufferSetHandle CreateStorageBufferSet(); - IndirectBufferSetHandle CreateIndirectBufferSet(); - IndexBufferSetHandle CreateIndexBufferSet(); - UniformBufferSetHandle CreateUniformBufferSet(); - void CreateSwapchain(); - void ResizeSwapchain(); - void DisposeSwapchain(); - void NewFrame(); - void Present(); - void IncrementFrameImageCount(); - CommandBuffer* GetCommandBuffer(bool begin = true); - CommandBuffer* GetInstantCommandBuffer(Rendering::QueueType type, bool begin = true); - void EnqueueInstantCommandBuffer(CommandBuffer* const buffer, int wait_flag = -1); - void EnqueueCommandBuffer(CommandBuffer* const buffer); - void DirtyCollector(); - - Helpers::Handle CompileShader(Rendering::Specifications::ShaderSpecification& spec); - - Rendering::Textures::TextureHandle CreateTexture(uint32_t width, uint32_t height); - Rendering::Textures::TextureHandle CreateTexture(uint32_t width, uint32_t height, float r = 255, float g = 255, float b = 255, float a = 255); - Rendering::Textures::TextureHandle CreateTexture(const Rendering::Specifications::TextureSpecification& spec); - void WriteTextureData(CommandBufferPtr command_buf, const Rendering::Textures::TextureHandle& handle, const void* data); - - Rendering::Renderers::RenderPasses::RenderPass* CreateRenderPass(const Rendering::Specifications::RenderPassSpecification& spec); + bool HasSeperateTransfertQueueFamily = false; + bool PhysicalDeviceSupportSampledImageBindless = false; + bool PhysicalDeviceSupportStorageBufferBindless = false; + const char* ApplicationName = "Tetragrama"; + const char* EngineName = "ZEngine"; + uint32_t SwapchainImageCount = 3; + uint32_t SwapchainImageIndex = std::numeric_limits::max(); + uint32_t CurrentFrameIndex = std::numeric_limits::max(); + uint32_t PreviousFrameIndex = std::numeric_limits::max(); + uint32_t SwapchainImageWidth = std::numeric_limits::max(); + uint32_t SwapchainImageHeight = std::numeric_limits::max(); + uint32_t GraphicFamilyIndex = std::numeric_limits::max(); + uint32_t TransferFamilyIndex = std::numeric_limits::max(); + uint32_t EnqueuedCommandbufferIndex = 0; + uint32_t WriteDescriptorSetIndex = 0; + uint32_t MaxGlobalTexture = 600; + VkInstance Instance = VK_NULL_HANDLE; + VkSurfaceKHR Surface = VK_NULL_HANDLE; + VkSurfaceFormatKHR SurfaceFormat = {}; + VkPresentModeKHR PresentMode = {}; + VkPhysicalDeviceProperties PhysicalDeviceProperties = {}; + VkPhysicalDeviceDescriptorIndexingProperties PhysicalDeviceDescriptorIndexingProperties = {}; + VkDevice LogicalDevice = VK_NULL_HANDLE; + VkPhysicalDevice PhysicalDevice = VK_NULL_HANDLE; + VkPhysicalDeviceFeatures2 PhysicalDeviceFeature = {}; + VkPhysicalDeviceMemoryProperties PhysicalDeviceMemoryProperties = {}; + VkSwapchainKHR SwapchainHandle = VK_NULL_HANDLE; + VkDescriptorPool GlobalDescriptorPoolHandle = VK_NULL_HANDLE; + VmaAllocator VmaAllocatorValue = nullptr; + Core::Containers::Array DefaultDepthFormats = {}; + Rendering::Renderers::RenderPasses::Attachment* SwapchainAttachment = {}; + Core::Containers::Array SwapchainImageViews = {}; + Core::Containers::Array SwapchainFramebuffers = {}; + Core::Containers::Array SwapchainAcquiredSemaphores = {}; + Core::Containers::Array SwapchainRenderCompleteSemaphores = {}; + Core::Containers::Array SwapchainSignalFences = {}; + Core::Containers::Array EnqueuedCommandbuffers = {}; + Core::Containers::HashMap> ShaderCaches = {}; + Core::Containers::HashMap> ShaderReservedDescriptorSetMap = {}; //> + Core::Containers::HashMap ShaderReservedDescriptorSetLayoutMap = {}; // + Core::Containers::HashMap> ShaderReservedLayoutBindingSpecificationMap = {}; + std::set WriteBindlessDescriptorSetRequests = {}; + std::unordered_set ShaderReservedBindingSets = {}; + Rendering::Textures::TextureHandleManager GlobalTextures = {}; + Helpers::HandleManager Image2DBufferManager = {}; + Helpers::ThreadSafeQueue TextureHandleToUpdates = {}; + Helpers::ThreadSafeQueue TextureHandleToDispose = {}; + Helpers::HandleManager ShaderManager = {}; + Helpers::HandleManager VertexBufferSetManager = {}; + Helpers::HandleManager StorageBufferSetManager = {}; + Helpers::HandleManager IndirectBufferSetManager = {}; + Helpers::HandleManager IndexBufferSetManager = {}; + Helpers::HandleManager UniformBufferSetManager = {}; + Helpers::HandleManager DirtyResources = {}; + Helpers::HandleManager DirtyBuffers = {}; + Helpers::HandleManager DirtyBufferImages = {}; + std::atomic_bool RunningDirtyCollector = true; + std::atomic_uint IdleFrameCount = 0; + std::atomic_uint IdleFrameThreshold = SwapchainImageCount * 3 * 3; + std::condition_variable DirtyCollectorCond = {}; + std::mutex DirtyMutex = {}; + std::mutex Mutex = {}; + Windows::CoreWindow* CurrentWindow = nullptr; + ZEngine::Core::Memory::ArenaAllocator* Arena = nullptr; + AsyncResourceLoaderPtr AsyncResLoader = nullptr; + + void Initialize(ZEngine::Core::Memory::ArenaAllocator* arena, Windows::CoreWindow* const window); + void Deinitialize(); + void Update(); + void Dispose(); + bool QueueSubmit(const VkPipelineStageFlags wait_stage_flag, CommandBuffer* const command_buffer, Rendering::Primitives::Semaphore* const signal_semaphore = nullptr, Rendering::Primitives::Fence* const fence = nullptr); + void EnqueueForDeletion(Rendering::DeviceResourceType resource_type, void* const resource_handle); + void EnqueueForDeletion(Rendering::DeviceResourceType resource_type, DirtyResource resource); + void EnqueueBufferForDeletion(BufferView& buffer); + void EnqueueBufferImageForDeletion(BufferImage& buffer); + QueueView GetQueue(Rendering::QueueType type); + void QueueWait(Rendering::QueueType type); + void QueueWaitAll(); + void MapAndCopyToMemory(BufferView& buffer, size_t data_size, const void* data); + BufferView CreateBuffer(VkDeviceSize byte_size, VkBufferUsageFlags buffer_usage, VmaAllocationCreateFlags vma_create_flags = 0); + void CopyBuffer(const BufferView& source, const BufferView& destination, VkDeviceSize byte_size, VkDeviceSize src_buffer_offset = 0u, VkDeviceSize dst_buffer_offset = 0u); + BufferImage CreateImage(uint32_t width, uint32_t height, VkImageType image_type, VkImageViewType image_view_type, VkFormat image_format, VkImageTiling image_tiling, VkImageLayout image_initial_layout, VkImageUsageFlags image_usage, VkSharingMode image_sharing_mode, VkSampleCountFlagBits image_sample_count, VkMemoryPropertyFlags requested_properties, VkImageAspectFlagBits image_aspect_flag, uint32_t layer_count = 1U, VkImageCreateFlags image_create_flag_bit = 0); + VkSampler CreateImageSampler(); + VkFormat FindSupportedFormat(Core::Containers::ArrayView format_collection, VkImageTiling image_tiling, VkFormatFeatureFlags feature_flags); + VkFormat FindDepthFormat(); + VkImageView CreateImageView(VkImage image, VkFormat image_format, VkImageViewType image_view_type, VkImageAspectFlagBits image_aspect_flag, uint32_t layer_count = 1U); + VkFramebuffer CreateFramebuffer(Core::Containers::ArrayView attachments, const VkRenderPass& render_pass, uint32_t width, uint32_t height, uint32_t layer_number = 1); + VertexBufferSetHandle CreateVertexBufferSet(); + StorageBufferSetHandle CreateStorageBufferSet(); + IndirectBufferSetHandle CreateIndirectBufferSet(); + IndexBufferSetHandle CreateIndexBufferSet(); + UniformBufferSetHandle CreateUniformBufferSet(); + void CreateSwapchain(); + void ResizeSwapchain(); + void DisposeSwapchain(); + void NewFrame(); + void Present(); + void IncrementFrameImageCount(); + CommandBuffer* GetCommandBuffer(bool begin = true); + CommandBuffer* GetInstantCommandBuffer(Rendering::QueueType type, bool begin = true); + void EnqueueInstantCommandBuffer(CommandBuffer* const buffer, int wait_flag = -1); + void EnqueueCommandBuffer(CommandBuffer* const buffer); + void DirtyCollector(); + + Helpers::Handle CompileShader(Rendering::Specifications::ShaderSpecification& spec); + + Rendering::Textures::TextureHandle CreateTexture(uint32_t width, uint32_t height); + Rendering::Textures::TextureHandle CreateTexture(uint32_t width, uint32_t height, float r = 255, float g = 255, float b = 255, float a = 255); + Rendering::Textures::TextureHandle CreateTexture(const Rendering::Specifications::TextureSpecification& spec); + void WriteTextureData(CommandBufferPtr command_buf, const Rendering::Textures::TextureHandle& handle, const void* data); + + Rendering::Renderers::RenderPasses::RenderPass* CreateRenderPass(const Rendering::Specifications::RenderPassSpecification& spec); private: VulkanLayer m_layer = {}; diff --git a/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp b/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp index b9cfd8c8..6f39fefd 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp @@ -91,7 +91,7 @@ namespace ZEngine::Rendering::Renderers .SetOffset(2, IM_OFFSETOF(ImDrawVert, col)) .UseShader("imgui") - .SetShaderOverloadMaxSet(2000) + // .SetShaderOverloadMaxSet(2000) // Todo : deprecated API - should be removed .UseSwapchainAsRenderTarget(); @@ -165,7 +165,7 @@ namespace ZEngine::Rendering::Renderers for (unsigned i = 0; i < frame_count; ++i) { - auto set = descriptor_set_map.at(0)[i]; + auto set = descriptor_set_map.at(1)[i]; write_descriptor_sets.push(VkWriteDescriptorSet{.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = set, .dstBinding = 0, .dstArrayElement = (uint32_t) font_tex_handle.Index, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &(font_image_info), .pBufferInfo = nullptr, .pTexelBufferView = nullptr}); } diff --git a/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp b/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp index 6658b23e..ca1c1cd1 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/RenderGraph.cpp @@ -31,10 +31,10 @@ namespace ZEngine::Rendering::Renderers void RenderGraph::Setup() { - for (auto [name, node] : NodeMap) + for (auto [name, _] : NodeMap) // Todo HashMap needs to support for (auto& [key, val]) {....} { - node.EdgeNodes.init(Device->Arena, 5); - node.CallbackPass->Setup(Device, name, ResourceBuilder, ResourceInspector); + NodeMap[name].EdgeNodes.init(Device->Arena, 5); + NodeMap[name].CallbackPass->Setup(Device, name, ResourceBuilder, ResourceInspector); } } diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp index a84556f1..70ef326b 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp @@ -41,17 +41,44 @@ namespace ZEngine::Rendering::Shaders LayoutBindingSpecificationMap.init(device->Arena, 4); LayoutBindingSpections.init(device->Arena, 5); SetLayouts.init(device->Arena, 5); - DescriptorSetLayoutMap.init(device->Arena, 5); + InternalDescriptorSetLayoutMap.init(device->Arena, 5); CreateModule(); CreateDescriptorSetLayouts(); CreatePushConstantRange(); - for (auto layout : DescriptorSetLayoutMap) + for (auto layout : InternalDescriptorSetLayoutMap) { SetLayouts.push(layout.second); } + // We merge info of Biding Set that is managed by the Device + if (!PostBindingSetFromDevices.empty()) + { + for (uint32_t i = 0; i < PostBindingSetFromDevices.size(); ++i) + { + uint32_t set = PostBindingSetFromDevices[i]; + SetLayouts.push(m_device->ShaderReservedDescriptorSetLayoutMap[set]); + + const auto& descriptor_sets = m_device->ShaderReservedDescriptorSetMap[set]; + const auto& binding_specifications = m_device->ShaderReservedLayoutBindingSpecificationMap[set]; + + DescriptorSetMap[set].init(m_device->Arena, descriptor_sets.size(), descriptor_sets.size()); + for (uint32_t ds = 0; ds < descriptor_sets.size(); ++ds) + { + DescriptorSetMap[set][ds] = descriptor_sets[ds]; + } + + LayoutBindingSpecificationMap[set].init(m_device->Arena, binding_specifications.size(), binding_specifications.size()); + for (uint32_t lb = 0; lb < binding_specifications.size(); ++lb) + { + LayoutBindingSpecificationMap[set][lb] = binding_specifications[lb]; + } + } + + PostBindingSetFromDevices.empty(); + } + for (const auto layout_binding : LayoutBindingSpecificationMap) { for (const auto& spec : layout_binding.second) @@ -59,11 +86,14 @@ namespace ZEngine::Rendering::Shaders LayoutBindingSpections.push(spec); } } + LocalArena.Clear(); } void Shader::CreateModule() { + PostBindingSetFromDevices.init(&LocalArena, 5); + ZRawPtr(spirv_cross::Compiler) spirv_compiler = nullptr; /* @@ -206,50 +236,20 @@ namespace ZEngine::Rendering::Shaders for (const auto& SI_resource : fragment_resources.sampled_images) { - uint32_t set = spirv_compiler->get_decoration(SI_resource.id, spv::DecorationDescriptorSet); - uint32_t binding = spirv_compiler->get_decoration(SI_resource.id, spv::DecorationBinding); + uint32_t set = spirv_compiler->get_decoration(SI_resource.id, spv::DecorationDescriptorSet); - uint32_t count = 1; - const auto& type = spirv_compiler->get_type(SI_resource.type_id); - if (!type.array.empty()) + if (m_device->ShaderReservedBindingSets.contains(set)) // reserved set by the Device { - count = type.array[0]; - if (count == 0) // Unsized arrays - { - /* - * Unsized arrays require descriptor update-after-bind support - * If device doesn't support it, we fall back to a reasonable maximum - */ - if (m_device->PhysicalDeviceSupportSampledImageBindless) - { - count = m_device->PhysicalDeviceDescriptorIndexingProperties.maxPerStageDescriptorUpdateAfterBindSamplers - 1; - } - else - { - /* - * Fallback: derive a safe maximum from device properties when possible - * Otherwise fall back to a conservative hard limit. - */ - uint32_t fallback_count = 4096; - if (m_device->PhysicalDeviceDescriptorIndexingProperties.maxPerStageDescriptorUpdateAfterBindSamplers > 1) - { - fallback_count = static_cast(m_device->PhysicalDeviceDescriptorIndexingProperties.maxPerStageDescriptorUpdateAfterBindSamplers - 1); - if (fallback_count > 4096) - { - fallback_count = 4096; // cap to reasonable upper bound - } - } - - count = fallback_count; - ZENGINE_CORE_WARN( - "Shader {} uses unsized sampler arrays but device does not support descriptor update-after-bind. " - "Using fallback size of {} descriptors. For full bindless rendering support, use GPUs with descriptor-indexing support.", - m_specification.VertexFilename ? m_specification.VertexFilename : m_specification.FragmentFilename, - count) - } - } + PostBindingSetFromDevices.push(set); + continue; } + uint32_t binding = spirv_compiler->get_decoration(SI_resource.id, spv::DecorationBinding); + + const auto& type = spirv_compiler->get_type(SI_resource.type_id); + + uint32_t count = std::min(type.array.empty() ? 1 : type.array[0], 256u); + if (LayoutBindingSpecificationMap[set].capacity() <= 0) { LayoutBindingSpecificationMap[set].init(m_device->Arena, 10); @@ -285,11 +285,11 @@ namespace ZEngine::Rendering::Shaders } ShaderModules.clear(); - for (auto set_layout : DescriptorSetLayoutMap) + for (auto set_layout : InternalDescriptorSetLayoutMap) { m_device->EnqueueForDeletion(Rendering::DeviceResourceType::DESCRIPTORSETLAYOUT, set_layout.second); } - DescriptorSetLayoutMap.clear(); + InternalDescriptorSetLayoutMap.clear(); if (m_descriptor_pool) { @@ -320,6 +320,7 @@ namespace ZEngine::Rendering::Shaders for (uint32_t i = 0; i < layout_binding_collection.size(); ++i) { binding_flags_collection[i] = 0; // We zeroing as we iterate + if (m_device->PhysicalDeviceSupportSampledImageBindless && ((layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) || (layout_binding_collection[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE))) { binding_flags_collection[i] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT; @@ -351,7 +352,7 @@ namespace ZEngine::Rendering::Shaders VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; ZENGINE_VALIDATE_ASSERT(vkCreateDescriptorSetLayout(m_device->LogicalDevice, &descriptor_set_layout_create_info, nullptr, &descriptor_set_layout) == VK_SUCCESS, "Failed to create DescriptorSetLayout") - DescriptorSetLayoutMap[binding_set] = std::move(descriptor_set_layout); + InternalDescriptorSetLayoutMap[binding_set] = std::move(descriptor_set_layout); /* * Packing PoolSize */ @@ -367,7 +368,7 @@ namespace ZEngine::Rendering::Shaders /* * ToDo: we should check the limit against the device.. */ - find_pool_size_it->descriptorCount++; + find_pool_size_it->descriptorCount += layout_binding.descriptorCount; } /* * Ensure correctness with number of frame count @@ -375,12 +376,18 @@ namespace ZEngine::Rendering::Shaders for (auto& pool_size : pool_size_collection) { pool_size.descriptorCount *= m_device->SwapchainImageCount; - pool_size.descriptorCount += m_specification.OverloadPoolSize; + // pool_size.descriptorCount += m_specification.OverloadPoolSize; } } + DescriptorSetMap.init(m_device->Arena, 5); /* * Create DescriptorPool */ + if (pool_size_collection.empty()) + { + ZENGINE_CORE_WARN("Shader: - The pool size is empty!") + return; + } ZENGINE_VALIDATE_ASSERT(!pool_size_collection.empty(), "The pool size can't be empty") VkDescriptorPoolCreateInfo pool_info = {}; @@ -395,8 +402,8 @@ namespace ZEngine::Rendering::Shaders /* * Create DescriptorSet */ - DescriptorSetMap.init(m_device->Arena, 5); - for (const auto& layout : DescriptorSetLayoutMap) + + for (const auto& layout : InternalDescriptorSetLayoutMap) { DescriptorSetMap[layout.first].init(m_device->Arena, m_device->SwapchainImageCount, m_device->SwapchainImageCount); diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.h b/ZEngine/ZEngine/Rendering/Shaders/Shader.h index bfd78e6c..c4ec3ce0 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.h +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.h @@ -17,19 +17,20 @@ namespace ZEngine::Rendering::Shaders void Dispose(); Specifications::LayoutBindingSpecification GetLayoutBindingSpecification(const char* name); - VkDescriptorPool m_descriptor_pool = VK_NULL_HANDLE; - Specifications::ShaderSpecification m_specification = {}; - Core::Memory::ArenaAllocator LocalArena = {}; - - Core::Containers::Array PushConstantSpecifications = {}; - Core::Containers::Array ShaderCreateInfos = {}; - Core::Containers::Array ShaderModules = {}; - Core::Containers::Array SetLayouts = {}; - Core::Containers::Array LayoutBindingSpections = {}; - Core::Containers::Array PushConstants = {}; - Core::Containers::HashMap> DescriptorSetMap = {}; //> - Core::Containers::HashMap DescriptorSetLayoutMap = {}; // - Core::Containers::HashMap> LayoutBindingSpecificationMap = {}; + VkDescriptorPool m_descriptor_pool = VK_NULL_HANDLE; + Specifications::ShaderSpecification m_specification = {}; + Core::Memory::ArenaAllocator LocalArena = {}; + + Core::Containers::Array PushConstantSpecifications = {}; + Core::Containers::Array ShaderCreateInfos = {}; + Core::Containers::Array ShaderModules = {}; + Core::Containers::Array SetLayouts = {}; + Core::Containers::Array LayoutBindingSpections = {}; + Core::Containers::Array PushConstants = {}; + Core::Containers::Array PostBindingSetFromDevices = {}; + Core::Containers::HashMap> DescriptorSetMap = {}; //> + Core::Containers::HashMap InternalDescriptorSetLayoutMap = {}; // + Core::Containers::HashMap> LayoutBindingSpecificationMap = {}; private: void CreateModule(); @@ -37,6 +38,7 @@ namespace ZEngine::Rendering::Shaders void CreatePushConstantRange(); private: + bool m_perform_post_merging_from_device{false}; Hardwares::VulkanDevice* m_device{nullptr}; }; From 1666d1ded95beef3316f302aed0fd8d2f637060f Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Wed, 28 Jan 2026 10:34:46 +0900 Subject: [PATCH 08/15] fixed descriptor set count logic --- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 7 +- .../Rendering/Renderers/GraphicRenderer.cpp | 2 +- .../Renderers/RenderPasses/RenderPass.cpp | 21 ++-- ZEngine/ZEngine/Rendering/Shaders/Shader.cpp | 95 +++++++++++-------- ZEngine/ZEngine/Rendering/Shaders/Shader.h | 6 +- 5 files changed, 77 insertions(+), 54 deletions(-) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index 50984234..c6b68003 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -1873,15 +1873,18 @@ namespace ZEngine::Hardwares auto pipeline = render_pass->Pipeline; auto pipeline_layout = pipeline->Layout; auto shader = pipeline->Shader; + const auto& set_layout = shader->SetLayouts; auto& descriptor_set_map = shader->DescriptorSetMap; auto scratch = ZGetScratch(&LocalArena); Array frame_sets = {}; frame_sets.init(scratch.Arena, 5); - for (const auto& [_, sets] : descriptor_set_map) + // Since SetLayout is ordered by defined Set in shader source + // We're safe to use index as Set + for (uint32_t i = 0; i < set_layout.size(); ++i) { - frame_sets.push(sets[frame_index]); + frame_sets.push(descriptor_set_map[i][frame_index]); } vkCmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, frame_sets.size(), frame_sets.data(), 0, nullptr); diff --git a/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp b/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp index 458c00a7..495548f8 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp @@ -85,7 +85,7 @@ namespace ZEngine::Rendering::Renderers // RenderGraph->AddCallbackPass("Skybox Pass", skybox_pass); RenderGraph->AddCallbackPass("Grid Pass", grid_pass); RenderGraph->AddCallbackPass("G-Buffer Pass", gbuffer_pass); - // RenderGraph->AddCallbackPass("Lighting Pass", lighting_pass); + // RenderGraph->AddCallbackPass("Lighting Pass", lighting_pass); RenderGraph->Setup(); RenderGraph->Compile(); diff --git a/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp b/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp index 5d6a953f..5bed25cb 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp @@ -110,27 +110,30 @@ namespace ZEngine::Rendering::Renderers::RenderPasses bool RenderPass::Verify() { - const auto& m_layout_bindings = Pipeline->Shader->LayoutBindingSpections; + bool verify = true; + const auto& layout_binding_specification = Pipeline->Shader->LayoutBindingSpecifications; - if (Inputs.size() != m_layout_bindings.size()) + if (Inputs.size() != layout_binding_specification.size()) { std::vector missing_names; - for (const auto& binding : m_layout_bindings) + for (const auto& specification : layout_binding_specification) { - if (!Inputs.count(binding.Name)) + std::string name(specification.Name); + if (!Inputs.count(name)) { - missing_names.emplace_back(binding.Name); + missing_names.emplace_back(name); } } auto start = missing_names.begin(); auto end = missing_names.end(); - std::string unset_inputs = std::accumulate(std::next(start), end, *start, [](std::string_view a, std::string_view b) { return fmt::format("{}, {}", a, b); }); + std::string unset_inputs = std::accumulate(std::next(start), end, *start, [](std::string_view a, std::string_view b) { return fmt::format("{}, {}", a.data(), b.data()); }); - ZENGINE_CORE_WARN("Shader '{}': {} unset input(s): {}", Specification.PipelineSpecification.DebugName, missing_names.size(), unset_inputs); + ZENGINE_CORE_WARN("Shader '{}': {} unset input(s): {}", Specification.PipelineSpecification.DebugName, missing_names.size(), unset_inputs.c_str()); - return false; + verify = false; } - return true; + + return verify; } void RenderPass::SetInput(std::string_view key_name, const Hardwares::UniformBufferSetHandle& handle) diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp index 70ef326b..c2e2c64d 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp @@ -39,7 +39,7 @@ namespace ZEngine::Rendering::Shaders PushConstants.init(device->Arena, 4); PushConstantSpecifications.init(device->Arena, 4); LayoutBindingSpecificationMap.init(device->Arena, 4); - LayoutBindingSpections.init(device->Arena, 5); + LayoutBindingSpecifications.init(device->Arena, 5); SetLayouts.init(device->Arena, 5); InternalDescriptorSetLayoutMap.init(device->Arena, 5); @@ -47,43 +47,33 @@ namespace ZEngine::Rendering::Shaders CreateDescriptorSetLayouts(); CreatePushConstantRange(); - for (auto layout : InternalDescriptorSetLayoutMap) { - SetLayouts.push(layout.second); - } - - // We merge info of Biding Set that is managed by the Device - if (!PostBindingSetFromDevices.empty()) - { - for (uint32_t i = 0; i < PostBindingSetFromDevices.size(); ++i) + std::set ordered_sets = {}; + for (auto [i, _] : InternalDescriptorSetLayoutMap) { - uint32_t set = PostBindingSetFromDevices[i]; - SetLayouts.push(m_device->ShaderReservedDescriptorSetLayoutMap[set]); - - const auto& descriptor_sets = m_device->ShaderReservedDescriptorSetMap[set]; - const auto& binding_specifications = m_device->ShaderReservedLayoutBindingSpecificationMap[set]; - - DescriptorSetMap[set].init(m_device->Arena, descriptor_sets.size(), descriptor_sets.size()); - for (uint32_t ds = 0; ds < descriptor_sets.size(); ++ds) - { - DescriptorSetMap[set][ds] = descriptor_sets[ds]; - } - - LayoutBindingSpecificationMap[set].init(m_device->Arena, binding_specifications.size(), binding_specifications.size()); - for (uint32_t lb = 0; lb < binding_specifications.size(); ++lb) - { - LayoutBindingSpecificationMap[set][lb] = binding_specifications[lb]; - } + ordered_sets.insert(i); } - PostBindingSetFromDevices.empty(); + for (auto set : ordered_sets) + { + SetLayouts.push(InternalDescriptorSetLayoutMap[set]); + } } for (const auto layout_binding : LayoutBindingSpecificationMap) { for (const auto& spec : layout_binding.second) { - LayoutBindingSpections.push(spec); + LayoutBindingSpecifications.push(spec); + } + } + + // We remove the Set to avoid double release from the Device and Shader owned resource + for (const auto& [set, _] : m_device->ShaderReservedDescriptorSetLayoutMap) + { + if (InternalDescriptorSetLayoutMap.contains(set)) + { + InternalDescriptorSetLayoutMap.remove(set); } } @@ -92,8 +82,6 @@ namespace ZEngine::Rendering::Shaders void Shader::CreateModule() { - PostBindingSetFromDevices.init(&LocalArena, 5); - ZRawPtr(spirv_cross::Compiler) spirv_compiler = nullptr; /* @@ -238,12 +226,17 @@ namespace ZEngine::Rendering::Shaders { uint32_t set = spirv_compiler->get_decoration(SI_resource.id, spv::DecorationDescriptorSet); - if (m_device->ShaderReservedBindingSets.contains(set)) // reserved set by the Device + if (m_device->ShaderReservedLayoutBindingSpecificationMap.contains(set)) { - PostBindingSetFromDevices.push(set); + const auto& binding_specifications = m_device->ShaderReservedLayoutBindingSpecificationMap[set]; + LayoutBindingSpecificationMap[set].init(m_device->Arena, binding_specifications.size(), binding_specifications.size()); + + for (uint32_t i = 0; i < binding_specifications.size(); ++i) + { + LayoutBindingSpecificationMap[set][i] = binding_specifications[i]; + } continue; } - uint32_t binding = spirv_compiler->get_decoration(SI_resource.id, spv::DecorationBinding); const auto& type = spirv_compiler->get_type(SI_resource.type_id); @@ -260,9 +253,15 @@ namespace ZEngine::Rendering::Shaders } } - Specifications::LayoutBindingSpecification Shader::GetLayoutBindingSpecification(const char* name) + Specifications::LayoutBindingSpecification Shader::GetLayoutBindingSpecification(cstring name) { LayoutBindingSpecification binding_spec = {}; + + if (!Helpers::secure_strlen(name)) + { + return binding_spec; + } + for (const auto& layout_binding : LayoutBindingSpecificationMap) { const auto& binding_specification_collection = layout_binding.second; @@ -305,7 +304,15 @@ namespace ZEngine::Rendering::Shaders for (const auto& layout_binding_set : LayoutBindingSpecificationMap) { - uint32_t binding_set = layout_binding_set.first; + uint32_t binding_set = layout_binding_set.first; + + if (m_device->ShaderReservedLayoutBindingSpecificationMap.contains(binding_set)) + { + // Since it's a reserved Set The device already created its SetLayout + InternalDescriptorSetLayoutMap[binding_set] = m_device->ShaderReservedDescriptorSetLayoutMap[binding_set]; + continue; + } + Array layout_binding_collection = {}; layout_binding_collection.init(&LocalArena, 10); for (uint32_t i = 0; i < layout_binding_set.second.size(); ++i) @@ -376,10 +383,14 @@ namespace ZEngine::Rendering::Shaders for (auto& pool_size : pool_size_collection) { pool_size.descriptorCount *= m_device->SwapchainImageCount; - // pool_size.descriptorCount += m_specification.OverloadPoolSize; } } + + /* + * Creating DescriptorPool and DescriptorSet + */ DescriptorSetMap.init(m_device->Arena, 5); + /* * Create DescriptorPool */ @@ -388,12 +399,11 @@ namespace ZEngine::Rendering::Shaders ZENGINE_CORE_WARN("Shader: - The pool size is empty!") return; } - ZENGINE_VALIDATE_ASSERT(!pool_size_collection.empty(), "The pool size can't be empty") VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = m_device->PhysicalDeviceSupportSampledImageBindless ? VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT : 0; - pool_info.maxSets = m_device->SwapchainImageCount * pool_size_collection.size() * m_specification.OverloadMaxSet; + pool_info.maxSets = m_device->SwapchainImageCount; pool_info.poolSizeCount = pool_size_collection.size(); pool_info.pPoolSizes = pool_size_collection.data(); @@ -406,6 +416,15 @@ namespace ZEngine::Rendering::Shaders for (const auto& layout : InternalDescriptorSetLayoutMap) { DescriptorSetMap[layout.first].init(m_device->Arena, m_device->SwapchainImageCount, m_device->SwapchainImageCount); + if (m_device->ShaderReservedDescriptorSetMap.contains(layout.first)) + { + // Since it's a Reserved Set, the Device already created the DescriptorSet + for (uint32_t i = 0; i < m_device->SwapchainImageCount; ++i) + { + DescriptorSetMap[layout.first][i] = m_device->ShaderReservedDescriptorSetMap[layout.first][i]; + } + continue; + } Array layout_set = {}; layout_set.init(&LocalArena, m_device->SwapchainImageCount, m_device->SwapchainImageCount); diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.h b/ZEngine/ZEngine/Rendering/Shaders/Shader.h index c4ec3ce0..c12c3aec 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.h +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.h @@ -15,7 +15,7 @@ namespace ZEngine::Rendering::Shaders void Initialize(Hardwares::VulkanDevice* device, const Specifications::ShaderSpecification& spec); void Dispose(); - Specifications::LayoutBindingSpecification GetLayoutBindingSpecification(const char* name); + Specifications::LayoutBindingSpecification GetLayoutBindingSpecification(cstring name); VkDescriptorPool m_descriptor_pool = VK_NULL_HANDLE; Specifications::ShaderSpecification m_specification = {}; @@ -25,9 +25,8 @@ namespace ZEngine::Rendering::Shaders Core::Containers::Array ShaderCreateInfos = {}; Core::Containers::Array ShaderModules = {}; Core::Containers::Array SetLayouts = {}; - Core::Containers::Array LayoutBindingSpections = {}; + Core::Containers::Array LayoutBindingSpecifications = {}; Core::Containers::Array PushConstants = {}; - Core::Containers::Array PostBindingSetFromDevices = {}; Core::Containers::HashMap> DescriptorSetMap = {}; //> Core::Containers::HashMap InternalDescriptorSetLayoutMap = {}; // Core::Containers::HashMap> LayoutBindingSpecificationMap = {}; @@ -38,7 +37,6 @@ namespace ZEngine::Rendering::Shaders void CreatePushConstantRange(); private: - bool m_perform_post_merging_from_device{false}; Hardwares::VulkanDevice* m_device{nullptr}; }; From 99576160967c591820145195480be32734678498 Mon Sep 17 00:00:00 2001 From: Mathew Benson Date: Thu, 29 Jan 2026 01:57:46 +0300 Subject: [PATCH 09/15] Mitigate undesired unsynchronized effect of changing SwapchainImage Count (#495) * Re-Arrange Code flow after swapchainimage count change - The code that relies on the SwapchainImageCount such as the command buffer are re-arranged to ensure that they run after we establish the correct number of Swapchain Images * Pull Request #495 Requested Changes - Removed Redundant parameter to the CommandBufferManager.Initialize method - Moved the EnquedCommandBuffers.init method to be called right after the m_buffer_manager.Initialize function call --------- Co-authored-by: Mathew Benson --- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index c6b68003..98a96965 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -409,9 +409,6 @@ namespace ZEngine::Hardwares VmaAllocatorCreateInfo vma_allocator_create_info = {.physicalDevice = PhysicalDevice, .device = LogicalDevice, .instance = Instance, .vulkanApiVersion = VK_API_VERSION_1_3}; ZENGINE_VALIDATE_ASSERT(vmaCreateAllocator(&vma_allocator_create_info, &VmaAllocatorValue) == VK_SUCCESS, "Failed to create VMA Allocator") - m_buffer_manager.Initialize(this); - EnqueuedCommandbuffers.init(Arena, m_buffer_manager.TotalCommandBufferCount, m_buffer_manager.TotalCommandBufferCount); - /* * Creating Swapchain */ @@ -428,6 +425,8 @@ namespace ZEngine::Hardwares PreviousFrameIndex = 0; CurrentFrameIndex = 0; + CreateSwapchain(); + SwapchainRenderCompleteSemaphores.init(Arena, SwapchainImageCount, SwapchainImageCount); SwapchainAcquiredSemaphores.init(Arena, SwapchainImageCount, SwapchainImageCount); SwapchainSignalFences.init(Arena, SwapchainImageCount, SwapchainImageCount); @@ -438,7 +437,6 @@ namespace ZEngine::Hardwares SwapchainRenderCompleteSemaphores[i] = ZPushStructCtorArgs(Arena, Primitives::Semaphore, this); SwapchainSignalFences[i] = ZPushStructCtorArgs(Arena, Primitives::Fence, this, true); } - CreateSwapchain(); /* * Creating Global Descriptor Pool for : Textures @@ -1242,6 +1240,9 @@ namespace ZEngine::Hardwares SwapchainFramebuffers.init(Arena, SwapchainImageCount, SwapchainImageCount); } + m_buffer_manager.Initialize(this); + EnqueuedCommandbuffers.init(Arena, m_buffer_manager.TotalCommandBufferCount, m_buffer_manager.TotalCommandBufferCount); + scratch = ZGetScratch(Arena); Array SwapchainImages = {}; @@ -2004,10 +2005,10 @@ namespace ZEngine::Hardwares } } - void CommandBufferManager::Initialize(VulkanDevice* device, uint8_t swapchain_image_count, int thread_count) + void CommandBufferManager::Initialize(VulkanDevice* device, int thread_count) { Device = device; - m_total_pool_count = swapchain_image_count * thread_count; + m_total_pool_count = device->SwapchainImageCount * thread_count; TotalCommandBufferCount = m_total_pool_count * MaxBufferPerPool; m_instant_fence = ZPushStructCtorArgs(Device->Arena, Primitives::Fence, device); m_instant_semaphore = ZPushStructCtorArgs(Device->Arena, Primitives::Semaphore, device); From 3b703f6c139987481f26906d0cf7082e89d11054 Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Thu, 29 Jan 2026 16:32:59 +0900 Subject: [PATCH 10/15] improved buffer manager --- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 135 ++++++++++++++++----- ZEngine/ZEngine/Hardwares/VulkanDevice.h | 35 ++++-- 2 files changed, 127 insertions(+), 43 deletions(-) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index 98a96965..738dbadb 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -570,7 +570,6 @@ namespace ZEngine::Hardwares UniformBufferSetManager.Dispose(); ShaderManager.Dispose(); - EnqueuedCommandbuffers.clear(); SwapchainSignalFences.clear(); SwapchainAcquiredSemaphores.clear(); SwapchainRenderCompleteSemaphores.clear(); @@ -1222,26 +1221,50 @@ namespace ZEngine::Hardwares uint32_t image_count = 0; ZENGINE_VALIDATE_ASSERT(vkGetSwapchainImagesKHR(LogicalDevice, SwapchainHandle, &image_count, nullptr) == VK_SUCCESS, "Failed to get Images count from Swapchain") + bool swapchainImageCountChanged = false; if (image_count != SwapchainImageCount) { - ZENGINE_CORE_WARN("Max Swapchain image count supported is {}, but requested {}", image_count, SwapchainImageCount); + ZENGINE_CORE_WARN("Max Swapchain image count supported is {}, but requested {}", image_count, SwapchainImageCount) auto old_swapchain_image_count = SwapchainImageCount; SwapchainImageCount = image_count; - ZENGINE_CORE_WARN("Swapchain image count has changed from {} to {}", old_swapchain_image_count, image_count); - } + ZENGINE_CORE_WARN("Swapchain image count has changed from {} to {}", old_swapchain_image_count, image_count) - if (SwapchainImageViews.capacity() <= 0) - { - SwapchainImageViews.init(Arena, SwapchainImageCount, SwapchainImageCount); + swapchainImageCountChanged = true; } - if (SwapchainFramebuffers.capacity() <= 0) + if ((SwapchainImageCountChangeCount > 0) && (PreviousSwapchainImageCount != SwapchainImageCount)) { - SwapchainFramebuffers.init(Arena, SwapchainImageCount, SwapchainImageCount); + ZENGINE_CORE_WARN("Swapchain image count has changed from previous creation") + + auto delta = SwapchainImageCount - PreviousSwapchainImageCount; + + // When delta is less or equal of zero, it means we have enough memory to handle ops + if (delta > 0 && delta < std::numeric_limits::max()) + { + SwapchainImageViews.push({}); + SwapchainFramebuffers.push({}); + + m_buffer_manager.IncreaseBuffers(); + // EnqueuedCommandbuffers.reserve(m_buffer_manager.TotalCommandBufferCount); + } } + else + { + if (SwapchainImageViews.capacity() <= 0) + { + SwapchainImageViews.init(Arena, SwapchainImageCount, SwapchainImageCount); + } - m_buffer_manager.Initialize(this); - EnqueuedCommandbuffers.init(Arena, m_buffer_manager.TotalCommandBufferCount, m_buffer_manager.TotalCommandBufferCount); + if (SwapchainFramebuffers.capacity() <= 0) + { + SwapchainFramebuffers.init(Arena, SwapchainImageCount, SwapchainImageCount); + } + + if (!m_buffer_manager.IsInitialized()) + { + m_buffer_manager.Initialize(this); + } + } scratch = ZGetScratch(Arena); @@ -1282,6 +1305,11 @@ namespace ZEngine::Hardwares } ZReleaseScratch(scratch); + + if (swapchainImageCountChanged) + { + SwapchainImageCountChangeCount++; + } } void VulkanDevice::ResizeSwapchain() @@ -1296,6 +1324,8 @@ namespace ZEngine::Hardwares void VulkanDevice::DisposeSwapchain() { + PreviousSwapchainImageCount = SwapchainImageCount; + for (VkImageView image_view : SwapchainImageViews) { if (image_view) @@ -1394,14 +1424,14 @@ namespace ZEngine::Hardwares Primitives::Semaphore* render_complete_semaphore = SwapchainRenderCompleteSemaphores[CurrentFrameIndex]; Primitives::Fence* signal_fence = SwapchainSignalFences[CurrentFrameIndex]; - auto scratch = ZGetScratch(Arena); + m_buffer_manager.EndEnqueuedBuffers(); + auto scratch = ZGetScratch(Arena); - Array buffer; - buffer.init(scratch.Arena, EnqueuedCommandbufferIndex); - for (int i = 0; i < EnqueuedCommandbufferIndex; ++i) + Array buffer = {}; + buffer.init(scratch.Arena, m_buffer_manager.EnqueuedCommandbufferIndex, m_buffer_manager.EnqueuedCommandbufferIndex); + for (int i = 0; i < buffer.size(); ++i) { - EnqueuedCommandbuffers[i]->End(); - buffer.push(EnqueuedCommandbuffers[i]->GetHandle()); + buffer[i] = m_buffer_manager.EnqueuedCommandbuffers[i]->GetHandle(); } ZENGINE_VALIDATE_ASSERT(render_complete_semaphore->GetState() != Rendering::Primitives::SemaphoreState::Submitted, "Signal semaphore is already in a signaled state.") @@ -1418,10 +1448,7 @@ namespace ZEngine::Hardwares ZReleaseScratch(scratch); - for (int i = 0; i < EnqueuedCommandbufferIndex; ++i) - { - EnqueuedCommandbuffers[i]->SetState(CommanBufferState::Pending); - } + m_buffer_manager.ResetEnqueuedBufferIndex(); signal_fence->SetState(FenceState::Submitted); render_complete_semaphore->SetState(SemaphoreState::Submitted); @@ -1429,9 +1456,8 @@ namespace ZEngine::Hardwares VkSwapchainKHR swapchains[] = {SwapchainHandle}; uint32_t frames[] = {SwapchainImageIndex}; VkPresentInfoKHR present_info = {.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .pNext = nullptr, .waitSemaphoreCount = 1, .pWaitSemaphores = signal_semaphores, .swapchainCount = 1, .pSwapchains = swapchains, .pImageIndices = frames}; - VkResult present_result = vkQueuePresentKHR(queue, &present_info); - EnqueuedCommandbufferIndex = 0; + acquired_semaphore->SetState(SemaphoreState::Idle); render_complete_semaphore->SetState(SemaphoreState::Idle); @@ -1476,7 +1502,7 @@ namespace ZEngine::Hardwares void VulkanDevice::EnqueueCommandBuffer(CommandBuffer* const buffer) { - EnqueuedCommandbuffers[EnqueuedCommandbufferIndex++] = buffer; + m_buffer_manager.EnqueueBuffer(buffer); } void VulkanDevice::DirtyCollector() @@ -2007,16 +2033,25 @@ namespace ZEngine::Hardwares void CommandBufferManager::Initialize(VulkanDevice* device, int thread_count) { + if (m_is_initialized) + { + ZENGINE_CORE_WARN("Attempted to call {}, but it has been already initialized", __FUNCTION__) + return; + } + Device = device; - m_total_pool_count = device->SwapchainImageCount * thread_count; + m_thread_count = thread_count; + m_total_pool_count = Device->SwapchainImageCount * m_thread_count; TotalCommandBufferCount = m_total_pool_count * MaxBufferPerPool; - m_instant_fence = ZPushStructCtorArgs(Device->Arena, Primitives::Fence, device); - m_instant_semaphore = ZPushStructCtorArgs(Device->Arena, Primitives::Semaphore, device); + m_instant_fence = ZPushStructCtorArgs(Device->Arena, Primitives::Fence, Device); + m_instant_semaphore = ZPushStructCtorArgs(Device->Arena, Primitives::Semaphore, Device); + + EnqueuedCommandbuffers.init(Device->Arena, TotalCommandBufferCount, TotalCommandBufferCount); CommandPools.init(Device->Arena, m_total_pool_count, m_total_pool_count); for (int i = 0; i < m_total_pool_count; ++i) { - CommandPools[i] = ZPushStructCtorArgs(Device->Arena, Rendering::Pools::CommandPool, device, Rendering::QueueType::GRAPHIC_QUEUE); + CommandPools[i] = ZPushStructCtorArgs(Device->Arena, Rendering::Pools::CommandPool, Device, Rendering::QueueType::GRAPHIC_QUEUE); } CommandBuffers.init(Device->Arena, TotalCommandBufferCount, TotalCommandBufferCount); @@ -2027,7 +2062,7 @@ namespace ZEngine::Hardwares CommandBuffers[i] = ZPushStructCtorArgs( Device->Arena, CommandBuffer, - device, + Device, pool->Handle, pool->QueueType, /*(i % MaxBufferPerPool) == 0 ? false : true */ false); @@ -2038,7 +2073,7 @@ namespace ZEngine::Hardwares TransferCommandPools.init(Device->Arena, m_total_pool_count, m_total_pool_count); for (int i = 0; i < m_total_pool_count; ++i) { - TransferCommandPools[i] = ZPushStructCtorArgs(Device->Arena, Rendering::Pools::CommandPool, device, Rendering::QueueType::TRANSFER_QUEUE); + TransferCommandPools[i] = ZPushStructCtorArgs(Device->Arena, Rendering::Pools::CommandPool, Device, Rendering::QueueType::TRANSFER_QUEUE); } TransferCommandBuffers.init(Device->Arena, TotalCommandBufferCount, TotalCommandBufferCount); @@ -2046,9 +2081,11 @@ namespace ZEngine::Hardwares { int pool_index = GetPoolFromIndex(Rendering::QueueType::TRANSFER_QUEUE, i); auto& pool = TransferCommandPools[pool_index]; - TransferCommandBuffers[i] = ZPushStructCtorArgs(Device->Arena, CommandBuffer, device, pool->Handle, pool->QueueType, true); + TransferCommandBuffers[i] = ZPushStructCtorArgs(Device->Arena, CommandBuffer, Device, pool->Handle, pool->QueueType, true); } } + + m_is_initialized = true; } void CommandBufferManager::Deinitialize() @@ -2060,6 +2097,7 @@ namespace ZEngine::Hardwares CommandPools.clear(); TransferCommandPools.clear(); + EnqueuedCommandbuffers.clear(); } CommandBuffer* CommandBufferManager::GetCommandBuffer(uint8_t frame_index, bool begin) @@ -2129,6 +2167,41 @@ namespace ZEngine::Hardwares } } + void CommandBufferManager::ResetEnqueuedBufferIndex() + { + for (int i = 0; i < EnqueuedCommandbufferIndex; ++i) + { + EnqueuedCommandbuffers[i]->SetState(CommanBufferState::Pending); + } + EnqueuedCommandbufferIndex = 0u; + } + + void CommandBufferManager::EndEnqueuedBuffers() + { + for (int i = 0; i < EnqueuedCommandbufferIndex; ++i) + { + EnqueuedCommandbuffers[i]->End(); + } + } + + void CommandBufferManager::EnqueueBuffer(CommandBufferPtr const buffer) + { + EnqueuedCommandbuffers[EnqueuedCommandbufferIndex++] = buffer; + } + + void CommandBufferManager::IncreaseBuffers() + { + m_total_pool_count = Device->SwapchainImageCount * m_thread_count; + TotalCommandBufferCount = m_total_pool_count * MaxBufferPerPool; + + + } + + bool CommandBufferManager::IsInitialized() const + { + return m_is_initialized; + } + BufferView VertexBuffer::CreateBuffer() { return m_device->CreateBuffer(m_total_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.h b/ZEngine/ZEngine/Hardwares/VulkanDevice.h index c4810f7d..d75d0641 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.h +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.h @@ -479,7 +479,7 @@ namespace ZEngine::Hardwares struct CommandBufferManager { - void Initialize(VulkanDevice* device, uint8_t swapchain_image_count = 3, int thread_count = 1); + void Initialize(VulkanDevice* device, int thread_count = 1); void Deinitialize(); CommandBuffer* GetCommandBuffer(uint8_t frame_index, bool begin = true); CommandBuffer* GetInstantCommandBuffer(Rendering::QueueType type, uint8_t frame_index, bool begin = true); @@ -487,17 +487,26 @@ namespace ZEngine::Hardwares Rendering::Pools::CommandPool* GetCommandPool(Rendering::QueueType type, uint8_t frame_index); int GetPoolFromIndex(Rendering::QueueType type, uint8_t index); void ResetPool(int frame_index); - - VulkanDevice* Device = nullptr; - const int MaxBufferPerPool = 4; - Core::Containers::Array CommandPools = {}; - Core::Containers::Array TransferCommandPools = {}; - Core::Containers::Array CommandBuffers = {}; - Core::Containers::Array TransferCommandBuffers = {}; - int TotalCommandBufferCount = 0; + void IncreaseBuffers(); + void EnqueueBuffer(CommandBufferPtr const buffer); + void EndEnqueuedBuffers(); + void ResetEnqueuedBufferIndex(); + bool IsInitialized() const; + + VulkanDevice* Device = nullptr; + const int MaxBufferPerPool = 4; + Core::Containers::Array CommandPools = {}; + Core::Containers::Array TransferCommandPools = {}; + Core::Containers::Array CommandBuffers = {}; + Core::Containers::Array TransferCommandBuffers = {}; + int TotalCommandBufferCount = 0; + uint32_t EnqueuedCommandbufferIndex = 0; + Core::Containers::Array EnqueuedCommandbuffers = {}; private: - int m_total_pool_count{0}; + bool m_is_initialized = false; + int m_total_pool_count = 0; + int m_thread_count = 1; std::condition_variable m_cond; std::atomic_bool m_executing_instant_command{false}; std::mutex m_instant_command_mutex; @@ -541,6 +550,8 @@ namespace ZEngine::Hardwares const char* ApplicationName = "Tetragrama"; const char* EngineName = "ZEngine"; uint32_t SwapchainImageCount = 3; + uint32_t PreviousSwapchainImageCount = 3; + uint32_t SwapchainImageCountChangeCount = 0; uint32_t SwapchainImageIndex = std::numeric_limits::max(); uint32_t CurrentFrameIndex = std::numeric_limits::max(); uint32_t PreviousFrameIndex = std::numeric_limits::max(); @@ -548,7 +559,7 @@ namespace ZEngine::Hardwares uint32_t SwapchainImageHeight = std::numeric_limits::max(); uint32_t GraphicFamilyIndex = std::numeric_limits::max(); uint32_t TransferFamilyIndex = std::numeric_limits::max(); - uint32_t EnqueuedCommandbufferIndex = 0; + uint32_t WriteDescriptorSetIndex = 0; uint32_t MaxGlobalTexture = 600; VkInstance Instance = VK_NULL_HANDLE; @@ -571,7 +582,7 @@ namespace ZEngine::Hardwares Core::Containers::Array SwapchainAcquiredSemaphores = {}; Core::Containers::Array SwapchainRenderCompleteSemaphores = {}; Core::Containers::Array SwapchainSignalFences = {}; - Core::Containers::Array EnqueuedCommandbuffers = {}; + Core::Containers::HashMap> ShaderCaches = {}; Core::Containers::HashMap> ShaderReservedDescriptorSetMap = {}; //> Core::Containers::HashMap ShaderReservedDescriptorSetLayoutMap = {}; // From d41b5057443ea3057d228c2caf57a31483163c4a Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Thu, 29 Jan 2026 17:08:30 +0900 Subject: [PATCH 11/15] prevent swapchain image count change in after first creation --- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 52 +++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index 738dbadb..c5059e03 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -2194,7 +2194,57 @@ namespace ZEngine::Hardwares m_total_pool_count = Device->SwapchainImageCount * m_thread_count; TotalCommandBufferCount = m_total_pool_count * MaxBufferPerPool; - + if (TotalCommandBufferCount > EnqueuedCommandbuffers.size()) + { + auto size = EnqueuedCommandbuffers.size(); + for (uint32_t i = size; i < TotalCommandBufferCount; ++i) + { + EnqueuedCommandbuffers.push(nullptr); + } + } + + if (m_total_pool_count > CommandPools.size()) + { + auto size = CommandPools.size(); + for (uint32_t i = size; i < TotalCommandBufferCount; ++i) + { + CommandPools.push(ZPushStructCtorArgs(Device->Arena, Rendering::Pools::CommandPool, Device, Rendering::QueueType::GRAPHIC_QUEUE)); + } + } + + if (TotalCommandBufferCount > CommandBuffers.size()) + { + auto size = CommandBuffers.size(); + for (uint32_t i = size; i < TotalCommandBufferCount; ++i) + { + int pool_index = GetPoolFromIndex(Rendering::QueueType::GRAPHIC_QUEUE, i); + auto& pool = CommandPools[pool_index]; + CommandBuffers.push(ZPushStructCtorArgs( + Device->Arena, + CommandBuffer, + Device, + pool->Handle, + pool->QueueType, + /*(i % MaxBufferPerPool) == 0 ? false : true */ false)); + } + } + + if (Device->HasSeperateTransfertQueueFamily) + { + auto size = TransferCommandPools.size(); + for (uint32_t i = size; i < TotalCommandBufferCount; ++i) + { + TransferCommandPools.push(ZPushStructCtorArgs(Device->Arena, Rendering::Pools::CommandPool, Device, Rendering::QueueType::TRANSFER_QUEUE)); + } + + size = TransferCommandBuffers.size(); + for (uint32_t i = size; i < TotalCommandBufferCount; ++i) + { + int pool_index = GetPoolFromIndex(Rendering::QueueType::TRANSFER_QUEUE, i); + auto& pool = TransferCommandPools[pool_index]; + TransferCommandBuffers.push(ZPushStructCtorArgs(Device->Arena, CommandBuffer, Device, pool->Handle, pool->QueueType, true)); + } + } } bool CommandBufferManager::IsInitialized() const From 68fcc57b2639268511031c485cc0eeb0265ceb46 Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Sun, 1 Feb 2026 20:32:40 +0900 Subject: [PATCH 12/15] fixed string deref --- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 4 +- ZEngine/ZEngine/Helpers/MemoryOperations.h | 16 +- .../Rendering/Renderers/GraphicRenderer.cpp | 6 +- .../Renderers/RenderPasses/RenderPass.cpp | 6 +- ZEngine/ZEngine/Rendering/Shaders/Shader.cpp | 148 +++++++++++------- 5 files changed, 106 insertions(+), 74 deletions(-) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index c5059e03..3489ba18 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -1901,7 +1901,7 @@ namespace ZEngine::Hardwares auto pipeline_layout = pipeline->Layout; auto shader = pipeline->Shader; const auto& set_layout = shader->SetLayouts; - auto& descriptor_set_map = shader->DescriptorSetMap; + const auto& descriptor_set_map = shader->DescriptorSetMap; auto scratch = ZGetScratch(&LocalArena); Array frame_sets = {}; @@ -1911,7 +1911,7 @@ namespace ZEngine::Hardwares // We're safe to use index as Set for (uint32_t i = 0; i < set_layout.size(); ++i) { - frame_sets.push(descriptor_set_map[i][frame_index]); + frame_sets.push(descriptor_set_map.at(i)[frame_index]); } vkCmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, frame_sets.size(), frame_sets.data(), 0, nullptr); diff --git a/ZEngine/ZEngine/Helpers/MemoryOperations.h b/ZEngine/ZEngine/Helpers/MemoryOperations.h index 235d17f1..fcf8b105 100644 --- a/ZEngine/ZEngine/Helpers/MemoryOperations.h +++ b/ZEngine/ZEngine/Helpers/MemoryOperations.h @@ -104,13 +104,7 @@ namespace ZEngine::Helpers inline int secure_strcpy(char* dest, size_t destSize, const char* src) { - if (!dest || !src) - { - return MEMORY_OP_FAILURE; - } - - size_t srcLength = secure_strlen(src); - if (srcLength + 1 > destSize) + if (!dest || !src || destSize == 0) { return MEMORY_OP_FAILURE; } @@ -119,6 +113,14 @@ namespace ZEngine::Helpers errno_t err = strcpy_s(dest, destSize, src); return (err == 0) ? MEMORY_OP_SUCCESS : MEMORY_OP_FAILURE; #else + // Manual bounds-checked implementation for portability + + size_t src_len = secure_strlen(src); + if (src_len + 1 > destSize) + { + return MEMORY_OP_FAILURE; + } + return (std::strcpy(dest, src) == dest) ? MEMORY_OP_SUCCESS : MEMORY_OP_FAILURE; #endif } diff --git a/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp b/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp index 495548f8..7523cf25 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp @@ -82,10 +82,10 @@ namespace ZEngine::Rendering::Renderers RenderGraph->AddCallbackPass("Initial Pass", initial_pass); RenderGraph->AddCallbackPass("Depth Pre-Pass", scene_depth_prepass); - // RenderGraph->AddCallbackPass("Skybox Pass", skybox_pass); + // RenderGraph->AddCallbackPass("Skybox Pass", skybox_pass); RenderGraph->AddCallbackPass("Grid Pass", grid_pass); - RenderGraph->AddCallbackPass("G-Buffer Pass", gbuffer_pass); - // RenderGraph->AddCallbackPass("Lighting Pass", lighting_pass); + // RenderGraph->AddCallbackPass("G-Buffer Pass", gbuffer_pass); + // RenderGraph->AddCallbackPass("Lighting Pass", lighting_pass); RenderGraph->Setup(); RenderGraph->Compile(); diff --git a/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp b/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp index 5bed25cb..211cb141 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp @@ -146,7 +146,7 @@ namespace ZEngine::Rendering::Renderers::RenderPasses const auto& spec = validity_output.second; auto shader = Pipeline->Shader; - auto descriptor_set_map = shader->DescriptorSetMap; + const auto& descriptor_set_map = shader->DescriptorSetMap; auto frame_count = m_device->SwapchainImageCount; auto ubo_buf = m_device->UniformBufferSetManager.Access(handle); auto write_reqs = std::vector(frame_count); @@ -177,7 +177,7 @@ namespace ZEngine::Rendering::Renderers::RenderPasses const auto& spec = validity_output.second; auto shader = Pipeline->Shader; - auto descriptor_set_map = shader->DescriptorSetMap; + const auto& descriptor_set_map = shader->DescriptorSetMap; auto frame_count = m_device->SwapchainImageCount; auto sbo_buf = m_device->StorageBufferSetManager.Access(handle); auto write_reqs = std::vector(frame_count); @@ -209,7 +209,7 @@ namespace ZEngine::Rendering::Renderers::RenderPasses const auto& spec = validity_output.second; auto shader = Pipeline->Shader; - auto descriptor_set_map = shader->DescriptorSetMap; + const auto& descriptor_set_map = shader->DescriptorSetMap; auto frame_count = m_device->SwapchainImageCount; auto tex_buf = m_device->GlobalTextures.Access(handle); auto img_buf = m_device->Image2DBufferManager.Access(tex_buf->BufferHandle); diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp index c2e2c64d..8e797ec6 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -34,14 +35,15 @@ namespace ZEngine::Rendering::Shaders m_device = device; m_specification = spec; - ShaderCreateInfos.init(device->Arena, 4); - ShaderModules.init(device->Arena, 3); - PushConstants.init(device->Arena, 4); - PushConstantSpecifications.init(device->Arena, 4); - LayoutBindingSpecificationMap.init(device->Arena, 4); - LayoutBindingSpecifications.init(device->Arena, 5); - SetLayouts.init(device->Arena, 5); - InternalDescriptorSetLayoutMap.init(device->Arena, 5); + ShaderCreateInfos.init(m_device->Arena, 4); + ShaderModules.init(m_device->Arena, 3); + PushConstants.init(m_device->Arena, 4); + PushConstantSpecifications.init(m_device->Arena, 4); + LayoutBindingSpecificationMap.init(m_device->Arena, 4); + LayoutBindingSpecifications.init(m_device->Arena, 5); + SetLayouts.init(m_device->Arena, 5); + InternalDescriptorSetLayoutMap.init(m_device->Arena, 5); + DescriptorSetMap.init(m_device->Arena, 5); CreateModule(); CreateDescriptorSetLayouts(); @@ -56,7 +58,7 @@ namespace ZEngine::Rendering::Shaders for (auto set : ordered_sets) { - SetLayouts.push(InternalDescriptorSetLayoutMap[set]); + SetLayouts.push(InternalDescriptorSetLayoutMap.at(set)); } } @@ -69,20 +71,18 @@ namespace ZEngine::Rendering::Shaders } // We remove the Set to avoid double release from the Device and Shader owned resource - for (const auto& [set, _] : m_device->ShaderReservedDescriptorSetLayoutMap) + for (const auto [set, _] : m_device->ShaderReservedDescriptorSetLayoutMap) { if (InternalDescriptorSetLayoutMap.contains(set)) { InternalDescriptorSetLayoutMap.remove(set); } } - - LocalArena.Clear(); } void Shader::CreateModule() { - ZRawPtr(spirv_cross::Compiler) spirv_compiler = nullptr; + Scope spirv_compiler = nullptr; /* * Vertex Shader processing @@ -104,7 +104,7 @@ namespace ZEngine::Rendering::Shaders /* * Source Reflection */ - spirv_compiler = ZPushStructCtorArgs(&LocalArena, spirv_cross::Compiler, vertex_shader_binary_code); + spirv_compiler = CreateScope(vertex_shader_binary_code); auto vertex_resources = spirv_compiler->get_shader_resources(); for (const auto& UB_resource : vertex_resources.uniform_buffers) { @@ -116,7 +116,10 @@ namespace ZEngine::Rendering::Shaders LayoutBindingSpecificationMap[set].init(m_device->Arena, 10); } - LayoutBindingSpecificationMap[set].push(LayoutBindingSpecification{.Set = set, .Binding = binding, .Name = UB_resource.name.c_str(), .DescriptorTypeValue = DescriptorType::UNIFORM_BUFFER, .Flags = ShaderStageFlags::VERTEX}); + auto name_c_size = (UB_resource.name.size() + 1u); + auto name_c_str = ZPushString(&LocalArena, name_c_size); + Helpers::secure_strcpy(name_c_str, name_c_size, UB_resource.name.c_str()); + LayoutBindingSpecificationMap[set].push(LayoutBindingSpecification{.Set = set, .Binding = binding, .Name = name_c_str, .DescriptorTypeValue = DescriptorType::UNIFORM_BUFFER, .Flags = ShaderStageFlags::VERTEX}); } for (const auto& SB_resource : vertex_resources.storage_buffers) @@ -129,7 +132,10 @@ namespace ZEngine::Rendering::Shaders LayoutBindingSpecificationMap[set].init(m_device->Arena, 10); } - LayoutBindingSpecificationMap[set].push(LayoutBindingSpecification{.Set = set, .Binding = binding, .Name = SB_resource.name.c_str(), .DescriptorTypeValue = DescriptorType::STORAGE_BUFFER, .Flags = ShaderStageFlags::VERTEX}); + auto name_c_size = (SB_resource.name.size() + 1u); + auto name_c_str = ZPushString(&LocalArena, name_c_size); + Helpers::secure_strcpy(name_c_str, name_c_size, SB_resource.name.c_str()); + LayoutBindingSpecificationMap[set].push(LayoutBindingSpecification{.Set = set, .Binding = binding, .Name = name_c_str, .DescriptorTypeValue = DescriptorType::STORAGE_BUFFER, .Flags = ShaderStageFlags::VERTEX}); } for (const auto& pushConstant_resource : vertex_resources.push_constant_buffers) @@ -145,7 +151,11 @@ namespace ZEngine::Rendering::Shaders uint32_t memberSize = spirv_compiler->get_declared_struct_member_size(type, i); struct_total_size += memberSize; } - PushConstantSpecifications.push(PushConstantSpecification{.Name = pushConstant_resource.name.c_str(), .Size = struct_total_size, .Offset = struct_offset, .Flags = ShaderStageFlags::VERTEX}); + + auto name_c_size = (pushConstant_resource.name.size() + 1u); + auto name_c_str = ZPushString(&LocalArena, name_c_size); + Helpers::secure_strcpy(name_c_str, name_c_size, pushConstant_resource.name.c_str()); + PushConstantSpecifications.push(PushConstantSpecification{.Name = name_c_str, .Size = struct_total_size, .Offset = struct_offset, .Flags = ShaderStageFlags::VERTEX}); /* * We update the offset for next iteration */ @@ -173,7 +183,7 @@ namespace ZEngine::Rendering::Shaders /* * Source Reflection */ - spirv_compiler = ZPushStructCtorArgs(&LocalArena, spirv_cross::Compiler, fragment_shader_binary_code); + spirv_compiler = CreateScope(fragment_shader_binary_code); auto fragment_resources = spirv_compiler->get_shader_resources(); for (const auto& UB_resource : fragment_resources.uniform_buffers) { @@ -185,7 +195,11 @@ namespace ZEngine::Rendering::Shaders LayoutBindingSpecificationMap[set].init(m_device->Arena, 10); } - LayoutBindingSpecificationMap[set].push(LayoutBindingSpecification{.Set = set, .Binding = binding, .Name = UB_resource.name.c_str(), .DescriptorTypeValue = DescriptorType::UNIFORM_BUFFER, .Flags = ShaderStageFlags::FRAGMENT}); + auto name_c_size = (UB_resource.name.size() + 1u); + auto name_c_str = ZPushString(&LocalArena, name_c_size); + Helpers::secure_strcpy(name_c_str, name_c_size, UB_resource.name.c_str()); + + LayoutBindingSpecificationMap[set].push(LayoutBindingSpecification{.Set = set, .Binding = binding, .Name = name_c_str, .DescriptorTypeValue = DescriptorType::UNIFORM_BUFFER, .Flags = ShaderStageFlags::FRAGMENT}); } for (const auto& SB_resource : fragment_resources.storage_buffers) @@ -195,10 +209,12 @@ namespace ZEngine::Rendering::Shaders if (LayoutBindingSpecificationMap.at(set).capacity() <= 0) { - LayoutBindingSpecificationMap[set].init(m_device->Arena, 10); + LayoutBindingSpecificationMap[set].init(&LocalArena, 10); } - - LayoutBindingSpecificationMap[set].push(LayoutBindingSpecification{.Set = set, .Binding = binding, .Name = SB_resource.name.c_str(), .DescriptorTypeValue = DescriptorType::STORAGE_BUFFER, .Flags = ShaderStageFlags::FRAGMENT}); + auto name_c_size = (SB_resource.name.size() + 1u); + auto name_c_str = ZPushString(&LocalArena, name_c_size); + Helpers::secure_strcpy(name_c_str, name_c_size, SB_resource.name.c_str()); + LayoutBindingSpecificationMap[set].push(LayoutBindingSpecification{.Set = set, .Binding = binding, .Name = name_c_str, .DescriptorTypeValue = DescriptorType::STORAGE_BUFFER, .Flags = ShaderStageFlags::FRAGMENT}); } for (const auto& pushConstant_resource : fragment_resources.push_constant_buffers) @@ -214,7 +230,11 @@ namespace ZEngine::Rendering::Shaders uint32_t memberSize = spirv_compiler->get_declared_struct_member_size(type, i); struct_total_size += memberSize; } - PushConstantSpecifications.push(PushConstantSpecification{.Name = pushConstant_resource.name.c_str(), .Size = struct_total_size, .Offset = struct_offset, .Flags = ShaderStageFlags::FRAGMENT}); + auto name_c_size = (pushConstant_resource.name.size() + 1u); + auto name_c_str = ZPushString(&LocalArena, name_c_size); + Helpers::secure_strcpy(name_c_str, name_c_size, pushConstant_resource.name.c_str()); + + PushConstantSpecifications.push(PushConstantSpecification{.Name = name_c_str, .Size = struct_total_size, .Offset = struct_offset, .Flags = ShaderStageFlags::FRAGMENT}); /* * We update the offset for next iteration */ @@ -229,7 +249,7 @@ namespace ZEngine::Rendering::Shaders if (m_device->ShaderReservedLayoutBindingSpecificationMap.contains(set)) { const auto& binding_specifications = m_device->ShaderReservedLayoutBindingSpecificationMap[set]; - LayoutBindingSpecificationMap[set].init(m_device->Arena, binding_specifications.size(), binding_specifications.size()); + LayoutBindingSpecificationMap[set].init(&LocalArena, binding_specifications.size(), binding_specifications.size()); for (uint32_t i = 0; i < binding_specifications.size(); ++i) { @@ -245,10 +265,13 @@ namespace ZEngine::Rendering::Shaders if (LayoutBindingSpecificationMap[set].capacity() <= 0) { - LayoutBindingSpecificationMap[set].init(m_device->Arena, 10); + LayoutBindingSpecificationMap[set].init(&LocalArena, 10); } + auto name_c_size = (SI_resource.name.size() + 1u); + auto name_c_str = ZPushString(&LocalArena, name_c_size); + Helpers::secure_strcpy(name_c_str, name_c_size, SI_resource.name.c_str()); - LayoutBindingSpecificationMap[set].push(LayoutBindingSpecification{.Set = set, .Binding = binding, .Count = count, .Name = SI_resource.name.c_str(), .DescriptorTypeValue = DescriptorType::COMBINED_IMAGE_SAMPLER, .Flags = ShaderStageFlags::FRAGMENT}); + LayoutBindingSpecificationMap[set].push(LayoutBindingSpecification{.Set = set, .Binding = binding, .Count = count, .Name = name_c_str, .DescriptorTypeValue = DescriptorType::COMBINED_IMAGE_SAMPLER, .Flags = ShaderStageFlags::FRAGMENT}); } } } @@ -299,31 +322,35 @@ namespace ZEngine::Rendering::Shaders void Shader::CreateDescriptorSetLayouts() { + auto scratch = ZGetScratch(&LocalArena); + Array pool_size_collection = {}; - pool_size_collection.init(&LocalArena, 10); + pool_size_collection.init(scratch.Arena, 10); - for (const auto& layout_binding_set : LayoutBindingSpecificationMap) + Array layout_binding_collection = {}; + layout_binding_collection.init(scratch.Arena, 10); + + for (const auto layout_binding_set : LayoutBindingSpecificationMap) { uint32_t binding_set = layout_binding_set.first; if (m_device->ShaderReservedLayoutBindingSpecificationMap.contains(binding_set)) { // Since it's a reserved Set The device already created its SetLayout - InternalDescriptorSetLayoutMap[binding_set] = m_device->ShaderReservedDescriptorSetLayoutMap[binding_set]; + InternalDescriptorSetLayoutMap[binding_set] = m_device->ShaderReservedDescriptorSetLayoutMap.at(binding_set); continue; } - Array layout_binding_collection = {}; - layout_binding_collection.init(&LocalArena, 10); for (uint32_t i = 0; i < layout_binding_set.second.size(); ++i) { layout_binding_collection.push(VkDescriptorSetLayoutBinding{.binding = layout_binding_set.second[i].Binding, .descriptorType = DescriptorTypeMap[static_cast(layout_binding_set.second[i].DescriptorTypeValue)], .descriptorCount = layout_binding_set.second[i].Count, .stageFlags = ShaderStageFlagsMap[static_cast(layout_binding_set.second[i].Flags)], .pImmutableSamplers = nullptr}); } + /* * Binding flag extension */ Array binding_flags_collection = {}; - binding_flags_collection.init(&LocalArena, layout_binding_collection.size(), layout_binding_collection.size()); + binding_flags_collection.init(scratch.Arena, layout_binding_collection.size(), layout_binding_collection.size()); for (uint32_t i = 0; i < layout_binding_collection.size(); ++i) { binding_flags_collection[i] = 0; // We zeroing as we iterate @@ -360,43 +387,39 @@ namespace ZEngine::Rendering::Shaders ZENGINE_VALIDATE_ASSERT(vkCreateDescriptorSetLayout(m_device->LogicalDevice, &descriptor_set_layout_create_info, nullptr, &descriptor_set_layout) == VK_SUCCESS, "Failed to create DescriptorSetLayout") InternalDescriptorSetLayoutMap[binding_set] = std::move(descriptor_set_layout); - /* - * Packing PoolSize - */ - for (const auto& layout_binding : layout_binding_collection) - { - auto find_pool_size_it = std::find_if(pool_size_collection.begin(), pool_size_collection.end(), [&](const VkDescriptorPoolSize& pool_size) { return (layout_binding.descriptorType == pool_size.type); }); + } - if (find_pool_size_it == std::end(pool_size_collection)) - { - pool_size_collection.push(VkDescriptorPoolSize{.type = layout_binding.descriptorType, .descriptorCount = layout_binding.descriptorCount}); - continue; - } - /* - * ToDo: we should check the limit against the device.. - */ - find_pool_size_it->descriptorCount += layout_binding.descriptorCount; + /* + * Packing PoolSize + */ + for (const auto& layout_binding : layout_binding_collection) + { + auto find_pool_size_it = std::find_if(pool_size_collection.begin(), pool_size_collection.end(), [&](const VkDescriptorPoolSize& pool_size) { return (layout_binding.descriptorType == pool_size.type); }); + + if (find_pool_size_it == std::end(pool_size_collection)) + { + pool_size_collection.push(VkDescriptorPoolSize{.type = layout_binding.descriptorType, .descriptorCount = layout_binding.descriptorCount}); + continue; } /* - * Ensure correctness with number of frame count + * ToDo: we should check the limit against the device.. */ - for (auto& pool_size : pool_size_collection) - { - pool_size.descriptorCount *= m_device->SwapchainImageCount; - } + find_pool_size_it->descriptorCount += layout_binding.descriptorCount; } - /* - * Creating DescriptorPool and DescriptorSet + * Ensure correctness with number of frame count */ - DescriptorSetMap.init(m_device->Arena, 5); - + for (auto& pool_size : pool_size_collection) + { + pool_size.descriptorCount *= m_device->SwapchainImageCount; + } /* * Create DescriptorPool */ if (pool_size_collection.empty()) { ZENGINE_CORE_WARN("Shader: - The pool size is empty!") + ZReleaseScratch(scratch); return; } @@ -409,25 +432,30 @@ namespace ZEngine::Rendering::Shaders ZENGINE_VALIDATE_ASSERT(vkCreateDescriptorPool(m_device->LogicalDevice, &pool_info, nullptr, &m_descriptor_pool) == VK_SUCCESS, "Failed to create DescriptorPool") + ZReleaseScratch(scratch); + /* * Create DescriptorSet */ - for (const auto& layout : InternalDescriptorSetLayoutMap) + for (const auto layout : InternalDescriptorSetLayoutMap) { DescriptorSetMap[layout.first].init(m_device->Arena, m_device->SwapchainImageCount, m_device->SwapchainImageCount); + if (m_device->ShaderReservedDescriptorSetMap.contains(layout.first)) { // Since it's a Reserved Set, the Device already created the DescriptorSet for (uint32_t i = 0; i < m_device->SwapchainImageCount; ++i) { - DescriptorSetMap[layout.first][i] = m_device->ShaderReservedDescriptorSetMap[layout.first][i]; + DescriptorSetMap[layout.first][i] = m_device->ShaderReservedDescriptorSetMap.at(layout.first)[i]; } continue; } + auto scratch = ZGetScratch(&LocalArena); + Array layout_set = {}; - layout_set.init(&LocalArena, m_device->SwapchainImageCount, m_device->SwapchainImageCount); + layout_set.init(scratch.Arena, m_device->SwapchainImageCount, m_device->SwapchainImageCount); for (uint32_t i = 0; i < m_device->SwapchainImageCount; ++i) { layout_set[i] = layout.second; @@ -439,6 +467,8 @@ namespace ZEngine::Rendering::Shaders descriptor_set_allocate_info.descriptorSetCount = m_device->SwapchainImageCount; descriptor_set_allocate_info.pSetLayouts = layout_set.data(); ZENGINE_VALIDATE_ASSERT(vkAllocateDescriptorSets(m_device->LogicalDevice, &descriptor_set_allocate_info, DescriptorSetMap[layout.first].data()) == VK_SUCCESS, "Failed to create DescriptorSet") + + ZReleaseScratch(scratch); } } From d6fb5820ad39162291cfdc669ace302ff3038223 Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Mon, 2 Feb 2026 15:58:06 +0900 Subject: [PATCH 13/15] filled dummy set for imgui --- ZEngine/ZEngine/Hardwares/VulkanDevice.cpp | 9 ++++---- ZEngine/ZEngine/Helpers/MemoryOperations.h | 10 ++++----- .../Rendering/Renderers/ImGUIRenderer.cpp | 21 +++++++++++++++++-- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp index 3489ba18..8a5ee66f 100644 --- a/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp +++ b/ZEngine/ZEngine/Hardwares/VulkanDevice.cpp @@ -2623,11 +2623,12 @@ namespace ZEngine::Hardwares size_t data_size = width * height * byte_per_pixel; Array image_data = {}; + image_data.init(scratch.Arena, data_size, data_size); - unsigned char r_byte = static_cast(std::clamp(r * 255.0f, 0.0f, 255.0f)); - unsigned char g_byte = static_cast(std::clamp(g * 255.0f, 0.0f, 255.0f)); - unsigned char b_byte = static_cast(std::clamp(b * 255.0f, 0.0f, 255.0f)); - unsigned char a_byte = static_cast(std::clamp(a * 255.0f, 0.0f, 255.0f)); + unsigned char r_byte = static_cast(std::clamp(r * 255.0f, 0.0f, 255.0f)); + unsigned char g_byte = static_cast(std::clamp(g * 255.0f, 0.0f, 255.0f)); + unsigned char b_byte = static_cast(std::clamp(b * 255.0f, 0.0f, 255.0f)); + unsigned char a_byte = static_cast(std::clamp(a * 255.0f, 0.0f, 255.0f)); for (size_t i = 0; i < data_size; i += byte_per_pixel) { diff --git a/ZEngine/ZEngine/Helpers/MemoryOperations.h b/ZEngine/ZEngine/Helpers/MemoryOperations.h index fcf8b105..ed62e781 100644 --- a/ZEngine/ZEngine/Helpers/MemoryOperations.h +++ b/ZEngine/ZEngine/Helpers/MemoryOperations.h @@ -109,18 +109,16 @@ namespace ZEngine::Helpers return MEMORY_OP_FAILURE; } -#if SECURE_C11_FUNCTIONS_AVAILABLE - errno_t err = strcpy_s(dest, destSize, src); - return (err == 0) ? MEMORY_OP_SUCCESS : MEMORY_OP_FAILURE; -#else - // Manual bounds-checked implementation for portability - size_t src_len = secure_strlen(src); if (src_len + 1 > destSize) { return MEMORY_OP_FAILURE; } +#if SECURE_C11_FUNCTIONS_AVAILABLE + errno_t err = strcpy_s(dest, destSize, src); + return (err == 0) ? MEMORY_OP_SUCCESS : MEMORY_OP_FAILURE; +#else return (std::strcpy(dest, src) == dest) ? MEMORY_OP_SUCCESS : MEMORY_OP_FAILURE; #endif } diff --git a/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp b/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp index 6f39fefd..ee69902f 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp @@ -152,9 +152,17 @@ namespace ZEngine::Rendering::Renderers img_buf->Layout = barrier_spec_1.NewLayout; Device->EnqueueInstantCommandBuffer(command_buf); + /* + * Dummy Texture + */ + auto dummy_tex_handle = Device->CreateTexture(1, 1, 255, 255, 255, 255); + auto dummy_tex_res = Device->GlobalTextures.Access(dummy_tex_handle); + auto dummy_tex_buf = Device->Image2DBufferManager.Access(dummy_tex_res->BufferHandle); + io.Fonts->TexID = (ImTextureID) font_tex_handle.Index; auto font_image_info = img_buf->GetDescriptorImageInfo(); + auto dummy_image_info = dummy_tex_buf->GetDescriptorImageInfo(); uint32_t frame_count = Device->SwapchainImageCount; auto shader = m_ui_pass->Pipeline->Shader; auto& descriptor_set_map = shader->DescriptorSetMap; @@ -165,8 +173,17 @@ namespace ZEngine::Rendering::Renderers for (unsigned i = 0; i < frame_count; ++i) { - auto set = descriptor_set_map.at(1)[i]; - write_descriptor_sets.push(VkWriteDescriptorSet{.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = set, .dstBinding = 0, .dstArrayElement = (uint32_t) font_tex_handle.Index, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &(font_image_info), .pBufferInfo = nullptr, .pTexelBufferView = nullptr}); + for (const auto& [set, arr] : descriptor_set_map) + { + auto frame_set = arr[i]; + if (set == 0) // __unused + { + write_descriptor_sets.push(VkWriteDescriptorSet{.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = frame_set, .dstBinding = 0, .dstArrayElement = 0u /*(uint32_t) dummy_tex_handle.Index*/, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &(dummy_image_info), .pBufferInfo = nullptr, .pTexelBufferView = nullptr}); + continue; + } + + write_descriptor_sets.push(VkWriteDescriptorSet{.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = frame_set, .dstBinding = 0, .dstArrayElement = (uint32_t) font_tex_handle.Index, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &(font_image_info), .pBufferInfo = nullptr, .pTexelBufferView = nullptr}); + } } vkUpdateDescriptorSets(Device->LogicalDevice, write_descriptor_sets.size(), write_descriptor_sets.data(), 0, nullptr); From 0cb693542dfaae920c918ac8fdf2a45456be6ced Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Mon, 2 Feb 2026 09:44:51 +0000 Subject: [PATCH 14/15] fixed usage of Shader LocalArena --- ZEngine/ZEngine/Rendering/Shaders/Shader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp index 8e797ec6..488cbd20 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.cpp @@ -209,7 +209,7 @@ namespace ZEngine::Rendering::Shaders if (LayoutBindingSpecificationMap.at(set).capacity() <= 0) { - LayoutBindingSpecificationMap[set].init(&LocalArena, 10); + LayoutBindingSpecificationMap[set].init(m_device->Arena, 10); } auto name_c_size = (SB_resource.name.size() + 1u); auto name_c_str = ZPushString(&LocalArena, name_c_size); @@ -249,7 +249,7 @@ namespace ZEngine::Rendering::Shaders if (m_device->ShaderReservedLayoutBindingSpecificationMap.contains(set)) { const auto& binding_specifications = m_device->ShaderReservedLayoutBindingSpecificationMap[set]; - LayoutBindingSpecificationMap[set].init(&LocalArena, binding_specifications.size(), binding_specifications.size()); + LayoutBindingSpecificationMap[set].init(m_device->Arena, binding_specifications.size(), binding_specifications.size()); for (uint32_t i = 0; i < binding_specifications.size(); ++i) { @@ -265,7 +265,7 @@ namespace ZEngine::Rendering::Shaders if (LayoutBindingSpecificationMap[set].capacity() <= 0) { - LayoutBindingSpecificationMap[set].init(&LocalArena, 10); + LayoutBindingSpecificationMap[set].init(m_device->Arena, 10); } auto name_c_size = (SI_resource.name.size() + 1u); auto name_c_str = ZPushString(&LocalArena, name_c_size); From 7cb797c9340e846f943f4b0d342986ba7b955feb Mon Sep 17 00:00:00 2001 From: Jean Philippe Date: Tue, 3 Feb 2026 01:42:33 +0900 Subject: [PATCH 15/15] fixed rendering on wrong framebuffer --- ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp b/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp index ee69902f..c49a911c 100644 --- a/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp +++ b/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp @@ -312,7 +312,7 @@ namespace ZEngine::Rendering::Renderers ZReleaseScratch(scratch); - auto current_framebuffer = Device->SwapchainFramebuffers[Device->CurrentFrameIndex]; + auto current_framebuffer = Device->SwapchainFramebuffers[Device->SwapchainImageIndex]; command_buffer->BeginRenderPass(m_ui_pass, current_framebuffer); command_buffer->BindVertexBuffer(*vertex_buffer);