Синхронизация графической очереди

This commit is contained in:
2025-07-26 01:55:11 +06:00
parent 824b7f2f80
commit 9e0c6c5220
5 changed files with 337 additions and 181 deletions

View File

@@ -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<Task> postponed = std::move(TasksPostponed);

View File

@@ -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<std::string_view> knownDebugLayers =
@@ -1506,7 +1542,38 @@ void Vulkan::initNextSettings()
break;
}
Graphics.Instance.emplace(this, enableDebugLayers);
std::vector<vkInstanceExtension> 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<PFN_vkCreateDebugUtilsMessengerEXT>(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,

View File

@@ -178,7 +178,7 @@ private:
asio::executor_work_guard<asio::io_context::executor_type> GuardLock;
public:
struct {
struct GraphicsObj_t {
std::vector<vkInstanceLayer> InstanceLayers;
std::vector<vkInstanceExtension> InstanceExtensions;
std::vector<std::string> GLFWExtensions;
@@ -191,7 +191,7 @@ public:
VkPhysicalDevice PhysicalDevice = nullptr;
VkPhysicalDeviceMemoryProperties DeviceMemoryProperties = {0};
VkDevice Device = nullptr;
VkQueue DeviceQueueGraphic = VK_NULL_HANDLE;
SpinlockObject<VkQueue> 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<std::function<void()>> AfterExecute;
VkCommandPool OffthreadPool = VK_NULL_HANDLE;

View File

@@ -21,6 +21,7 @@ namespace LV::Client::VK {
void VulkanRenderSession::ThreadVertexObj_t::run() {
Logger LOG = "ThreadVertex";
LOG.debug() << "Старт потока подготовки чанков к рендеру";
// Контейнеры событий
std::vector<DefVoxelId_t> changedDefines_Voxel;
@@ -34,16 +35,172 @@ void VulkanRenderSession::ThreadVertexObj_t::run() {
// std::vector<VertexPool<VoxelVertexPoint>::Pointer> ToDelete_Voxels;
// std::vector<VertexPool<VoxelVertexPoint>::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<WorldId_t> 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 &region = 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<WorldId_t> 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<VoxelVertexPoint> voxels = generateMeshForVoxelChunks(chunk.Voxels);
if(!voxels.empty()) {
drawChunk.VoxelPointer = VertexPool_Voxels.pushVertexs(std::move(voxels));
hasVertexChanges = true;
}
}
{
std::vector<NodeVertexStatic> 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<WorldId_t> 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<VoxelVertexPoint> voxels = generateMeshForVoxelChunks(chunk.Voxels);
if(!voxels.empty()) {
drawChunk.VoxelPointer = VertexPool_Voxels.pushVertexs(std::move(voxels));
}
}
{
std::vector<NodeVertexStatic> 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<WorldId_t> 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 &region = 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) {

View File

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