fixing allocator

This commit is contained in:
2025-05-21 10:58:57 +02:00
parent c7dfc64f26
commit 42508722ca
8 changed files with 110 additions and 17 deletions

View File

@@ -173,8 +173,8 @@ void Chunk::UploadMesh()
std::uint32_t Chunk::GetBlock(Scop::Vec3i position) const noexcept
{
//if(position.x < 0 || position.x >= m_data.size() || position.z < 0 || position.z >= m_data[position.x >= m_data.size() ? m_data.size() - 1 : position.x].size() || position.y < 0)
// return 1;
if(position.x < 0 || position.x >= m_data.size() || position.z < 0 || position.z >= m_data[position.x >= m_data.size() ? m_data.size() - 1 : position.x].size() || position.y < 0)
return 1;
if(position.x < m_data.size() && position.z < m_data[position.x].size() && position.y < m_data[position.x][position.z].size())
return m_data[position.x][position.z][position.y];
return 0;

View File

@@ -88,6 +88,8 @@ void World::GenerateWorld()
std::this_thread::sleep_for(16ms);
continue;
}
std::queue<std::reference_wrapper<Chunk>> mesh_generation_queue;
for(std::int32_t x = m_current_chunk_position.x - RENDER_DISTANCE; x <= m_current_chunk_position.x + RENDER_DISTANCE; x++)
{
for(std::int32_t z = m_current_chunk_position.y - RENDER_DISTANCE; z <= m_current_chunk_position.y + RENDER_DISTANCE; z++)
@@ -98,12 +100,18 @@ void World::GenerateWorld()
if(!res.first->second.GetActor())
{
res.first->second.GenerateChunk();
res.first->second.GenerateMesh();
m_chunks_to_upload.Push(std::ref(res.first->second));
mesh_generation_queue.push(std::ref(res.first->second));
}
}
}
}
while(!mesh_generation_queue.empty())
{
auto chunk = mesh_generation_queue.front();
mesh_generation_queue.pop();
chunk.get().GenerateMesh();
m_chunks_to_upload.Push(chunk);
}
m_generation_status = GenerationState::Finished;
}
}

View File

@@ -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
};

View File

@@ -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();

View File

@@ -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;
};
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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--;
}