Синхронизация графической очереди
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ®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<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 ®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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user