From 9e0c6c52200673412e24092c65d00cca2f24c80f Mon Sep 17 00:00:00 2001 From: DrSocalkwe3n Date: Sat, 26 Jul 2025 01:55:11 +0600 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=B8=D0=BD=D1=85=D1=80=D0=BE=D0=BD?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B3=D1=80=D0=B0=D1=84?= =?UTF-8?q?=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=BE=D0=B9=20=D0=BE=D1=87=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B4=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/Client/Vulkan/VertexPool.hpp | 22 +- Src/Client/Vulkan/Vulkan.cpp | 135 +++++++-- Src/Client/Vulkan/Vulkan.hpp | 9 +- Src/Client/Vulkan/VulkanRenderSession.cpp | 320 ++++++++++++---------- Src/Client/Vulkan/VulkanRenderSession.hpp | 32 ++- 5 files changed, 337 insertions(+), 181 deletions(-) diff --git a/Src/Client/Vulkan/VertexPool.hpp b/Src/Client/Vulkan/VertexPool.hpp index 120e6e9..a54aee2 100644 --- a/Src/Client/Vulkan/VertexPool.hpp +++ b/Src/Client/Vulkan/VertexPool.hpp @@ -24,6 +24,7 @@ class VertexPool { // Память, доступная для обмена с устройством Buffer HostCoherent; Vertex *HCPtr = nullptr; + VkFence Fence = nullptr; size_t WritePos = 0; struct Pool { @@ -83,11 +84,23 @@ public: { Pools.reserve(16); HCPtr = (Vertex*) HostCoherent.mapMemory(); + + const VkFenceCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0 + }; + + vkAssert(!vkCreateFence(inst->Graphics.Device, &info, nullptr, &Fence)); } ~VertexPool() { if(HCPtr) HostCoherent.unMapMemory(); + + if(Fence) { + vkDestroyFence(Inst->Graphics.Device, Fence, nullptr); + } } @@ -295,9 +308,12 @@ public: 0, nullptr }; - - vkQueueSubmit(Inst->Graphics.DeviceQueueGraphic, 1, &submitInfo, VK_NULL_HANDLE); - vkQueueWaitIdle(Inst->Graphics.DeviceQueueGraphic); + { + auto lockQueue = Inst->Graphics.DeviceQueueGraphic.lock(); + vkAssert(!vkQueueSubmit(*lockQueue, 1, &submitInfo, Fence)); + } + vkAssert(!vkWaitForFences(Inst->Graphics.Device, 1, &Fence, VK_TRUE, UINT64_MAX)); + vkAssert(!vkResetFences(Inst->Graphics.Device, 1, &Fence)); vkFreeCommandBuffers(Inst->Graphics.Device, commandPool, 1, &commandBuffer); std::queue postponed = std::move(TasksPostponed); diff --git a/Src/Client/Vulkan/Vulkan.cpp b/Src/Client/Vulkan/Vulkan.cpp index 081758d..012e19e 100644 --- a/Src/Client/Vulkan/Vulkan.cpp +++ b/Src/Client/Vulkan/Vulkan.cpp @@ -33,6 +33,21 @@ extern void LoadSymbolsVulkan(TOS::DynamicLibrary &library); namespace LV::Client::VK { +static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData) +{ + std::cerr << "Validation Layer: " << pCallbackData->pMessage << std::endl; + + if("Copying old device 0 into new device 0" == std::string(pCallbackData->pMessage)) { + return VK_FALSE; + } + + return VK_FALSE; +} + struct ServerObj { Server::GameServer GS; Net::SocketServer LS; @@ -99,6 +114,11 @@ Vulkan::Vulkan(asio::io_context &ioc) glfwSetWindowAttrib(Graphics.Window, GLFW_VISIBLE, false); } catch(...) {} + try { + if(Game.RSession) + Game.RSession->pushStage(EnumRenderStage::Shutdown); + } catch(...) {} + try { Game.RSession = nullptr; } catch(const std::exception &exc) { LOG.error() << "Game.RSession = nullptr: " << exc.what(); } @@ -460,7 +480,11 @@ void Vulkan::run() Game.RSession->pushStage(EnumRenderStage::Render); #ifdef HAS_IMGUI - ImGui_ImplVulkan_NewFrame(); + { + auto lockQueue = Graphics.DeviceQueueGraphic.lock(); + ImGui_ImplVulkan_NewFrame(); + lockQueue.unlock(); + } ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); @@ -514,7 +538,10 @@ void Vulkan::run() }; //Рисуем, когда получим картинку - vkAssert(!vkQueueSubmit(Graphics.DeviceQueueGraphic, 1, &submit_info, nullFence)); + { + auto lockQueue = Graphics.DeviceQueueGraphic.lock(); + vkAssert(!vkQueueSubmit(*lockQueue, 1, &submit_info, nullFence)); + } } { @@ -530,7 +557,11 @@ void Vulkan::run() }; // Завершаем картинку - err = vkQueuePresentKHR(Graphics.DeviceQueueGraphic, &present); + { + auto lockQueue = Graphics.DeviceQueueGraphic.lock(); + err = vkQueuePresentKHR(*lockQueue, &present); + } + if (err == VK_ERROR_OUT_OF_DATE_KHR) { freeSwapchains(); @@ -550,9 +581,13 @@ void Vulkan::run() Game.Session->atFreeDrawTime(gTime, dTime); } - vkAssert(!vkQueueWaitIdle(Graphics.DeviceQueueGraphic)); + // vkAssert(!vkQueueWaitIdle(Graphics.DeviceQueueGraphic)); - vkDeviceWaitIdle(Graphics.Device); + { + auto lockQueue = Graphics.DeviceQueueGraphic.lock(); + vkDeviceWaitIdle(Graphics.Device); + lockQueue.unlock(); + } Screen.State = DrawState::End; } @@ -1477,6 +1512,7 @@ void Vulkan::initNextSettings() freeSwapchains(); } + bool hasVK_EXT_debug_utils = false; if(!Graphics.Instance) { std::vector knownDebugLayers = @@ -1506,7 +1542,38 @@ void Vulkan::initNextSettings() break; } - Graphics.Instance.emplace(this, enableDebugLayers); + std::vector enableExtension; + if(SettingsNext.Debug) + for(const vkInstanceExtension &ext : Graphics.InstanceExtensions) { + if(ext.ExtensionName == "VK_EXT_debug_utils") { + enableExtension.push_back(ext); + hasVK_EXT_debug_utils = true; + break; + } + } + + Graphics.Instance.emplace(this, enableDebugLayers, enableExtension); + } + + if(hasVK_EXT_debug_utils) { + VkDebugUtilsMessengerCreateInfoEXT createInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = 0, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + .pfnUserCallback = &debugCallback, + .pUserData = nullptr + }; + + VkDebugUtilsMessengerEXT debugMessenger; + PFN_vkCreateDebugUtilsMessengerEXT myvkCreateDebugUtilsMessengerEXT = reinterpret_cast(vkGetInstanceProcAddr(Graphics.Instance->getInstance(), "vkCreateDebugUtilsMessengerEXT")); + myvkCreateDebugUtilsMessengerEXT(Graphics.Instance->getInstance(), &createInfo, nullptr, &debugMessenger); + LOG.debug() << "Добавлен обработчик логов"; } if(!Graphics.Surface) @@ -1594,7 +1661,8 @@ void Vulkan::initNextSettings() }; vkAssert(!vkCreateDevice(Graphics.PhysicalDevice, &infoDevice, nullptr, &Graphics.Device)); - vkGetDeviceQueue(Graphics.Device, SettingsNext.QueueGraphics, 0, &Graphics.DeviceQueueGraphic); + auto lockQueue = Graphics.DeviceQueueGraphic.lock(); + vkGetDeviceQueue(Graphics.Device, SettingsNext.QueueGraphics, 0, &*lockQueue); } // Определяемся с форматом экранного буфера @@ -1821,13 +1889,14 @@ void Vulkan::initNextSettings() ImGui_ImplGlfw_InitForVulkan(Graphics.Window, true); + auto lockQueue = Graphics.DeviceQueueGraphic.lock(); ImGui_ImplVulkan_InitInfo ImGuiInfo = { .Instance = Graphics.Instance->getInstance(), .PhysicalDevice = Graphics.PhysicalDevice, .Device = Graphics.Device, .QueueFamily = SettingsNext.QueueGraphics, - .Queue = Graphics.DeviceQueueGraphic, + .Queue = *lockQueue, .DescriptorPool = Graphics.ImGuiDescPool, .RenderPass = Graphics.RenderPass, .MinImageCount = Graphics.DrawBufferCount, @@ -1843,6 +1912,7 @@ void Vulkan::initNextSettings() }; ImGui_ImplVulkan_Init(&ImGuiInfo); + lockQueue.unlock(); // ImFontConfig fontConfig; // fontConfig.MergeMode = false; @@ -1946,7 +2016,7 @@ void Vulkan::deInitVulkan() Graphics.RenderPass = nullptr; Graphics.Device = nullptr; Graphics.PhysicalDevice = nullptr; - Graphics.DeviceQueueGraphic = nullptr; + *Graphics.DeviceQueueGraphic.lock() = nullptr; Graphics.Surface = nullptr; Graphics.Instance.reset(); } @@ -1970,8 +2040,10 @@ void Vulkan::flushCommandBufferData() .pSignalSemaphores = nullptr }; - vkAssert(!vkQueueSubmit(Graphics.DeviceQueueGraphic, 1, &submit_info, nullFence)); - vkAssert(!vkQueueWaitIdle(Graphics.DeviceQueueGraphic)); + auto lockQueue = Graphics.DeviceQueueGraphic.lock(); + vkAssert(!vkQueueSubmit(*lockQueue, 1, &submit_info, nullFence)); + vkAssert(!vkQueueWaitIdle(*lockQueue)); + lockQueue.unlock(); VkCommandBufferBeginInfo infoCmdBuffer = { @@ -2763,13 +2835,22 @@ CommandBuffer::CommandBuffer(Vulkan *instance) }; vkAssert(!vkBeginCommandBuffer(Buffer, &infoCmdBuffer)); + + const VkFenceCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0 + }; + + vkAssert(!vkCreateFence(instance->Graphics.Device, &info, nullptr, &Fence)); } CommandBuffer::~CommandBuffer() { if(Buffer && Instance && Instance->Graphics.Device) { - if(Instance->Graphics.DeviceQueueGraphic) + auto lockQueue = Instance->Graphics.DeviceQueueGraphic.lock(); + if(*lockQueue) { //vkAssert(!vkEndCommandBuffer(Buffer)); vkEndCommandBuffer(Buffer); @@ -2789,25 +2870,33 @@ CommandBuffer::~CommandBuffer() }; //vkAssert(!vkQueueSubmit(Instance->Graphics.DeviceQueueGraphic, 1, &submit_info, nullFence)); - vkQueueSubmit(Instance->Graphics.DeviceQueueGraphic, 1, &submit_info, nullFence); + vkQueueSubmit(*lockQueue, 1, &submit_info, Fence); + lockQueue.unlock(); //vkAssert(!vkQueueWaitIdle(Instance->Graphics.DeviceQueueGraphic)); - vkQueueWaitIdle(Instance->Graphics.DeviceQueueGraphic); - + //vkQueueWaitIdle(Instance->Graphics.DeviceQueueGraphic); + vkWaitForFences(Instance->Graphics.Device, 1, &Fence, VK_TRUE, UINT64_MAX); + vkResetFences(Instance->Graphics.Device, 1, &Fence); + auto toExecute = std::move(AfterExecute); for(auto &iter : toExecute) try { iter(); } catch(const std::exception &exc) { Logger("CommandBuffer").error() << exc.what(); } - } + } else + lockQueue.unlock(); vkFreeCommandBuffers(Instance->Graphics.Device, OffthreadPool ? OffthreadPool : Instance->Graphics.Pool, 1, &Buffer); if(OffthreadPool) vkDestroyCommandPool(Instance->Graphics.Device, OffthreadPool, nullptr); + + if(Fence) + vkDestroyFence(Instance->Graphics.Device, Fence, nullptr); } } void CommandBuffer::execute() { - vkAssert(Instance->Graphics.DeviceQueueGraphic); + auto lockQueue = Instance->Graphics.DeviceQueueGraphic.lock(); + vkAssert(*lockQueue); vkAssert(!vkEndCommandBuffer(Buffer)); const VkCommandBuffer cmd_bufs[] = { Buffer }; @@ -2825,8 +2914,16 @@ void CommandBuffer::execute() .pSignalSemaphores = nullptr }; - vkAssert(!vkQueueSubmit(Instance->Graphics.DeviceQueueGraphic, 1, &submit_info, nullFence)); - vkAssert(!vkQueueWaitIdle(Instance->Graphics.DeviceQueueGraphic)); + // vkAssert(!vkQueueSubmit(Instance->Graphics.DeviceQueueGraphic, 1, &submit_info, nullFence)); + // vkAssert(!vkQueueWaitIdle(Instance->Graphics.DeviceQueueGraphic)); + + vkAssert(!vkQueueSubmit(*lockQueue, 1, &submit_info, Fence)); + lockQueue.unlock(); + //vkAssert(!vkQueueWaitIdle(Instance->Graphics.DeviceQueueGraphic)); + //vkQueueWaitIdle(Instance->Graphics.DeviceQueueGraphic); + vkAssert(!vkWaitForFences(Instance->Graphics.Device, 1, &Fence, VK_TRUE, UINT64_MAX)); + vkAssert(!vkResetFences(Instance->Graphics.Device, 1, &Fence)); + VkCommandBufferBeginInfo infoCmdBuffer = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, diff --git a/Src/Client/Vulkan/Vulkan.hpp b/Src/Client/Vulkan/Vulkan.hpp index 57f4ff7..62a732f 100644 --- a/Src/Client/Vulkan/Vulkan.hpp +++ b/Src/Client/Vulkan/Vulkan.hpp @@ -178,7 +178,7 @@ private: asio::executor_work_guard GuardLock; public: - struct { + struct GraphicsObj_t { std::vector InstanceLayers; std::vector InstanceExtensions; std::vector GLFWExtensions; @@ -191,7 +191,7 @@ public: VkPhysicalDevice PhysicalDevice = nullptr; VkPhysicalDeviceMemoryProperties DeviceMemoryProperties = {0}; VkDevice Device = nullptr; - VkQueue DeviceQueueGraphic = VK_NULL_HANDLE; + SpinlockObject DeviceQueueGraphic; VkFormat SurfaceFormat = VK_FORMAT_B8G8R8A8_UNORM; VkColorSpaceKHR SurfaceColorSpace = VK_COLOR_SPACE_MAX_ENUM_KHR; @@ -226,6 +226,10 @@ public: // Идентификатор потока графики std::thread::id ThisThread = std::this_thread::get_id(); + + GraphicsObj_t() + : DeviceQueueGraphic(VK_NULL_HANDLE) + {} } Graphics; enum struct DrawState { @@ -537,6 +541,7 @@ public: class CommandBuffer { VkCommandBuffer Buffer = VK_NULL_HANDLE; Vulkan *Instance; + VkFence Fence = VK_NULL_HANDLE; std::vector> AfterExecute; VkCommandPool OffthreadPool = VK_NULL_HANDLE; diff --git a/Src/Client/Vulkan/VulkanRenderSession.cpp b/Src/Client/Vulkan/VulkanRenderSession.cpp index 08f7d20..eda796e 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.cpp +++ b/Src/Client/Vulkan/VulkanRenderSession.cpp @@ -21,6 +21,7 @@ namespace LV::Client::VK { void VulkanRenderSession::ThreadVertexObj_t::run() { Logger LOG = "ThreadVertex"; + LOG.debug() << "Старт потока подготовки чанков к рендеру"; // Контейнеры событий std::vector changedDefines_Voxel; @@ -34,16 +35,172 @@ void VulkanRenderSession::ThreadVertexObj_t::run() { // std::vector::Pointer> ToDelete_Voxels; // std::vector::Pointer> ToDelete_Nodes; - try { + try { while(State.get_read().Stage != EnumRenderStage::Shutdown) { - bool hasWork = false; + bool hasWork = false, hasVertexChanges = false; auto lock = State.lock(); - if(lock->Stage != EnumRenderStage::WorldUpdate) { + // uint64_t now = 0; + + if((!changedContent_RegionRemove.empty() || !chunksUpdate.empty()) + && (lock->Stage == EnumRenderStage::Render || lock->Stage == EnumRenderStage::WorldUpdate)) + { + // Здесь можно выгрузить готовые данные в ChunkMesh + lock->ChunkMesh_IsUse = true; + lock.unlock(); + hasWork = true; + // now = Time::nowSystem(); + + // Удаляем регионы + std::vector toRemove; + for(auto& [worldId, regions] : changedContent_RegionRemove) { + auto iterWorld = ChunkMesh.find(worldId); + if(iterWorld == ChunkMesh.end()) + continue; + + for(Pos::GlobalRegion regionPos : regions) { + auto iterRegion = iterWorld->second.find(regionPos); + if(iterRegion == iterWorld->second.end()) + continue; + + for(size_t index = 0; index < iterRegion->second.size(); index++) { + auto &chunk = iterRegion->second[index]; + chunk.NodeDefines.clear(); + chunk.VoxelDefines.clear(); + + VertexPool_Voxels.dropVertexs(chunk.VoxelPointer); + VertexPool_Nodes.dropVertexs(chunk.NodePointer); + } + + iterWorld->second.erase(iterRegion); + } + + if(iterWorld->second.empty()) + toRemove.push_back(worldId); + } + + for(WorldId_t worldId : toRemove) + ChunkMesh.erase(ChunkMesh.find(worldId)); + + // Добавляем обновлённые меши + for(auto& [worldId, regions] : chunksUpdate) { + auto &world = ChunkMesh[worldId]; + + for(auto& [regionPos, chunks] : regions) { + auto ®ion = world[regionPos]; + + for(auto& [chunkPos, chunk] : chunks) { + auto &drawChunk = region[chunkPos.pack()]; + VertexPool_Voxels.dropVertexs(drawChunk.VoxelPointer); + VertexPool_Nodes.dropVertexs(drawChunk.NodePointer); + drawChunk = std::move(chunk); + } + } + } + + + State.lock()->ChunkMesh_IsUse = false; + chunksUpdate.clear(); + + // LOG.debug() << "ChunkMesh_IsUse: " << Time::nowSystem() - now; + + lock = State.lock(); + } + + if((!changedContent_Chunk.empty()) + && (lock->Stage == EnumRenderStage::ComposingCommandBuffer || lock->Stage == EnumRenderStage::Render)) + { + // Здесь можно обработать события, и подготовить меши по данным с мира + lock->ServerSession_InUse = true; + lock.unlock(); + // now = Time::nowSystem(); + hasWork = true; + // changedContent_Chunk + + std::vector toRemove; + for(auto& [worldId, chunks] : changedContent_Chunk) { + while(!chunks.empty() && (State.get_read().Stage == EnumRenderStage::ComposingCommandBuffer || State.get_read().Stage == EnumRenderStage::Render)) { + auto& chunkPos = chunks.back(); + Pos::GlobalRegion regionPos = chunkPos >> 2; + Pos::bvec4u localPos = chunkPos & 0x3; + + auto& drawChunk = chunksUpdate[worldId][regionPos][localPos]; + { + auto iterWorld = SSession->Data.Worlds.find(worldId); + if(iterWorld == SSession->Data.Worlds.end()) + goto skip; + + auto iterRegion = iterWorld->second.Regions.find(regionPos); + if(iterRegion == iterWorld->second.Regions.end()) + goto skip; + + auto& chunk = iterRegion->second.Chunks[localPos.pack()]; + + { + drawChunk.VoxelDefines.resize(chunk.Voxels.size()); + for(size_t index = 0; index < chunk.Voxels.size(); index++) + drawChunk.VoxelDefines[index] = chunk.Voxels[index].VoxelId; + std::sort(drawChunk.VoxelDefines.begin(), drawChunk.VoxelDefines.end()); + auto last = std::unique(drawChunk.VoxelDefines.begin(), drawChunk.VoxelDefines.end()); + drawChunk.VoxelDefines.erase(last, drawChunk.VoxelDefines.end()); + drawChunk.VoxelDefines.shrink_to_fit(); + } + + { + drawChunk.NodeDefines.resize(chunk.Nodes.size()); + for(size_t index = 0; index < chunk.Nodes.size(); index++) + drawChunk.NodeDefines[index] = chunk.Nodes[index].NodeId; + std::sort(drawChunk.NodeDefines.begin(), drawChunk.NodeDefines.end()); + auto last = std::unique(drawChunk.NodeDefines.begin(), drawChunk.NodeDefines.end()); + drawChunk.NodeDefines.erase(last, drawChunk.NodeDefines.end()); + drawChunk.NodeDefines.shrink_to_fit(); + } + + { + std::vector voxels = generateMeshForVoxelChunks(chunk.Voxels); + if(!voxels.empty()) { + drawChunk.VoxelPointer = VertexPool_Voxels.pushVertexs(std::move(voxels)); + hasVertexChanges = true; + } + } + + { + std::vector nodes = generateMeshForNodeChunks(chunk.Nodes.data()); + if(!nodes.empty()) { + drawChunk.NodePointer = VertexPool_Nodes.pushVertexs(std::move(nodes)); + hasVertexChanges = true; + } + } + } + + skip: + + chunks.pop_back(); + } + + if(chunks.empty()) + toRemove.push_back(worldId); + } + + State.lock()->ServerSession_InUse = false; + + for(WorldId_t worldId : toRemove) + changedContent_Chunk.erase(changedContent_Chunk.find(worldId)); + + // LOG.debug() << "ServerSession_InUse: " << Time::nowSystem() - now; + lock = State.lock(); + } + + if((!ChangedContent_Chunk.empty() || !ChangedContent_RegionRemove.empty() + || !ChangedDefines_Voxel.empty() || !ChangedDefines_Node.empty()) + && (lock->Stage != EnumRenderStage::WorldUpdate)) + { // Переносим все события в локальные хранилища lock->ServerSession_InUse = true; lock.unlock(); + // now = Time::nowSystem(); + hasWork = true; if(!ChangedContent_Chunk.empty()) { for(auto& [worldId, chunks] : ChangedContent_Chunk) { @@ -52,7 +209,6 @@ void VulkanRenderSession::ThreadVertexObj_t::run() { } ChangedContent_Chunk.clear(); - hasWork = true; } if(!ChangedContent_RegionRemove.empty()) { @@ -62,7 +218,6 @@ void VulkanRenderSession::ThreadVertexObj_t::run() { } ChangedContent_RegionRemove.clear(); - hasWork = true; } if(!ChangedDefines_Voxel.empty()) { @@ -72,7 +227,6 @@ void VulkanRenderSession::ThreadVertexObj_t::run() { std::sort(changedDefines_Voxel.begin(), changedDefines_Voxel.end()); auto last = std::unique(changedDefines_Voxel.begin(), changedDefines_Voxel.end()); changedDefines_Voxel.erase(last, changedDefines_Voxel.end()); - hasWork = true; } if(!ChangedDefines_Node.empty()) { @@ -82,7 +236,6 @@ void VulkanRenderSession::ThreadVertexObj_t::run() { std::sort(changedDefines_Node.begin(), changedDefines_Node.end()); auto last = std::unique(changedDefines_Node.begin(), changedDefines_Node.end()); changedDefines_Node.erase(last, changedDefines_Node.end()); - hasWork = true; } State.lock()->ServerSession_InUse = false; @@ -152,155 +305,19 @@ void VulkanRenderSession::ThreadVertexObj_t::run() { regions.erase(last, regions.end()); } + // LOG.debug() << "WorldUpdate: " << Time::nowSystem() - now; lock = State.lock(); } - if(lock->Stage == EnumRenderStage::ComposingCommandBuffer || lock->Stage == EnumRenderStage::Render) { - // Здесь можно обработать события, и подготовить меши по данным с мира - lock->ServerSession_InUse = true; - lock.unlock(); - // changedContent_Chunk - if(!changedContent_Chunk.empty()) - hasWork = true; - - std::vector toRemove; - for(auto& [worldId, chunks] : changedContent_Chunk) { - while(!chunks.empty() && State.get_read().Stage != EnumRenderStage::ComposingCommandBuffer && State.get_read().Stage != EnumRenderStage::Render) { - auto& chunkPos = chunks.back(); - Pos::GlobalRegion regionPos = chunkPos >> 2; - Pos::bvec4u localPos = chunkPos & 0x3; - - auto& drawChunk = chunksUpdate[worldId][regionPos][localPos]; - { - auto iterWorld = SSession->Data.Worlds.find(worldId); - if(iterWorld == SSession->Data.Worlds.end()) - goto skip; - - auto iterRegion = iterWorld->second.Regions.find(regionPos); - if(iterRegion == iterWorld->second.Regions.end()) - goto skip; - - auto& chunk = iterRegion->second.Chunks[localPos.pack()]; - - { - drawChunk.VoxelDefines.resize(chunk.Voxels.size()); - for(size_t index = 0; index < chunk.Voxels.size(); index++) - drawChunk.VoxelDefines[index] = chunk.Voxels[index].VoxelId; - std::sort(drawChunk.VoxelDefines.begin(), drawChunk.VoxelDefines.end()); - auto last = std::unique(drawChunk.VoxelDefines.begin(), drawChunk.VoxelDefines.end()); - drawChunk.VoxelDefines.erase(last, drawChunk.VoxelDefines.end()); - drawChunk.VoxelDefines.shrink_to_fit(); - } - - { - drawChunk.NodeDefines.resize(chunk.Nodes.size()); - for(size_t index = 0; index < chunk.Nodes.size(); index++) - drawChunk.NodeDefines[index] = chunk.Nodes[index].NodeId; - std::sort(drawChunk.NodeDefines.begin(), drawChunk.NodeDefines.end()); - auto last = std::unique(drawChunk.NodeDefines.begin(), drawChunk.NodeDefines.end()); - drawChunk.NodeDefines.erase(last, drawChunk.NodeDefines.end()); - drawChunk.NodeDefines.shrink_to_fit(); - } - - { - std::vector voxels = generateMeshForVoxelChunks(chunk.Voxels); - if(!voxels.empty()) { - drawChunk.VoxelPointer = VertexPool_Voxels.pushVertexs(std::move(voxels)); - } - } - - { - std::vector nodes = generateMeshForNodeChunks(chunk.Nodes.data()); - if(!nodes.empty()) { - drawChunk.NodePointer = VertexPool_Nodes.pushVertexs(std::move(nodes)); - } - } - } - - skip: - - chunks.pop_back(); - } - - if(chunks.empty()) - toRemove.push_back(worldId); - } - - for(WorldId_t worldId : toRemove) - changedContent_Chunk.erase(changedContent_Chunk.find(worldId)); - - lock = State.lock(); - lock->ServerSession_InUse = false; - } - - if(lock->Stage == EnumRenderStage::Render || lock->Stage == EnumRenderStage::WorldUpdate) { - // Здесь можно выгрузить готовые данные в ChunkMesh - lock->ChunkMesh_IsUse = true; - lock.unlock(); - - if(!changedContent_RegionRemove.empty()) - hasWork = true; - - // Удаляем регионы - std::vector toRemove; - for(auto& [worldId, regions] : changedContent_RegionRemove) { - auto iterWorld = ChunkMesh.find(worldId); - if(iterWorld == ChunkMesh.end()) - continue; - - for(Pos::GlobalRegion regionPos : regions) { - auto iterRegion = iterWorld->second.find(regionPos); - if(iterRegion == iterWorld->second.end()) - continue; - - for(size_t index = 0; index < iterRegion->second.size(); index++) { - auto &chunk = iterRegion->second[index]; - chunk.NodeDefines.clear(); - chunk.VoxelDefines.clear(); - - VertexPool_Voxels.dropVertexs(chunk.VoxelPointer); - VertexPool_Nodes.dropVertexs(chunk.NodePointer); - } - - iterWorld->second.erase(iterRegion); - } - - if(iterWorld->second.empty()) - toRemove.push_back(worldId); - } - - for(WorldId_t worldId : toRemove) - ChunkMesh.erase(ChunkMesh.find(worldId)); - - if(!chunksUpdate.empty()) - hasWork = true; - - // Добавляем обновлённые меши - for(auto& [worldId, regions] : chunksUpdate) { - auto &world = ChunkMesh[worldId]; - - for(auto& [regionPos, chunks] : regions) { - auto ®ion = world[regionPos]; - - for(auto& [chunkPos, chunk] : chunks) { - auto &drawChunk = region[chunkPos.pack()]; - VertexPool_Voxels.dropVertexs(drawChunk.VoxelPointer); - VertexPool_Nodes.dropVertexs(drawChunk.NodePointer); - drawChunk = std::move(chunk); - } - } - } - - chunksUpdate.clear(); - - lock = State.lock(); - lock->ChunkMesh_IsUse = false; - } - lock.unlock(); + if(hasVertexChanges) { + VertexPool_Voxels.update(CMDPool); + VertexPool_Nodes.update(CMDPool); + } + if(!hasWork) - Time::sleep3(20); + Time::sleep3(3); } } catch(const std::exception &exc) { LOG.error() << exc.what(); @@ -310,6 +327,8 @@ void VulkanRenderSession::ThreadVertexObj_t::run() { lock->Stage = EnumRenderStage::Shutdown; lock->ChunkMesh_IsUse = false; lock->ServerSession_InUse = false; + + LOG.debug() << "Завершение потока подготовки чанков к рендеру"; } void VulkanRenderSession::VulkanContext::onUpdate() { @@ -329,7 +348,6 @@ VulkanRenderSession::VulkanRenderSession() } VulkanRenderSession::~VulkanRenderSession() { - } void VulkanRenderSession::free(Vulkan *instance) { diff --git a/Src/Client/Vulkan/VulkanRenderSession.hpp b/Src/Client/Vulkan/VulkanRenderSession.hpp index 1cf3f36..351c7fe 100644 --- a/Src/Client/Vulkan/VulkanRenderSession.hpp +++ b/Src/Client/Vulkan/VulkanRenderSession.hpp @@ -82,6 +82,7 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent { // соответственно никто не попытаеся сюда обратится без событий IServerSession *SSession = nullptr; Vulkan *VkInst; + VkCommandPool CMDPool = nullptr; // Здесь не хватает стадии работы с текстурами struct StateObj_t { @@ -104,11 +105,24 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent { VertexPool_Voxels(vkInst), VertexPool_Nodes(vkInst), Thread(&ThreadVertexObj_t::run, this) - {} + { + const VkCommandPoolCreateInfo infoCmdPool = + { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + .queueFamilyIndex = VkInst->getSettings().QueueGraphics + }; + + vkAssert(!vkCreateCommandPool(VkInst->Graphics.Device, &infoCmdPool, nullptr, &CMDPool)); + } ~ThreadVertexObj_t() { State.lock()->Stage = EnumRenderStage::Shutdown; Thread.join(); + + if(CMDPool) + vkDestroyCommandPool(VkInst->Graphics.Device, CMDPool, nullptr); } // Сюда входят добавленные/изменённые/удалённые определения нод и вокселей @@ -148,16 +162,21 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent { while(State.get_read().ChunkMesh_IsUse); } else lock.unlock(); - - VertexPool_Voxels.update(VkInst->Graphics.Pool); - VertexPool_Nodes.update(VkInst->Graphics.Pool); } else if(stage == EnumRenderStage::WorldUpdate) { if(lock->ServerSession_InUse) { lock.unlock(); while(State.get_read().ServerSession_InUse); } else lock.unlock(); + } else if(stage == EnumRenderStage::Shutdown) { + if(lock->ServerSession_InUse || lock->ChunkMesh_IsUse) { + lock.unlock(); + while(State.get_read().ServerSession_InUse); + while(State.get_read().ChunkMesh_IsUse); + } else + lock.unlock(); } + } std::pair< @@ -181,7 +200,9 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent { bool isVisible = false; for(int index = 0; index < 8; index++) { - glm::vec4 temp = glm::vec4((begin+glm::vec3(index&1, (index>>1)&1, (index>>2)&1))*64.f, 1) * projView; + glm::vec4 vec((begin+glm::vec3(index&1, (index>>1)&1, (index>>2)&1))*64.f, 1); + glm::vec4 temp = projView * vec; + temp /= temp.w; if(temp.x >= -1 && temp.x <= 1 && temp.y >= -1 && temp.y <= 1 @@ -252,7 +273,6 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent { {} ~VulkanContext() { - ThreadVertexObj.pushStage(EnumRenderStage::Shutdown); } void onUpdate();