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 5eff9d9e..8a5ee66f 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); @@ -191,11 +190,15 @@ 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 +206,8 @@ namespace ZEngine::Hardwares 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; } @@ -287,34 +292,43 @@ 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(); - 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; - device_create_info.pNext = &device_features_2; + 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; + device_features_2.features.samplerAnisotropy = PhysicalDeviceFeature.features.samplerAnisotropy; + device_features_2.features.shaderInt64 = PhysicalDeviceFeature.features.shaderInt64; + + if (PhysicalDeviceSupportSampledImageBindless || PhysicalDeviceSupportStorageBufferBindless) + { + 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; + + 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") @@ -395,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 */ @@ -414,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); @@ -424,7 +437,113 @@ 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 + */ + 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); @@ -451,7 +570,6 @@ namespace ZEngine::Hardwares UniformBufferSetManager.Dispose(); ShaderManager.Dispose(); - EnqueuedCommandbuffers.clear(); SwapchainSignalFences.clear(); SwapchainAcquiredSemaphores.clear(); SwapchainRenderCompleteSemaphores.clear(); @@ -464,6 +582,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(); @@ -893,8 +1023,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; @@ -1091,21 +1221,49 @@ 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); - SwapchainImageCount = image_count; - ZENGINE_CORE_WARN("Swapchain image count has changed from {} to {}", SwapchainImageCount, image_count); + 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) + + swapchainImageCountChanged = true; } - if (SwapchainImageViews.capacity() <= 0) + if ((SwapchainImageCountChangeCount > 0) && (PreviousSwapchainImageCount != SwapchainImageCount)) { - SwapchainImageViews.init(Arena, SwapchainImageCount, SwapchainImageCount); - } + ZENGINE_CORE_WARN("Swapchain image count has changed from previous creation") - if (SwapchainFramebuffers.capacity() <= 0) + 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 { - SwapchainFramebuffers.init(Arena, SwapchainImageCount, SwapchainImageCount); + if (SwapchainImageViews.capacity() <= 0) + { + SwapchainImageViews.init(Arena, SwapchainImageCount, SwapchainImageCount); + } + + if (SwapchainFramebuffers.capacity() <= 0) + { + SwapchainFramebuffers.init(Arena, SwapchainImageCount, SwapchainImageCount); + } + + if (!m_buffer_manager.IsInitialized()) + { + m_buffer_manager.Initialize(this); + } } scratch = ZGetScratch(Arena); @@ -1147,6 +1305,11 @@ namespace ZEngine::Hardwares } ZReleaseScratch(scratch); + + if (swapchainImageCountChanged) + { + SwapchainImageCountChangeCount++; + } } void VulkanDevice::ResizeSwapchain() @@ -1161,6 +1324,8 @@ namespace ZEngine::Hardwares void VulkanDevice::DisposeSwapchain() { + PreviousSwapchainImageCount = SwapchainImageCount; + for (VkImageView image_view : SwapchainImageViews) { if (image_view) @@ -1259,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.") @@ -1283,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); @@ -1294,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); @@ -1341,7 +1502,7 @@ namespace ZEngine::Hardwares void VulkanDevice::EnqueueCommandBuffer(CommandBuffer* const buffer) { - EnqueuedCommandbuffers[EnqueuedCommandbufferIndex++] = buffer; + m_buffer_manager.EnqueueBuffer(buffer); } void VulkanDevice::DirtyCollector() @@ -1739,15 +1900,18 @@ namespace ZEngine::Hardwares auto pipeline = render_pass->Pipeline; auto pipeline_layout = pipeline->Layout; auto shader = pipeline->Shader; - auto& descriptor_set_map = shader->DescriptorSetMap; + const auto& set_layout = shader->SetLayouts; + const 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.at(i)[frame_index]); } vkCmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, frame_sets.size(), frame_sets.data(), 0, nullptr); @@ -1867,18 +2031,27 @@ namespace ZEngine::Hardwares } } - void CommandBufferManager::Initialize(VulkanDevice* device, uint8_t swapchain_image_count, int thread_count) + 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 = swapchain_image_count * 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); @@ -1889,7 +2062,7 @@ namespace ZEngine::Hardwares CommandBuffers[i] = ZPushStructCtorArgs( Device->Arena, CommandBuffer, - device, + Device, pool->Handle, pool->QueueType, /*(i % MaxBufferPerPool) == 0 ? false : true */ false); @@ -1900,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); @@ -1908,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() @@ -1922,6 +2097,7 @@ namespace ZEngine::Hardwares CommandPools.clear(); TransferCommandPools.clear(); + EnqueuedCommandbuffers.clear(); } CommandBuffer* CommandBufferManager::GetCommandBuffer(uint8_t frame_index, bool begin) @@ -1991,6 +2167,91 @@ 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; + + 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 + { + 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); @@ -2362,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/Hardwares/VulkanDevice.h b/ZEngine/ZEngine/Hardwares/VulkanDevice.h index 5b200fea..d75d0641 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 @@ -478,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); @@ -486,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; @@ -534,110 +544,120 @@ namespace ZEngine::Hardwares */ struct VulkanDevice { - bool HasSeperateTransfertQueueFamily = 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; - VkPhysicalDeviceFeatures 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 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(); + 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 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::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/Helpers/MemoryOperations.h b/ZEngine/ZEngine/Helpers/MemoryOperations.h index 235d17f1..ed62e781 100644 --- a/ZEngine/ZEngine/Helpers/MemoryOperations.h +++ b/ZEngine/ZEngine/Helpers/MemoryOperations.h @@ -104,13 +104,13 @@ namespace ZEngine::Helpers inline int secure_strcpy(char* dest, size_t destSize, const char* src) { - if (!dest || !src) + if (!dest || !src || destSize == 0) { return MEMORY_OP_FAILURE; } - size_t srcLength = secure_strlen(src); - if (srcLength + 1 > destSize) + size_t src_len = secure_strlen(src); + if (src_len + 1 > destSize) { return MEMORY_OP_FAILURE; } diff --git a/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp b/ZEngine/ZEngine/Rendering/Renderers/GraphicRenderer.cpp index 2f23a86e..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/ImGUIRenderer.cpp b/ZEngine/ZEngine/Rendering/Renderers/ImGUIRenderer.cpp index b9cfd8c8..c49a911c 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(); @@ -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(0)[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); @@ -295,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); 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/Renderers/RenderPasses/RenderPass.cpp b/ZEngine/ZEngine/Rendering/Renderers/RenderPasses/RenderPass.cpp index 5d6a953f..211cb141 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) @@ -143,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); @@ -174,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); @@ -206,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 909aae71..488cbd20 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,37 +35,54 @@ 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); - LayoutBindingSpections.init(device->Arena, 5); - SetLayouts.init(device->Arena, 5); - DescriptorSetLayoutMap.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(); CreatePushConstantRange(); - for (auto layout : DescriptorSetLayoutMap) { - SetLayouts.push(layout.second); + std::set ordered_sets = {}; + for (auto [i, _] : InternalDescriptorSetLayoutMap) + { + ordered_sets.insert(i); + } + + for (auto set : ordered_sets) + { + SetLayouts.push(InternalDescriptorSetLayoutMap.at(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); } } - LocalArena.Clear(); } void Shader::CreateModule() { - ZRawPtr(spirv_cross::Compiler) spirv_compiler = nullptr; + Scope spirv_compiler = nullptr; /* * Vertex Shader processing @@ -86,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) { @@ -98,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) @@ -111,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) @@ -127,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 */ @@ -155,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) { @@ -167,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) @@ -179,8 +211,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::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) @@ -196,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 */ @@ -206,37 +244,51 @@ 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->ShaderReservedLayoutBindingSpecificationMap.contains(set)) { - count = type.array[0]; - if (count == 0) // Unsized arrays + 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) { - count = m_device->PhysicalDeviceDescriptorIndexingProperties.maxPerStageDescriptorUpdateAfterBindSamplers - 1; + 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); + + 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); } + 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}); } } } - 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; - 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)) { @@ -255,11 +307,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) { @@ -270,31 +322,47 @@ 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); + + Array layout_binding_collection = {}; + layout_binding_collection.init(scratch.Arena, 10); - for (const auto& layout_binding_set : LayoutBindingSpecificationMap) + for (const auto layout_binding_set : LayoutBindingSpecificationMap) { - uint32_t binding_set = layout_binding_set.first; - Array layout_binding_collection = {}; - layout_binding_collection.init(&LocalArena, 10); + 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.at(binding_set); + continue; + } + 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) { - 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] = 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; } - 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; + } } VkDescriptorSetLayoutBindingFlagsCreateInfo binding_flags_create_info = {}; @@ -308,63 +376,86 @@ 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.pNext = &binding_flags_create_info; - VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; + 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") - DescriptorSetLayoutMap[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); }); + InternalDescriptorSetLayoutMap[binding_set] = std::move(descriptor_set_layout); + } - 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++; + /* + * 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; - pool_size.descriptorCount += m_specification.OverloadPoolSize; - } + find_pool_size_it->descriptorCount += layout_binding.descriptorCount; + } + /* + * Ensure correctness with number of frame count + */ + for (auto& pool_size : pool_size_collection) + { + pool_size.descriptorCount *= m_device->SwapchainImageCount; } /* * Create DescriptorPool */ - ZENGINE_VALIDATE_ASSERT(!pool_size_collection.empty(), "The pool size can't be empty") + if (pool_size_collection.empty()) + { + ZENGINE_CORE_WARN("Shader: - The pool size is empty!") + ZReleaseScratch(scratch); + return; + } 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.maxSets = m_device->SwapchainImageCount * pool_size_collection.size() * m_specification.OverloadMaxSet; + pool_info.flags = m_device->PhysicalDeviceSupportSampledImageBindless ? VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT : 0; + pool_info.maxSets = m_device->SwapchainImageCount; pool_info.poolSizeCount = pool_size_collection.size(); pool_info.pPoolSizes = pool_size_collection.data(); ZENGINE_VALIDATE_ASSERT(vkCreateDescriptorPool(m_device->LogicalDevice, &pool_info, nullptr, &m_descriptor_pool) == VK_SUCCESS, "Failed to create DescriptorPool") + ZReleaseScratch(scratch); + /* * 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); + 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.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; @@ -376,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); } } diff --git a/ZEngine/ZEngine/Rendering/Shaders/Shader.h b/ZEngine/ZEngine/Rendering/Shaders/Shader.h index bfd78e6c..c12c3aec 100644 --- a/ZEngine/ZEngine/Rendering/Shaders/Shader.h +++ b/ZEngine/ZEngine/Rendering/Shaders/Shader.h @@ -15,21 +15,21 @@ namespace ZEngine::Rendering::Shaders void Initialize(Hardwares::VulkanDevice* device, const Specifications::ShaderSpecification& spec); 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 = {}; + Specifications::LayoutBindingSpecification GetLayoutBindingSpecification(cstring 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 LayoutBindingSpecifications = {}; + Core::Containers::Array PushConstants = {}; + Core::Containers::HashMap> DescriptorSetMap = {}; //> + Core::Containers::HashMap InternalDescriptorSetLayoutMap = {}; // + Core::Containers::HashMap> LayoutBindingSpecificationMap = {}; private: void CreateModule();