improving allocator

This commit is contained in:
2025-05-20 23:12:54 +02:00
parent 410d247c7f
commit c7dfc64f26
15 changed files with 145 additions and 35 deletions

View File

@@ -49,8 +49,8 @@ namespace Scop
VkMemoryRequirements mem_requirements;
RenderCore::Get().vkGetBufferMemoryRequirements(device, m_buffer, &mem_requirements);
m_memory = RenderCore::Get().GetAllocator().Allocate(size, mem_requirements.alignment, *FindMemoryType(mem_requirements.memoryTypeBits, properties), dedicated_alloc);
//m_memory = RenderCore::Get().GetAllocator().Allocate(mem_requirements.size, mem_requirements.alignment, *FindMemoryType(mem_requirements.memoryTypeBits, properties));
//m_memory = RenderCore::Get().GetAllocator().Allocate(size, mem_requirements.alignment, *FindMemoryType(mem_requirements.memoryTypeBits, properties), dedicated_alloc);
m_memory = RenderCore::Get().GetAllocator().Allocate(mem_requirements.size, mem_requirements.alignment, *FindMemoryType(mem_requirements.memoryTypeBits, properties), dedicated_alloc);
RenderCore::Get().vkBindBufferMemory(device, m_buffer, m_memory.memory, m_memory.offset);
#ifdef SCOP_HAS_DEBUG_UTILS_FUNCTIONS
@@ -75,6 +75,8 @@ namespace Scop
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
#endif
m_size = size;
m_is_dedicated_alloc = dedicated_alloc;
s_buffer_count++;

View File

@@ -4,7 +4,7 @@
namespace Scop
{
void Image::Init(ImageType type, std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, bool is_multisampled, std::string_view name)
void Image::Init(ImageType type, std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, bool is_multisampled, std::string_view name, bool dedicated_alloc)
{
m_type = type;
m_width = width;
@@ -47,8 +47,8 @@ namespace Scop
VkMemoryRequirements mem_requirements;
RenderCore::Get().vkGetImageMemoryRequirements(RenderCore::Get().GetDevice(), m_image, &mem_requirements);
m_memory = RenderCore::Get().GetAllocator().Allocate(mem_requirements.size, mem_requirements.alignment, *FindMemoryType(mem_requirements.memoryTypeBits, properties), true);
RenderCore::Get().vkBindImageMemory(RenderCore::Get().GetDevice(), m_image, m_memory.memory, 0);
m_memory = RenderCore::Get().GetAllocator().Allocate(mem_requirements.size, mem_requirements.alignment, *FindMemoryType(mem_requirements.memoryTypeBits, properties), dedicated_alloc);
RenderCore::Get().vkBindImageMemory(RenderCore::Get().GetDevice(), m_image, m_memory.memory, m_memory.offset);
#ifdef SCOP_HAS_DEBUG_UTILS_FUNCTIONS
VkDebugUtilsObjectNameInfoEXT name_info{};

View File

@@ -24,6 +24,7 @@ namespace Scop
if(RenderCore::Get().vkMapMemory(m_device, m_memory, 0, VK_WHOLE_SIZE, 0, &p_map) != VK_SUCCESS)
FatalError("Vulkan: failed to map a host visible chunk");
}
MemoryBlock& block = m_blocks.emplace_back();
block.memory = m_memory;
block.offset = 0;
@@ -37,7 +38,7 @@ namespace Scop
{
if(!m_blocks[i].free || m_blocks[i].size < size)
continue;
VkDeviceSize offset_displacement = (m_blocks[i].offset % alignment > 0) ? alignment - m_blocks[i].offset % alignment : 0;
VkDeviceSize offset_displacement = (m_blocks[i].offset % alignment != 0) ? alignment - m_blocks[i].offset % alignment : 0;
VkDeviceSize old_size_available = m_blocks[i].size - offset_displacement;
if(size + offset_displacement <= m_blocks[i].size)
@@ -51,7 +52,7 @@ namespace Scop
MemoryBlock new_block;
new_block.memory = m_memory;
new_block.offset = m_blocks[i].offset + size;
new_block.offset = m_blocks[i].offset + m_blocks[i].size;
new_block.size = old_size_available - size;
new_block.free = true;
@@ -76,9 +77,9 @@ namespace Scop
end = true;
for(auto it = m_blocks.begin(); it != m_blocks.end(); ++it)
{
if(it->free && (it + 1)->free)
if(it->free && it + 1 != m_blocks.end() && (it + 1)->free)
{
it->size = (it + 1)->offset + (it + 1)->size - it->offset;
it->size += (it + 1)->size;
m_blocks.erase(it + 1);
end = false;
break;

View File

@@ -1,4 +1,5 @@
#include <Renderer/Memory/DeviceAllocator.h>
#include <Renderer/RenderCore.h>
#include <Maths/Constants.h>
#include <Core/Logs.h>
@@ -6,7 +7,15 @@
namespace Scop
{
constexpr VkDeviceSize CHUNK_SIZE = MaxValue<std::uint16_t>();
#define AlignUp(val, alignment) (val + alignment - 1) & ~(alignment - 1)
void DeviceAllocator::AttachToDevice(VkDevice device, VkPhysicalDevice physical) noexcept
{
m_device = device;
m_physical = physical;
RenderCore::Get().vkGetPhysicalDeviceMemoryProperties(physical, &m_mem_props);
}
[[nodiscard]] MemoryBlock DeviceAllocator::Allocate(VkDeviceSize size, VkDeviceSize alignment, std::int32_t memory_type_index, bool dedicated_chunk)
{
@@ -25,7 +34,8 @@ namespace Scop
}
}
}
m_chunks.emplace_back(std::make_unique<MemoryChunk>(m_device, m_physical, (CHUNK_SIZE < size + alignment ? size + alignment : CHUNK_SIZE), memory_type_index, dedicated_chunk));
VkDeviceSize chunk_size = CalcPreferredChunkSize(memory_type_index);
m_chunks.emplace_back(std::make_unique<MemoryChunk>(m_device, m_physical, chunk_size, memory_type_index, dedicated_chunk));
std::optional<MemoryBlock> block = m_chunks.back()->Allocate(size, alignment);
m_allocations_count++;
if(block.has_value())
@@ -54,4 +64,12 @@ namespace Scop
}
Error("Device Allocator: unable to free a block; could not find it's chunk");
}
VkDeviceSize DeviceAllocator::CalcPreferredChunkSize(std::uint32_t mem_type_index)
{
std::uint32_t heap_index = m_mem_props.memoryTypes[mem_type_index].heapIndex;
VkDeviceSize heap_size = m_mem_props.memoryHeaps[heap_index].size;
bool is_small_heap = heap_size <= SMALL_HEAP_MAX_SIZE;
return AlignUp((is_small_heap ? (heap_size / 8) : DEFAULT_LARGE_HEAP_BLOCK_SIZE), (VkDeviceSize)32);
}
}

