diff --git a/Application/Chunk.cpp b/Application/Chunk.cpp index 84d8bdd..8eb1533 100644 --- a/Application/Chunk.cpp +++ b/Application/Chunk.cpp @@ -2,8 +2,6 @@ #include #include -#include - #define CHUNK_POS_TO_INDEX(px, py, pz) (px * CHUNK_SIZE.x * CHUNK_SIZE.z + pz * CHUNK_SIZE.z + py) Chunk::Chunk(World& world, Scop::Vec2i offset) : m_data(CHUNK_VOLUME, 0), m_offset(offset), m_position(std::move(offset) * Scop::Vec2i{ CHUNK_SIZE.x, CHUNK_SIZE.z }), m_world(world) @@ -21,7 +19,7 @@ void Chunk::GenerateChunk() for(std::uint32_t z = 0; z < CHUNK_SIZE.z; z++) { // Implement noise here - std::uint32_t height = 4 + std::sin(x) + std::cos(z); + std::uint32_t height = std::min(static_cast(4 + (std::sin(x) + std::cos(z)) * 2), CHUNK_SIZE.y); for(std::uint32_t y = 0; y < height; y++) m_data[CHUNK_POS_TO_INDEX(x, y, z)] = 1; } @@ -125,7 +123,7 @@ void Chunk::UploadMesh() mesh->AddSubMesh({ std::move(m_mesh_data), std::move(m_mesh_index_data) }); Scop::Actor& actor = m_world.GetScene().CreateActor(mesh); - //actor.GetModelRef().SetMaterial(m_world.GetBlockMaterial(), 0); + actor.GetModelRef().SetMaterial(m_world.GetBlockMaterial(), 0); actor.SetScale(Scop::Vec3f{ 2.0f }); actor.SetPosition(Scop::Vec3f(m_position.x, 0.0f, m_position.y)); p_actor = &actor; diff --git a/Application/Chunk.h b/Application/Chunk.h index 733c2cb..0215a83 100644 --- a/Application/Chunk.h +++ b/Application/Chunk.h @@ -2,12 +2,11 @@ #define CHUNK_H #include -#include #include #include -constexpr Scop::Vec3ui CHUNK_SIZE = Scop::Vec3ui{ 32, 256, 32 }; +constexpr Scop::Vec3ui CHUNK_SIZE = Scop::Vec3ui{ 32, 32, 32 }; constexpr std::uint32_t CHUNK_VOLUME = CHUNK_SIZE.x * CHUNK_SIZE.y * CHUNK_SIZE.z; class Chunk diff --git a/Application/Utils.h b/Application/Utils.h index 5454df4..b3fcb6f 100644 --- a/Application/Utils.h +++ b/Application/Utils.h @@ -1,8 +1,11 @@ #ifndef UTILS_H #define UTILS_H +#include +#include #include #include +#include #include @@ -42,4 +45,36 @@ namespace std }; } +template +class ThreadSafeQueue +{ + public: + inline void Push(T item) + { + const std::unique_lock lock(m_mutex); + m_queue.push(item); + m_cond.notify_one(); + } + + inline T Pop() + { + std::unique_lock lock(m_mutex); + m_cond.wait(lock, [this]() { return !m_queue.empty(); }); + T item = m_queue.front(); + m_queue.pop(); + return item; + } + + bool IsEmpty() const + { + const std::unique_lock lock(m_mutex); + return m_queue.empty(); + } + + private: + std::queue m_queue; + mutable std::mutex m_mutex; + std::condition_variable m_cond; +}; + #endif diff --git a/Application/World.cpp b/Application/World.cpp index 92051c8..f578cc0 100644 --- a/Application/World.cpp +++ b/Application/World.cpp @@ -1,3 +1,5 @@ +#include + #include #include @@ -7,13 +9,32 @@ World::World(Scop::Scene& scene) : m_scene(scene), m_narrator(scene.CreateNarrat { Scop::Vec2ui32 map_size; Scop::MaterialTextures material_params; - material_params.albedo = std::make_shared(Scop::LoadBMPFile(GetResourcesPath() / "prototype.bmp", map_size), map_size.x, map_size.y); + material_params.albedo = std::make_shared(Scop::LoadBMPFile(GetResourcesPath() / "dirt.bmp", map_size), map_size.x, map_size.y); p_block_material = std::make_shared(material_params); auto narrator_update = [this](Scop::NonOwningPtr scene, Scop::Inputs& input, float delta) { - GenerateWorld(); - Upload(); + Scop::FirstPerson3D* camera = reinterpret_cast(m_scene.GetCamera().get()); + std::int32_t x_chunk = static_cast(camera->GetPosition().x) / static_cast(CHUNK_SIZE.x); + std::int32_t z_chunk = static_cast(camera->GetPosition().z) / static_cast(CHUNK_SIZE.z); + Scop::Vec2i current_chunk_position{ x_chunk, z_chunk }; + + if(m_generation_status != GenerationState::Ready || current_chunk_position != m_previous_chunk_position) + { + if(m_generation_status == GenerationState::Ready) + { + UnloadChunks(current_chunk_position); + auto _ = std::async(std::launch::async, &World::GenerateWorld, this, current_chunk_position); + m_generation_status = GenerationState::Working; + } + else if(m_generation_status == GenerationState::Finished) + { + m_generation_status = GenerationState::Ready; + m_previous_chunk_position = current_chunk_position; + } + } + if(m_generation_status != GenerationState::Working) + Upload(); }; m_narrator.AttachScript(std::make_shared(std::function{}, narrator_update, std::function{})); @@ -27,23 +48,14 @@ World::World(Scop::Scene& scene) : m_scene(scene), m_narrator(scene.CreateNarrat return &it->second; } -void World::GenerateWorld() +void World::UnloadChunks(Scop::Vec2i current_chunk_position) { - Scop::FirstPerson3D* camera = reinterpret_cast(m_scene.GetCamera().get()); - std::int32_t x_chunk = static_cast(camera->GetPosition().x) / static_cast(CHUNK_SIZE.x); - std::int32_t z_chunk = static_cast(camera->GetPosition().z) / static_cast(CHUNK_SIZE.z); - Scop::Vec2i current_chunk_position{ x_chunk, z_chunk }; - - if(current_chunk_position == m_previous_chunk_position) - return; - for(auto it = m_chunks.begin(); it != m_chunks.end();) { Scop::Vec3i pos = it->first; - float x_dist = std::abs(pos.x - current_chunk_position.x); float z_dist = std::abs(pos.z - current_chunk_position.y); - if(RENDER_DISTANCE < x_dist || RENDER_DISTANCE < z_dist) + if(RENDER_DISTANCE_HALF < x_dist || RENDER_DISTANCE_HALF < z_dist) { if(it->second.GetActor()) m_scene.RemoveActor(*it->second.GetActor()); @@ -52,25 +64,41 @@ void World::GenerateWorld() else ++it; } +} - for(std::int32_t x = x_chunk - RENDER_DISTANCE; x <= x_chunk + RENDER_DISTANCE; x++) +void World::GenerateWorld(Scop::Vec2i current_chunk_position) +{ + m_generation_status = GenerationState::Working; + std::vector> futures; + for(std::int32_t x = current_chunk_position.x - RENDER_DISTANCE_HALF; x <= current_chunk_position.x + RENDER_DISTANCE_HALF; x++) { - for(std::int32_t z = z_chunk - RENDER_DISTANCE; z <= z_chunk + RENDER_DISTANCE; z++) + for(std::int32_t z = current_chunk_position.y - RENDER_DISTANCE_HALF; z <= current_chunk_position.y + RENDER_DISTANCE_HALF; z++) { auto res = m_chunks.try_emplace(Scop::Vec2i{ x, z }, *this, Scop::Vec2i{ x, z }); if(res.second) - res.first->second.GenerateChunk(); + { + futures.push_back(std::async(std::launch::async, &Chunk::GenerateChunk, &res.first->second)); + if(!res.first->second.GetActor()) + m_chunks_to_upload.Push(res.first->second); + } } } - - for(auto& chunk : m_chunks) - chunk.second.GenerateMesh(); - - m_previous_chunk_position = current_chunk_position; + for(auto& future: futures) + future.wait(); + m_generation_status = GenerationState::Finished; } void World::Upload() { - for(auto& chunk : m_chunks) - chunk.second.UploadMesh(); + if(m_chunks_to_upload.IsEmpty()) + return; + Scop::RenderCore::Get().ShouldStackSubmits(true); + for(std::size_t i = 0; i < CHUNKS_UPLOAD_PER_FRAME && !m_chunks_to_upload.IsEmpty(); i++) + { + auto chunk = m_chunks_to_upload.Pop().get(); + chunk.GenerateMesh(); + chunk.UploadMesh(); + } + Scop::RenderCore::Get().WaitQueueIdle(KVF_GRAPHICS_QUEUE); + Scop::RenderCore::Get().ShouldStackSubmits(false); } diff --git a/Application/World.h b/Application/World.h index 635d937..243d74f 100644 --- a/Application/World.h +++ b/Application/World.h @@ -1,6 +1,7 @@ #ifndef WORLD_H #define WORLD_H +#include #include #include @@ -8,7 +9,16 @@ #include #include -constexpr std::uint8_t RENDER_DISTANCE = 1; +constexpr std::uint8_t RENDER_DISTANCE = 10; +constexpr std::uint8_t RENDER_DISTANCE_HALF = RENDER_DISTANCE / 2; +constexpr std::uint8_t CHUNKS_UPLOAD_PER_FRAME = 1; + +enum class GenerationState: std::uint8_t +{ + Ready, + Working, + Finished, +}; class World { @@ -22,15 +32,18 @@ class World ~World() = default; private: - void GenerateWorld(); + void UnloadChunks(Scop::Vec2i current_chunk_position); + void GenerateWorld(Scop::Vec2i current_chunk_position); void Upload(); private: std::unordered_map m_chunks; + ThreadSafeQueue> m_chunks_to_upload; std::shared_ptr p_block_material; Scop::Narrator& m_narrator; Scop::Scene& m_scene; Scop::Vec2i m_previous_chunk_position; + std::atomic m_generation_status = GenerationState::Ready; }; #endif diff --git a/Resources/dirt.bmp b/Resources/dirt.bmp new file mode 100644 index 0000000..016f7a0 Binary files /dev/null and b/Resources/dirt.bmp differ diff --git a/ScopEngine/Makefile b/ScopEngine/Makefile index dfc6451..de7d870 100644 --- a/ScopEngine/Makefile +++ b/ScopEngine/Makefile @@ -45,7 +45,7 @@ _GRAY := $(shell $(TPUT) setaf 8) _PURPLE := $(shell $(TPUT) setaf 5) ifeq ($(DEBUG), true) - CXXFLAGS += -g -D DEBUG -D IMGUI_IMPL_VULKAN_NO_PROTOTYPES -I ThirdParty/imgui + CXXFLAGS += -g3 -D DEBUG -D IMGUI_IMPL_VULKAN_NO_PROTOTYPES -I ThirdParty/imgui SRCS += $(wildcard $(addsuffix /*.cpp, ./Runtime/Sources/Debug)) SRCS += $(wildcard $(addsuffix /*.cpp, ./ThirdParty/imgui)) SRCS += $(wildcard $(addsuffix /*.cpp, ./ThirdParty/imgui/backends)) diff --git a/ScopEngine/Runtime/Includes/Graphics/Mesh.h b/ScopEngine/Runtime/Includes/Graphics/Mesh.h index aa97580..556bedc 100644 --- a/ScopEngine/Runtime/Includes/Graphics/Mesh.h +++ b/ScopEngine/Runtime/Includes/Graphics/Mesh.h @@ -27,7 +27,7 @@ namespace Scop std::memcpy(data.GetData() + vertices.size() * sizeof(Vertex), indices.data(), indices.size() * sizeof(std::uint32_t)); buffer.Init(vertices.size() * sizeof(Vertex), indices.size() * sizeof(std::uint32_t), 0, std::move(data)); this->index_size = index_size == 0 ? indices.size() : index_size; - triangle_count = index_size / 3; + triangle_count = this->index_size / 3; } inline void SetData(const std::vector& vertices, const std::vector& indices, std::size_t index_size = 0) @@ -41,7 +41,7 @@ namespace Scop buffer.SetVertexData(std::move(index_data)); this->index_size = index_size == 0 ? indices.size() : index_size; - triangle_count = index_size / 3; + triangle_count = this->index_size / 3; } }; diff --git a/ScopEngine/Runtime/Includes/Graphics/Model.h b/ScopEngine/Runtime/Includes/Graphics/Model.h index d5986c9..dec05e0 100644 --- a/ScopEngine/Runtime/Includes/Graphics/Model.h +++ b/ScopEngine/Runtime/Includes/Graphics/Model.h @@ -34,6 +34,8 @@ namespace Scop ~Model() = default; private: + inline static std::shared_ptr s_default_material = nullptr; + Vec3f m_center = { 0.0f, 0.0f, 0.0f }; std::vector> m_materials; std::shared_ptr p_mesh; diff --git a/ScopEngine/Runtime/Includes/Renderer/Buffer.h b/ScopEngine/Runtime/Includes/Renderer/Buffer.h index b8064dd..0f6130c 100644 --- a/ScopEngine/Runtime/Includes/Renderer/Buffer.h +++ b/ScopEngine/Runtime/Includes/Renderer/Buffer.h @@ -15,7 +15,7 @@ namespace Scop public: GPUBuffer() = default; - void Init(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, CPUBuffer data, std::string_view name = {}); + void Init(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, CPUBuffer data, std::string_view name = {}, bool dedicated_alloc = false); void Destroy() noexcept; bool CopyFrom(const GPUBuffer& buffer, std::size_t src_offset = 0, std::size_t dst_offset = 0) noexcept; @@ -43,7 +43,7 @@ namespace Scop MemoryBlock m_memory = NULL_MEMORY_BLOCK; private: - void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, std::string_view name); + void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, std::string_view name, bool dedicated_alloc); private: inline static std::size_t s_buffer_count = 0; @@ -52,6 +52,7 @@ namespace Scop VkBufferUsageFlags m_usage = 0; VkMemoryPropertyFlags m_flags = 0; + bool m_is_dedicated_alloc = false; }; class VertexBuffer : public GPUBuffer @@ -77,7 +78,7 @@ namespace Scop { m_vertex_offset = 0; m_index_offset = vertex_size; - GPUBuffer::Init(BufferType::LowDynamic, vertex_size + index_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | additional_flags, std::move(data), std::move(name)); + GPUBuffer::Init(BufferType::LowDynamic, vertex_size + index_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | additional_flags, std::move(data), std::move(name), true); } void SetVertexData(CPUBuffer data); void SetIndexData(CPUBuffer data); diff --git a/ScopEngine/Runtime/Includes/Renderer/Memory/Chunk.h b/ScopEngine/Runtime/Includes/Renderer/Memory/Chunk.h index 4baa19d..aa49380 100644 --- a/ScopEngine/Runtime/Includes/Renderer/Memory/Chunk.h +++ b/ScopEngine/Runtime/Includes/Renderer/Memory/Chunk.h @@ -12,12 +12,13 @@ namespace Scop class MemoryChunk { public: - MemoryChunk(VkDevice device, VkPhysicalDevice physical, VkDeviceSize size, std::int32_t memory_type_index); + MemoryChunk(VkDevice device, VkPhysicalDevice physical, VkDeviceSize size, std::int32_t memory_type_index, bool is_dedicated); [[nodiscard]] std::optional 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; } ~MemoryChunk(); @@ -29,6 +30,7 @@ namespace Scop void* p_map = nullptr; VkDeviceSize m_size = 0; std::int32_t m_memory_type_index; + bool m_is_dedicated; }; } diff --git a/ScopEngine/Runtime/Includes/Renderer/Memory/DeviceAllocator.h b/ScopEngine/Runtime/Includes/Renderer/Memory/DeviceAllocator.h index 8d053f9..f07d3dd 100644 --- a/ScopEngine/Runtime/Includes/Renderer/Memory/DeviceAllocator.h +++ b/ScopEngine/Runtime/Includes/Renderer/Memory/DeviceAllocator.h @@ -1,6 +1,7 @@ #ifndef __SCOP_VULKAN_MEMORY_DEVICE_ALLOCATOR__ #define __SCOP_VULKAN_MEMORY_DEVICE_ALLOCATOR__ +#include #include #include #include @@ -29,6 +30,8 @@ namespace Scop VkDevice m_device = VK_NULL_HANDLE; VkPhysicalDevice m_physical = VK_NULL_HANDLE; std::size_t m_allocations_count = 0; + std::mutex m_alloc_mutex; + std::mutex m_dealloc_mutex; }; } diff --git a/ScopEngine/Runtime/Includes/Renderer/RenderCore.h b/ScopEngine/Runtime/Includes/Renderer/RenderCore.h index c3eceb5..1f0aaa2 100644 --- a/ScopEngine/Runtime/Includes/Renderer/RenderCore.h +++ b/ScopEngine/Runtime/Includes/Renderer/RenderCore.h @@ -6,9 +6,6 @@ #include #include -#ifdef DEBUG - #define KVF_ENABLE_VALIDATION_LAYERS -#endif #include #include @@ -36,17 +33,21 @@ namespace Scop [[nodiscard]] inline VkInstance& GetInstanceRef() noexcept { return m_instance; } [[nodiscard]] inline VkDevice GetDevice() const noexcept { return m_device; } [[nodiscard]] inline VkPhysicalDevice GetPhysicalDevice() const noexcept { return m_physical_device; } - [[nodiscard]] inline DeviceAllocator& GetAllocator() noexcept { return m_allocator; } + [[nodiscard]] inline DeviceAllocator& GetAllocator() noexcept { return m_allocator; } + [[nodiscard]] inline bool StackSubmits() const noexcept { return m_stack_submits; } [[nodiscard]] inline std::shared_ptr GetDefaultVertexShader() const { return m_internal_shaders[DEFAULT_VERTEX_SHADER_ID]; } [[nodiscard]] inline std::shared_ptr GetBasicFragmentShader() const { return m_internal_shaders[BASIC_FRAGMENT_SHADER_ID]; } [[nodiscard]] inline std::shared_ptr GetDefaultFragmentShader() const { return m_internal_shaders[DEFAULT_FRAGMENT_SHADER_ID]; } inline void WaitDeviceIdle() const noexcept { vkDeviceWaitIdle(m_device); } + inline void WaitQueueIdle(KvfQueueType queue) const noexcept { vkQueueWaitIdle(kvfGetDeviceQueue(m_device, queue)); } inline static bool IsInit() noexcept { return s_instance != nullptr; } inline static RenderCore& Get() noexcept { return *s_instance; } + inline void ShouldStackSubmits(bool should) noexcept { m_stack_submits = should; } + #define SCOP_VULKAN_GLOBAL_FUNCTION(fn) PFN_##fn fn = nullptr; #define SCOP_VULKAN_INSTANCE_FUNCTION(fn) PFN_##fn fn = nullptr; #define SCOP_VULKAN_DEVICE_FUNCTION(fn) PFN_##fn fn = nullptr; @@ -70,6 +71,7 @@ namespace Scop VkInstance m_instance = VK_NULL_HANDLE; VkDevice m_device = VK_NULL_HANDLE; VkPhysicalDevice m_physical_device = VK_NULL_HANDLE; + bool m_stack_submits = false; }; } diff --git a/ScopEngine/Runtime/Sources/Debug/ImGuiRenderer.cpp b/ScopEngine/Runtime/Sources/Debug/ImGuiRenderer.cpp index 611cf0a..cde5fe5 100644 --- a/ScopEngine/Runtime/Sources/Debug/ImGuiRenderer.cpp +++ b/ScopEngine/Runtime/Sources/Debug/ImGuiRenderer.cpp @@ -141,7 +141,7 @@ 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::Text("Allocations count %ld", RenderCore::Get().GetAllocator().GetAllocationsCount()); + 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::Text("Window dimensions: %ux%u", p_renderer->GetWindow()->GetWidth(), p_renderer->GetWindow()->GetHeight()); diff --git a/ScopEngine/Runtime/Sources/Graphics/Model.cpp b/ScopEngine/Runtime/Sources/Graphics/Model.cpp index 7d4a396..88199d3 100644 --- a/ScopEngine/Runtime/Sources/Graphics/Model.cpp +++ b/ScopEngine/Runtime/Sources/Graphics/Model.cpp @@ -12,13 +12,17 @@ namespace Scop if(p_mesh) m_materials.resize(p_mesh->GetSubMeshCount() + 1); - CPUBuffer default_pixels{ kvfFormatSize(VK_FORMAT_R8G8B8A8_SRGB) }; - default_pixels.GetDataAs()[0] = 0xFFFFFFFF; - std::shared_ptr default_texture = std::make_shared(std::move(default_pixels), 1, 1, VK_FORMAT_R8G8B8A8_SRGB); + if(!s_default_material) + { + CPUBuffer default_pixels{ kvfFormatSize(VK_FORMAT_R8G8B8A8_SRGB) }; + default_pixels.GetDataAs()[0] = 0xFFFFFFFF; + std::shared_ptr default_texture = std::make_shared(std::move(default_pixels), 1, 1, VK_FORMAT_R8G8B8A8_SRGB); - MaterialTextures textures; - textures.albedo = default_texture; - m_materials.back() = std::make_shared(textures); + MaterialTextures textures; + textures.albedo = default_texture; + s_default_material = std::make_shared(textures); + } + m_materials.back() = s_default_material; } void Model::Draw(VkCommandBuffer cmd, const DescriptorSet& matrices_set, const GraphicPipeline& pipeline, DescriptorSet& set, std::size_t& drawcalls, std::size_t& polygondrawn, std::size_t frame_index) const diff --git a/ScopEngine/Runtime/Sources/Renderer/Buffer.cpp b/ScopEngine/Runtime/Sources/Renderer/Buffer.cpp index 0b55971..d6b9897 100644 --- a/ScopEngine/Runtime/Sources/Renderer/Buffer.cpp +++ b/ScopEngine/Runtime/Sources/Renderer/Buffer.cpp @@ -4,7 +4,7 @@ namespace Scop { - void GPUBuffer::Init(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, CPUBuffer data, std::string_view name) + void GPUBuffer::Init(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, CPUBuffer data, std::string_view name, bool dedicated_alloc) { if(type == BufferType::Constant) { @@ -30,7 +30,7 @@ namespace Scop if(type == BufferType::Staging && data.Empty()) Warning("Vulkan: trying to create staging buffer without data (wtf?)"); - CreateBuffer(size, m_usage, m_flags, std::move(name)); + CreateBuffer(size, m_usage, m_flags, std::move(name), dedicated_alloc); if(!data.Empty()) { @@ -41,7 +41,7 @@ namespace Scop PushToGPU(); } - void GPUBuffer::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, std::string_view name) + void GPUBuffer::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, std::string_view name, bool dedicated_alloc) { auto device = RenderCore::Get().GetDevice(); m_buffer = kvfCreateBuffer(device, usage, size); @@ -49,7 +49,7 @@ 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)); + 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)); RenderCore::Get().vkBindBufferMemory(device, m_buffer, m_memory.memory, m_memory.offset); @@ -73,12 +73,10 @@ namespace Scop name_info.objectHandle = reinterpret_cast(m_buffer); name_info.pObjectName = m_name.c_str(); RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info); - - Message("Vulkan: % buffer created", m_name); - #else - Message("Vulkan: buffer created"); #endif + m_is_dedicated_alloc = dedicated_alloc; + s_buffer_count++; } @@ -99,10 +97,16 @@ namespace Scop kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); kvfCopyBufferToBuffer(cmd, m_buffer, buffer.Get(), buffer.GetSize(), src_offset, dst_offset); kvfEndCommandBuffer(cmd); - VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice()); - kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence); - kvfWaitForFence(RenderCore::Get().GetDevice(), fence); - kvfDestroyFence(RenderCore::Get().GetDevice(), fence); + if(!RenderCore::Get().StackSubmits()) + { + VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice()); + kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence); + kvfWaitForFence(RenderCore::Get().GetDevice(), fence); + kvfDestroyFence(RenderCore::Get().GetDevice(), fence); + kvfDestroyCommandBuffer(RenderCore::Get().GetDevice(), cmd); + } + else + kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, VK_NULL_HANDLE); return true; } @@ -111,12 +115,11 @@ namespace Scop GPUBuffer new_buffer; new_buffer.m_usage = (this->m_usage & 0xFFFFFFFC) | VK_BUFFER_USAGE_TRANSFER_DST_BIT; new_buffer.m_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - new_buffer.CreateBuffer(m_memory.size, new_buffer.m_usage, new_buffer.m_flags, m_name); + new_buffer.CreateBuffer(m_memory.size, new_buffer.m_usage, new_buffer.m_flags, m_name, m_is_dedicated_alloc); if(new_buffer.CopyFrom(*this)) Swap(new_buffer); new_buffer.Destroy(); - Message("Vulkan: pushed buffer to GPU memory"); } void GPUBuffer::Destroy() noexcept @@ -128,7 +131,6 @@ namespace Scop RenderCore::Get().GetAllocator().Deallocate(m_memory); m_buffer = VK_NULL_HANDLE; m_memory = NULL_MEMORY_BLOCK; - Message("Vulkan: destroyed buffer"); s_buffer_count--; } diff --git a/ScopEngine/Runtime/Sources/Renderer/Image.cpp b/ScopEngine/Runtime/Sources/Renderer/Image.cpp index f66f27f..95627e8 100644 --- a/ScopEngine/Runtime/Sources/Renderer/Image.cpp +++ b/ScopEngine/Runtime/Sources/Renderer/Image.cpp @@ -57,9 +57,6 @@ namespace Scop name_info.objectHandle = reinterpret_cast(m_image); name_info.pObjectName = name.data(); RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info); - Message("Vulkan: % image created", name); - #else - Message("Vulkan: image created"); #endif s_image_count++; @@ -151,7 +148,6 @@ namespace Scop m_memory = NULL_MEMORY_BLOCK; kvfDestroyImage(RenderCore::Get().GetDevice(), m_image); } - Message("Vulkan: image destroyed"); m_image = VK_NULL_HANDLE; m_memory = NULL_MEMORY_BLOCK; m_image = VK_NULL_HANDLE; diff --git a/ScopEngine/Runtime/Sources/Renderer/Memory/Chunk.cpp b/ScopEngine/Runtime/Sources/Renderer/Memory/Chunk.cpp index bd46dec..9d6ac7e 100644 --- a/ScopEngine/Runtime/Sources/Renderer/Memory/Chunk.cpp +++ b/ScopEngine/Runtime/Sources/Renderer/Memory/Chunk.cpp @@ -6,8 +6,8 @@ namespace Scop { - MemoryChunk::MemoryChunk(VkDevice device, VkPhysicalDevice physical, VkDeviceSize size, std::int32_t memory_type_index) - : m_device(device), m_physical(physical), m_size(size), m_memory_type_index(memory_type_index) + MemoryChunk::MemoryChunk(VkDevice device, VkPhysicalDevice physical, VkDeviceSize size, std::int32_t memory_type_index, bool is_dedicated) + : 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"); VkMemoryAllocateInfo alloc_info{}; diff --git a/ScopEngine/Runtime/Sources/Renderer/Memory/DeviceAllocator.cpp b/ScopEngine/Runtime/Sources/Renderer/Memory/DeviceAllocator.cpp index 0e2d6f4..77fde98 100644 --- a/ScopEngine/Runtime/Sources/Renderer/Memory/DeviceAllocator.cpp +++ b/ScopEngine/Runtime/Sources/Renderer/Memory/DeviceAllocator.cpp @@ -12,6 +12,7 @@ namespace Scop { Verify(m_device != VK_NULL_HANDLE, "invalid device"); Verify(m_physical != VK_NULL_HANDLE, "invalid physical device"); + const std::lock_guard guard(m_alloc_mutex); if(!dedicated_chunk) { for(auto& chunk : m_chunks) @@ -24,7 +25,7 @@ namespace Scop } } } - m_chunks.emplace_back(std::make_unique(m_device, m_physical, (CHUNK_SIZE < size + alignment ? size + alignment : CHUNK_SIZE), memory_type_index)); + m_chunks.emplace_back(std::make_unique(m_device, m_physical, (CHUNK_SIZE < size + alignment ? size + alignment : CHUNK_SIZE), memory_type_index, dedicated_chunk)); std::optional block = m_chunks.back()->Allocate(size, alignment); m_allocations_count++; if(block.has_value()) @@ -37,11 +38,17 @@ namespace Scop { Verify(m_device != VK_NULL_HANDLE, "invalid device"); Verify(m_physical != VK_NULL_HANDLE, "invalid physical device"); - for(auto& chunk : m_chunks) + const std::lock_guard guard(m_dealloc_mutex); + for(auto it = m_chunks.begin(); it != m_chunks.end(); ++it) { - if(chunk->Has(block)) + if((*it)->Has(block)) { - chunk->Deallocate(block); + (*it)->Deallocate(block); + if((*it)->IsDedicated()) + { + m_chunks.erase(it); + m_allocations_count--; + } return; } }