mirror of
https://github.com/Kbz-8/42_vox.git
synced 2026-01-11 14:43:34 +00:00
fixing allocator
This commit is contained in:
@@ -20,11 +20,12 @@ namespace Scop
|
||||
|
||||
enum class Event
|
||||
{
|
||||
SceneHasChangedEventCode = 55,
|
||||
ResizeEventCode = 56,
|
||||
FrameBeginEventCode = 57,
|
||||
FatalErrorEventCode = 168,
|
||||
QuitEventCode = 168,
|
||||
SceneHasChangedEventCode,
|
||||
ResizeEventCode,
|
||||
FrameBeginEventCode,
|
||||
FatalErrorEventCode,
|
||||
QuitEventCode,
|
||||
MemoryChunkAllocationFailed,
|
||||
|
||||
EndEnum
|
||||
};
|
||||
|
||||
@@ -12,13 +12,15 @@ namespace Scop
|
||||
class MemoryChunk
|
||||
{
|
||||
public:
|
||||
MemoryChunk(VkDevice device, VkPhysicalDevice physical, VkDeviceSize size, std::int32_t memory_type_index, bool is_dedicated);
|
||||
MemoryChunk(VkDevice device, VkPhysicalDevice physical, VkDeviceSize size, std::int32_t memory_type_index, bool is_dedicated, std::uint32_t& vram_usage, std::uint32_t& vram_host_visible_usage);
|
||||
|
||||
[[nodiscard]] std::optional<MemoryBlock> Allocate(VkDeviceSize size, VkDeviceSize alignment);
|
||||
void Deallocate(const MemoryBlock& block);
|
||||
[[nodiscard]] inline bool Has(const MemoryBlock& block) const noexcept { return block.memory == m_memory; }
|
||||
[[nodiscard]] inline std::int32_t GetMemoryTypeIndex() const noexcept { return m_memory_type_index; }
|
||||
[[nodiscard]] inline bool IsDedicated() const noexcept { return m_is_dedicated; }
|
||||
[[nodiscard]] inline void* GetMap() const noexcept { return p_map; }
|
||||
[[nodiscard]] inline VkDeviceSize GetSize() const noexcept { return m_size; }
|
||||
|
||||
~MemoryChunk();
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
constexpr std::size_t SMALL_HEAP_MAX_SIZE = (1024ULL * 1024 * 1024);
|
||||
constexpr std::size_t DEFAULT_LARGE_HEAP_BLOCK_SIZE = (256ULL * 1024 * 1024);
|
||||
constexpr std::size_t SMALL_HEAP_MAX_SIZE = (1024ULL * 1024 * 1024); // 1GB
|
||||
constexpr std::size_t DEFAULT_LARGE_HEAP_BLOCK_SIZE = (256ULL * 1024 * 1024); // 256MiB
|
||||
constexpr std::uint32_t NEW_BLOCK_SIZE_SHIFT_MAX = 3;
|
||||
|
||||
class DeviceAllocator
|
||||
{
|
||||
@@ -26,6 +27,9 @@ namespace Scop
|
||||
[[nodiscard]] MemoryBlock Allocate(VkDeviceSize size, VkDeviceSize alignment, std::int32_t memory_type_index, bool dedicated_chunk = false);
|
||||
void Deallocate(const MemoryBlock& block);
|
||||
|
||||
[[nodiscard]] inline std::uint32_t GetVramUsage() const noexcept { return m_vram_usage; }
|
||||
[[nodiscard]] inline std::uint32_t GetVramHostVisibleUsage() const noexcept { return m_vram_host_visible_usage; }
|
||||
|
||||
~DeviceAllocator() = default;
|
||||
|
||||
private:
|
||||
@@ -39,6 +43,9 @@ namespace Scop
|
||||
std::size_t m_allocations_count = 0;
|
||||
std::mutex m_alloc_mutex;
|
||||
std::mutex m_dealloc_mutex;
|
||||
std::uint32_t m_vram_usage = 0;
|
||||
std::uint32_t m_vram_host_visible_usage = 0;
|
||||
bool m_last_chunk_creation_failed = false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,25 @@
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
std::string HumanSize(uint64_t bytes)
|
||||
{
|
||||
std::string_view suffix[] = { "B", "KB", "MB", "GB", "TB" };
|
||||
std::size_t length = sizeof(suffix) / sizeof(suffix[0]);
|
||||
|
||||
int i = 0;
|
||||
double dbl_bytes = bytes;
|
||||
|
||||
if(bytes > 1024)
|
||||
{
|
||||
for(i = 0; (bytes / 1024) > 0 && i < length-1; i++, bytes /= 1024)
|
||||
dbl_bytes = bytes / 1024.0;
|
||||
}
|
||||
|
||||
std::string output(256, 0);
|
||||
std::sprintf(output.data(), "%.02lf %s", dbl_bytes, suffix[i].data());
|
||||
return output;
|
||||
}
|
||||
|
||||
ImGuiRenderer::ImGuiRenderer(NonOwningPtr<Renderer> renderer) : p_renderer(renderer)
|
||||
{}
|
||||
|
||||
@@ -141,9 +160,13 @@ namespace Scop
|
||||
ImGui::Text("Swapchain images count %ld", p_renderer->GetSwapchain().GetSwapchainImages().size());
|
||||
ImGui::Text("Drawcalls %ld", p_renderer->GetDrawCallsCounterRef());
|
||||
ImGui::Text("Polygon drawn %ld", p_renderer->GetPolygonDrawnCounterRef());
|
||||
ImGui::Separator();
|
||||
ImGui::Text("VRAM usage %s", HumanSize(RenderCore::Get().GetAllocator().GetVramUsage()).c_str());
|
||||
ImGui::Text("Host visible usage %s", HumanSize(RenderCore::Get().GetAllocator().GetVramHostVisibleUsage()).c_str());
|
||||
ImGui::Text("Allocations count %ld / %u", RenderCore::Get().GetAllocator().GetAllocationsCount(), props.limits.maxMemoryAllocationCount);
|
||||
ImGui::Text("Buffer count %ld", GPUBuffer::GetBufferCount());
|
||||
ImGui::Text("Image count %ld", Image::GetImageCount());
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Window dimensions: %ux%u", p_renderer->GetWindow()->GetWidth(), p_renderer->GetWindow()->GetHeight());
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
#include <Renderer/Memory/Chunk.h>
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Core/EventBus.h>
|
||||
#include <Core/Logs.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
MemoryChunk::MemoryChunk(VkDevice device, VkPhysicalDevice physical, VkDeviceSize size, std::int32_t memory_type_index, bool is_dedicated)
|
||||
namespace Internal
|
||||
{
|
||||
struct MemoryChunkAllocFailedEvent : public EventBase
|
||||
{
|
||||
Event What() const override { return Event::MemoryChunkAllocationFailed; }
|
||||
};
|
||||
}
|
||||
|
||||
MemoryChunk::MemoryChunk(VkDevice device, VkPhysicalDevice physical, VkDeviceSize size, std::int32_t memory_type_index, bool is_dedicated, std::uint32_t& vram_usage, std::uint32_t& vram_host_visible_usage)
|
||||
: m_device(device), m_physical(physical), m_size(size), m_memory_type_index(memory_type_index), m_is_dedicated(is_dedicated)
|
||||
{
|
||||
Verify(device != VK_NULL_HANDLE, "Memory Chunk : invalid device");
|
||||
@@ -15,7 +24,10 @@ namespace Scop
|
||||
alloc_info.allocationSize = size;
|
||||
alloc_info.memoryTypeIndex = m_memory_type_index;
|
||||
if(RenderCore::Get().vkAllocateMemory(m_device, &alloc_info, nullptr, &m_memory) != VK_SUCCESS)
|
||||
FatalError("Vulkan: failed to allocate memory for a chunk");
|
||||
{
|
||||
EventBus::Send("__ScopDeviceAllocator", Internal::MemoryChunkAllocFailedEvent{});
|
||||
return;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceMemoryProperties properties;
|
||||
RenderCore::Get().vkGetPhysicalDeviceMemoryProperties(m_physical, &properties);
|
||||
@@ -23,7 +35,10 @@ 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");
|
||||
vram_host_visible_usage += size;
|
||||
}
|
||||
else
|
||||
vram_usage += size;
|
||||
|
||||
MemoryBlock& block = m_blocks.emplace_back();
|
||||
block.memory = m_memory;
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
#include <Renderer/RenderCore.h>
|
||||
#include <Maths/Constants.h>
|
||||
#include <Core/Logs.h>
|
||||
#include <Core/EventBus.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace Scop
|
||||
{
|
||||
#define AlignUp(val, alignment) (val + alignment - 1) & ~(alignment - 1)
|
||||
#define AlignUp(val, alignment) ((val + alignment - 1) & ~(alignment - 1))
|
||||
|
||||
void DeviceAllocator::AttachToDevice(VkDevice device, VkPhysicalDevice physical) noexcept
|
||||
{
|
||||
@@ -15,6 +16,13 @@ namespace Scop
|
||||
m_physical = physical;
|
||||
|
||||
RenderCore::Get().vkGetPhysicalDeviceMemoryProperties(physical, &m_mem_props);
|
||||
|
||||
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||
{
|
||||
if(event.What() == Event::MemoryChunkAllocationFailed)
|
||||
m_last_chunk_creation_failed = true;
|
||||
};
|
||||
EventBus::RegisterListener({ functor, "__ScopDeviceAllocator" });
|
||||
}
|
||||
|
||||
[[nodiscard]] MemoryBlock DeviceAllocator::Allocate(VkDeviceSize size, VkDeviceSize alignment, std::int32_t memory_type_index, bool dedicated_chunk)
|
||||
@@ -34,8 +42,33 @@ namespace Scop
|
||||
}
|
||||
}
|
||||
}
|
||||
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));
|
||||
VkDeviceSize chunk_size = dedicated_chunk ? size + alignment : CalcPreferredChunkSize(memory_type_index);
|
||||
if(chunk_size < size + alignment)
|
||||
chunk_size = size + alignment;
|
||||
m_chunks.emplace_back(std::make_unique<MemoryChunk>(m_device, m_physical, chunk_size, memory_type_index, dedicated_chunk, m_vram_usage, m_vram_host_visible_usage));
|
||||
|
||||
if(m_last_chunk_creation_failed && !dedicated_chunk)
|
||||
{
|
||||
// Allocation of this size failed? Try 1/2, 1/4, 1/8 of preferred chunk size.
|
||||
std::uint32_t new_block_size_shift = 0;
|
||||
while(m_last_chunk_creation_failed && new_block_size_shift < NEW_BLOCK_SIZE_SHIFT_MAX)
|
||||
{
|
||||
m_last_chunk_creation_failed = false;
|
||||
m_chunks.pop_back();
|
||||
chunk_size /= 2;
|
||||
if(chunk_size < size + alignment)
|
||||
{
|
||||
m_last_chunk_creation_failed = true;
|
||||
break;
|
||||
}
|
||||
m_chunks.emplace_back(std::make_unique<MemoryChunk>(m_device, m_physical, chunk_size, memory_type_index, false, m_vram_usage, m_vram_host_visible_usage));
|
||||
}
|
||||
}
|
||||
|
||||
// If we could not recover from allocation failure
|
||||
if(m_last_chunk_creation_failed)
|
||||
FatalError("Device Allocator: could not allocate a memory chunk");
|
||||
|
||||
std::optional<MemoryBlock> block = m_chunks.back()->Allocate(size, alignment);
|
||||
m_allocations_count++;
|
||||
if(block.has_value())
|
||||
@@ -56,6 +89,10 @@ namespace Scop
|
||||
(*it)->Deallocate(block);
|
||||
if((*it)->IsDedicated())
|
||||
{
|
||||
if((*it)->GetMap() != nullptr) // If it is host visible
|
||||
m_vram_host_visible_usage -= (*it)->GetSize();
|
||||
else
|
||||
m_vram_usage -= (*it)->GetSize();
|
||||
m_chunks.erase(it);
|
||||
m_allocations_count--;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user