View File

@@ -23,7 +23,7 @@ namespace Scop
if(!m_main_render_texture.IsInit())
{
auto extent = kvfGetSwapchainImagesSize(renderer.GetSwapchain().Get());
m_main_render_texture.Init({}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_UNORM, false, "scop_main_render_texture");
m_main_render_texture.Init({}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_UNORM, false, "scop_main_render_texture", true);
}
scene.GetDepth().Clear(renderer.GetActiveCommandBuffer(), {});

View File

@@ -18,12 +18,15 @@ namespace Scop
{
p_window = window;
m_swapchain.Init(p_window);
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
for(std::size_t i = 0; i < SEMAPHORE_COUNT; i++)
{
m_image_available_semaphores[i] = kvfCreateSemaphore(RenderCore::Get().GetDevice());
Message("Vulkan: image available semaphore created");
m_render_finished_semaphores[i] = kvfCreateSemaphore(RenderCore::Get().GetDevice());
Message("Vulkan: render finished semaphore created");
}
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
{
m_cmd_buffers[i] = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
Message("Vulkan: command buffer created");
m_cmd_fences[i] = kvfCreateFence(RenderCore::Get().GetDevice());
@@ -34,7 +37,7 @@ namespace Scop
void Renderer::BeginFrame()
{
kvfWaitForFence(RenderCore::Get().GetDevice(), m_cmd_fences[m_current_frame_index]);
m_swapchain.AquireFrame(m_image_available_semaphores[m_current_frame_index]);
m_swapchain.AquireFrame(m_image_available_semaphores[m_current_semaphore_index]);
RenderCore::Get().vkResetCommandBuffer(m_cmd_buffers[m_current_frame_index], 0);
kvfBeginCommandBuffer(m_cmd_buffers[m_current_frame_index], 0);
m_drawcalls = 0;
@@ -46,20 +49,24 @@ namespace Scop
{
VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
kvfEndCommandBuffer(m_cmd_buffers[m_current_frame_index]);
kvfSubmitCommandBuffer(RenderCore::Get().GetDevice(), m_cmd_buffers[m_current_frame_index], KVF_GRAPHICS_QUEUE, m_render_finished_semaphores[m_current_frame_index], m_image_available_semaphores[m_current_frame_index], m_cmd_fences[m_current_frame_index], wait_stages);
m_swapchain.Present(m_render_finished_semaphores[m_current_frame_index]);
kvfSubmitCommandBuffer(RenderCore::Get().GetDevice(), m_cmd_buffers[m_current_frame_index], KVF_GRAPHICS_QUEUE, m_render_finished_semaphores[m_current_semaphore_index], m_image_available_semaphores[m_current_semaphore_index], m_cmd_fences[m_current_frame_index], wait_stages);
m_swapchain.Present(m_render_finished_semaphores[m_current_semaphore_index]);
m_current_frame_index = (m_current_frame_index + 1) % MAX_FRAMES_IN_FLIGHT;
m_current_semaphore_index = (m_current_semaphore_index + 1) % SEMAPHORE_COUNT;
}
void Renderer::Destroy() noexcept
{
RenderCore::Get().WaitDeviceIdle();
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
for(std::size_t i = 0; i < SEMAPHORE_COUNT; i++)
{
kvfDestroySemaphore(RenderCore::Get().GetDevice(), m_image_available_semaphores[i]);
Message("Vulkan: image available semaphore destroyed");
kvfDestroySemaphore(RenderCore::Get().GetDevice(), m_render_finished_semaphores[i]);
Message("Vulkan: render finished semaphore destroyed");
}
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
{
kvfDestroyCommandBuffer(RenderCore::Get().GetDevice(), m_cmd_buffers[i]);
Message("Vulkan: command buffer destroyed");
kvfDestroyFence(RenderCore::Get().GetDevice(), m_cmd_fences[i]);