Добавлен Frustum Culling, требующий отладки
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,3 +16,4 @@
|
|||||||
/gmon.out
|
/gmon.out
|
||||||
|
|
||||||
/log.raw
|
/log.raw
|
||||||
|
/Cache
|
||||||
|
|||||||
@@ -148,10 +148,14 @@ void Vulkan::run()
|
|||||||
double prevTime = glfwGetTime();
|
double prevTime = glfwGetTime();
|
||||||
while(!NeedShutdown)
|
while(!NeedShutdown)
|
||||||
{
|
{
|
||||||
|
|
||||||
float dTime = glfwGetTime()-prevTime;
|
float dTime = glfwGetTime()-prevTime;
|
||||||
prevTime += dTime;
|
prevTime += dTime;
|
||||||
|
|
||||||
Screen.State = DrawState::Begin;
|
Screen.State = DrawState::Begin;
|
||||||
|
if(Game.RSession)
|
||||||
|
Game.RSession->pushStage(EnumRenderStage::ComposingCommandBuffer);
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard lock(Screen.BeforeDrawMtx);
|
std::lock_guard lock(Screen.BeforeDrawMtx);
|
||||||
while(!Screen.BeforeDraw.empty())
|
while(!Screen.BeforeDraw.empty())
|
||||||
@@ -452,7 +456,8 @@ void Vulkan::run()
|
|||||||
// vkCmdBeginRenderPass(Graphics.CommandBufferRender, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
|
// vkCmdBeginRenderPass(Graphics.CommandBufferRender, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
if(Game.RSession)
|
||||||
|
Game.RSession->pushStage(EnumRenderStage::Render);
|
||||||
|
|
||||||
#ifdef HAS_IMGUI
|
#ifdef HAS_IMGUI
|
||||||
ImGui_ImplVulkan_NewFrame();
|
ImGui_ImplVulkan_NewFrame();
|
||||||
@@ -539,6 +544,9 @@ void Vulkan::run()
|
|||||||
vkAssert(err == VK_TIMEOUT);
|
vkAssert(err == VK_TIMEOUT);
|
||||||
|
|
||||||
if(Game.Session) {
|
if(Game.Session) {
|
||||||
|
if(Game.RSession)
|
||||||
|
Game.RSession->pushStage(EnumRenderStage::WorldUpdate);
|
||||||
|
|
||||||
Game.Session->atFreeDrawTime(gTime, dTime);
|
Game.Session->atFreeDrawTime(gTime, dTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1021,5 +1021,25 @@ public:
|
|||||||
virtual ~PipelineVGF();
|
virtual ~PipelineVGF();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum class EnumRenderStage {
|
||||||
|
// Постройка буфера команд на рисовку
|
||||||
|
// В этот период не должно быть изменений в таблице,
|
||||||
|
// хранящей указатели на данные для рендера ChunkMesh
|
||||||
|
// Можно работать с миром
|
||||||
|
// Здесь нужно дождаться завершения работы с ChunkMesh
|
||||||
|
ComposingCommandBuffer,
|
||||||
|
// В этот период можно менять ChunkMesh
|
||||||
|
// Можно работать с миром
|
||||||
|
Render,
|
||||||
|
// В этот период нельзя работать с миром
|
||||||
|
// Можно менять ChunkMesh
|
||||||
|
// Здесь нужно дождаться завершения работы с миром, только в
|
||||||
|
// этом этапе могут приходить события изменения чанков и определений
|
||||||
|
WorldUpdate,
|
||||||
|
|
||||||
|
Shutdown
|
||||||
|
};
|
||||||
|
|
||||||
} /* namespace TOS::Navie::VK */
|
} /* namespace TOS::Navie::VK */
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -27,15 +28,22 @@ void VulkanRenderSession::ThreadVertexObj_t::run() {
|
|||||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalChunk>> changedContent_Chunk;
|
std::unordered_map<WorldId_t, std::vector<Pos::GlobalChunk>> changedContent_Chunk;
|
||||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>> changedContent_RegionRemove;
|
std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>> changedContent_RegionRemove;
|
||||||
|
|
||||||
|
// Контейнер новых мешей
|
||||||
|
std::unordered_map<WorldId_t, std::unordered_map<Pos::GlobalRegion, std::unordered_map<Pos::bvec4u, ChunkObj_t>>> chunksUpdate;
|
||||||
|
|
||||||
// std::vector<VertexPool<VoxelVertexPoint>::Pointer> ToDelete_Voxels;
|
// std::vector<VertexPool<VoxelVertexPoint>::Pointer> ToDelete_Voxels;
|
||||||
// std::vector<VertexPool<VoxelVertexPoint>::Pointer> ToDelete_Nodes;
|
// std::vector<VertexPool<VoxelVertexPoint>::Pointer> ToDelete_Nodes;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while(Stage != EnumStage::Shutdown) {
|
|
||||||
if(Stage != EnumStage::WorldUpdate) {
|
while(State.get_read().Stage != EnumRenderStage::Shutdown) {
|
||||||
|
bool hasWork = false;
|
||||||
|
auto lock = State.lock();
|
||||||
|
|
||||||
|
if(lock->Stage != EnumRenderStage::WorldUpdate) {
|
||||||
// Переносим все события в локальные хранилища
|
// Переносим все события в локальные хранилища
|
||||||
ServerSession_InUse = true;
|
lock->ServerSession_InUse = true;
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
if(!ChangedContent_Chunk.empty()) {
|
if(!ChangedContent_Chunk.empty()) {
|
||||||
for(auto& [worldId, chunks] : ChangedContent_Chunk) {
|
for(auto& [worldId, chunks] : ChangedContent_Chunk) {
|
||||||
@@ -44,6 +52,7 @@ void VulkanRenderSession::ThreadVertexObj_t::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ChangedContent_Chunk.clear();
|
ChangedContent_Chunk.clear();
|
||||||
|
hasWork = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ChangedContent_RegionRemove.empty()) {
|
if(!ChangedContent_RegionRemove.empty()) {
|
||||||
@@ -53,6 +62,7 @@ void VulkanRenderSession::ThreadVertexObj_t::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ChangedContent_RegionRemove.clear();
|
ChangedContent_RegionRemove.clear();
|
||||||
|
hasWork = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ChangedDefines_Voxel.empty()) {
|
if(!ChangedDefines_Voxel.empty()) {
|
||||||
@@ -62,6 +72,7 @@ void VulkanRenderSession::ThreadVertexObj_t::run() {
|
|||||||
std::sort(changedDefines_Voxel.begin(), changedDefines_Voxel.end());
|
std::sort(changedDefines_Voxel.begin(), changedDefines_Voxel.end());
|
||||||
auto last = std::unique(changedDefines_Voxel.begin(), changedDefines_Voxel.end());
|
auto last = std::unique(changedDefines_Voxel.begin(), changedDefines_Voxel.end());
|
||||||
changedDefines_Voxel.erase(last, changedDefines_Voxel.end());
|
changedDefines_Voxel.erase(last, changedDefines_Voxel.end());
|
||||||
|
hasWork = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ChangedDefines_Node.empty()) {
|
if(!ChangedDefines_Node.empty()) {
|
||||||
@@ -71,12 +82,13 @@ void VulkanRenderSession::ThreadVertexObj_t::run() {
|
|||||||
std::sort(changedDefines_Node.begin(), changedDefines_Node.end());
|
std::sort(changedDefines_Node.begin(), changedDefines_Node.end());
|
||||||
auto last = std::unique(changedDefines_Node.begin(), changedDefines_Node.end());
|
auto last = std::unique(changedDefines_Node.begin(), changedDefines_Node.end());
|
||||||
changedDefines_Node.erase(last, changedDefines_Node.end());
|
changedDefines_Node.erase(last, changedDefines_Node.end());
|
||||||
|
hasWork = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerSession_InUse = false;
|
State.lock()->ServerSession_InUse = false;
|
||||||
|
|
||||||
// Ищем чанки, которые нужно перерисовать
|
// Ищем чанки, которые нужно перерисовать
|
||||||
if(!changedDefines_Voxel.empty() || changedDefines_Node.empty()) {
|
if(!changedDefines_Voxel.empty() || !changedDefines_Node.empty()) {
|
||||||
for(auto& [worldId, regions] : ChunkMesh) {
|
for(auto& [worldId, regions] : ChunkMesh) {
|
||||||
for(auto& [regionPos, chunks] : regions) {
|
for(auto& [regionPos, chunks] : regions) {
|
||||||
for(size_t index = 0; index < chunks.size(); index++) {
|
for(size_t index = 0; index < chunks.size(); index++) {
|
||||||
@@ -139,22 +151,73 @@ void VulkanRenderSession::ThreadVertexObj_t::run() {
|
|||||||
auto last = std::unique(regions.begin(), regions.end());
|
auto last = std::unique(regions.begin(), regions.end());
|
||||||
regions.erase(last, regions.end());
|
regions.erase(last, regions.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock = State.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Stage == EnumStage::ComposingCommandBuffer || Stage == EnumStage::Render) {
|
if(lock->Stage == EnumRenderStage::ComposingCommandBuffer || lock->Stage == EnumRenderStage::Render) {
|
||||||
// Здесь можно обработать события, и подготовить меши по данным с мира
|
// Здесь можно обработать события, и подготовить меши по данным с мира
|
||||||
|
lock->ServerSession_InUse = true;
|
||||||
|
lock.unlock();
|
||||||
// changedContent_Chunk
|
// changedContent_Chunk
|
||||||
|
if(!changedContent_Chunk.empty())
|
||||||
ServerSession_InUse = true;
|
hasWork = true;
|
||||||
|
|
||||||
std::vector<WorldId_t> toRemove;
|
std::vector<WorldId_t> toRemove;
|
||||||
for(auto& [worldId, chunks] : changedContent_Chunk) {
|
for(auto& [worldId, chunks] : changedContent_Chunk) {
|
||||||
if(Stage != EnumStage::ComposingCommandBuffer && Stage != EnumStage::Render)
|
while(!chunks.empty() && State.get_read().Stage != EnumRenderStage::ComposingCommandBuffer && State.get_read().Stage != EnumRenderStage::Render) {
|
||||||
break;
|
auto& chunkPos = chunks.back();
|
||||||
|
Pos::GlobalRegion regionPos = chunkPos >> 2;
|
||||||
while(!chunks.empty() && Stage != EnumStage::ComposingCommandBuffer && Stage != EnumStage::Render) {
|
Pos::bvec4u localPos = chunkPos & 0x3;
|
||||||
|
|
||||||
// TODO: Сгенерировать меши
|
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();
|
chunks.pop_back();
|
||||||
}
|
}
|
||||||
@@ -166,14 +229,20 @@ void VulkanRenderSession::ThreadVertexObj_t::run() {
|
|||||||
for(WorldId_t worldId : toRemove)
|
for(WorldId_t worldId : toRemove)
|
||||||
changedContent_Chunk.erase(changedContent_Chunk.find(worldId));
|
changedContent_Chunk.erase(changedContent_Chunk.find(worldId));
|
||||||
|
|
||||||
ServerSession_InUse = false;
|
lock = State.lock();
|
||||||
|
lock->ServerSession_InUse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Stage == EnumStage::Render || Stage == EnumStage::WorldUpdate) {
|
if(lock->Stage == EnumRenderStage::Render || lock->Stage == EnumRenderStage::WorldUpdate) {
|
||||||
// Здесь можно выгрузить готовые данные в ChunkMesh
|
// Здесь можно выгрузить готовые данные в ChunkMesh
|
||||||
ChunkMesh_IsUse = true;
|
lock->ChunkMesh_IsUse = true;
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
if(!changedContent_RegionRemove.empty())
|
||||||
|
hasWork = true;
|
||||||
|
|
||||||
// Удаляем регионы
|
// Удаляем регионы
|
||||||
|
std::vector<WorldId_t> toRemove;
|
||||||
for(auto& [worldId, regions] : changedContent_RegionRemove) {
|
for(auto& [worldId, regions] : changedContent_RegionRemove) {
|
||||||
auto iterWorld = ChunkMesh.find(worldId);
|
auto iterWorld = ChunkMesh.find(worldId);
|
||||||
if(iterWorld == ChunkMesh.end())
|
if(iterWorld == ChunkMesh.end())
|
||||||
@@ -192,20 +261,55 @@ void VulkanRenderSession::ThreadVertexObj_t::run() {
|
|||||||
VertexPool_Voxels.dropVertexs(chunk.VoxelPointer);
|
VertexPool_Voxels.dropVertexs(chunk.VoxelPointer);
|
||||||
VertexPool_Nodes.dropVertexs(chunk.NodePointer);
|
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();
|
||||||
|
|
||||||
ChunkMesh_IsUse = false;
|
lock = State.lock();
|
||||||
|
lock->ChunkMesh_IsUse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
if(!hasWork)
|
||||||
|
Time::sleep3(20);
|
||||||
}
|
}
|
||||||
} catch(const std::exception &exc) {
|
} catch(const std::exception &exc) {
|
||||||
LOG.error() << exc.what();
|
LOG.error() << exc.what();
|
||||||
}
|
}
|
||||||
|
|
||||||
ChunkMesh_IsUse = false;
|
auto lock = State.lock();
|
||||||
ServerSession_InUse = false;
|
lock->Stage = EnumRenderStage::Shutdown;
|
||||||
|
lock->ChunkMesh_IsUse = false;
|
||||||
|
lock->ServerSession_InUse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderSession::VulkanContext::onUpdate() {
|
void VulkanRenderSession::VulkanContext::onUpdate() {
|
||||||
@@ -521,6 +625,8 @@ void VulkanRenderSession::init(Vulkan *instance) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VKCTX->setServerSession(ServerSession);
|
||||||
|
|
||||||
updateDescriptor_MainAtlas();
|
updateDescriptor_MainAtlas();
|
||||||
updateDescriptor_VoxelsLight();
|
updateDescriptor_VoxelsLight();
|
||||||
updateDescriptor_ChunksLight();
|
updateDescriptor_ChunksLight();
|
||||||
@@ -877,9 +983,11 @@ void VulkanRenderSession::onContentDefinesLost(std::unordered_map<EnumDefContent
|
|||||||
|
|
||||||
void VulkanRenderSession::onChunksChange(WorldId_t worldId, const std::unordered_set<Pos::GlobalChunk>& changeOrAddList, const std::unordered_set<Pos::GlobalRegion>& remove) {
|
void VulkanRenderSession::onChunksChange(WorldId_t worldId, const std::unordered_set<Pos::GlobalChunk>& changeOrAddList, const std::unordered_set<Pos::GlobalRegion>& remove) {
|
||||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalChunk>> chunkChanges;
|
std::unordered_map<WorldId_t, std::vector<Pos::GlobalChunk>> chunkChanges;
|
||||||
chunkChanges[worldId] = std::vector<Pos::GlobalChunk>(changeOrAddList.begin(), changeOrAddList.end());
|
if(!changeOrAddList.empty())
|
||||||
|
chunkChanges[worldId] = std::vector<Pos::GlobalChunk>(changeOrAddList.begin(), changeOrAddList.end());
|
||||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>> regionRemove;
|
std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>> regionRemove;
|
||||||
regionRemove[worldId] = std::vector<Pos::GlobalRegion>(remove.begin(), remove.end());
|
if(!remove.empty())
|
||||||
|
regionRemove[worldId] = std::vector<Pos::GlobalRegion>(remove.begin(), remove.end());
|
||||||
VKCTX->ThreadVertexObj.onContentChunkChange(chunkChanges, regionRemove);
|
VKCTX->ThreadVertexObj.onContentChunkChange(chunkChanges, regionRemove);
|
||||||
|
|
||||||
// if(chunk.Voxels.empty()) {
|
// if(chunk.Voxels.empty()) {
|
||||||
@@ -1073,6 +1181,24 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff
|
|||||||
|
|
||||||
{
|
{
|
||||||
Pos::GlobalChunk x64offset = X64Offset >> Pos::Object_t::BS_Bit >> 4;
|
Pos::GlobalChunk x64offset = X64Offset >> Pos::Object_t::BS_Bit >> 4;
|
||||||
|
Pos::GlobalRegion x64offset_region = x64offset >> 2;
|
||||||
|
|
||||||
|
auto [voxelVertexs, nodeVertexs] = VKCTX->ThreadVertexObj.getChunksForRender(WorldId, Pos, 2, PCO.ProjView, x64offset_region);
|
||||||
|
|
||||||
|
glm::mat4 orig = PCO.Model;
|
||||||
|
for(auto& [chunkPos, vertexs, vertexCount] : nodeVertexs) {
|
||||||
|
glm::vec3 cpos(chunkPos-x64offset);
|
||||||
|
PCO.Model = glm::translate(orig, cpos*16.f);
|
||||||
|
auto [vkBuffer, offset] = vertexs;
|
||||||
|
|
||||||
|
vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout,
|
||||||
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(WorldPCO, Model), sizeof(WorldPCO::Model), &PCO.Model);
|
||||||
|
vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets);
|
||||||
|
vkCmdDraw(drawCmd, vertexCount, 1, offset, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PCO.Model = orig;
|
||||||
|
|
||||||
// auto iterWorld = External.ChunkVoxelMesh.find(WorldId);
|
// auto iterWorld = External.ChunkVoxelMesh.find(WorldId);
|
||||||
// if(iterWorld != External.ChunkVoxelMesh.end()) {
|
// if(iterWorld != External.ChunkVoxelMesh.end()) {
|
||||||
@@ -1096,6 +1222,13 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VulkanRenderSession::pushStage(EnumRenderStage stage) {
|
||||||
|
if(!VKCTX)
|
||||||
|
return;
|
||||||
|
|
||||||
|
VKCTX->ThreadVertexObj.pushStage(stage);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(const std::vector<VoxelCube> cubes) {
|
std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(const std::vector<VoxelCube> cubes) {
|
||||||
std::vector<VoxelVertexPoint> out;
|
std::vector<VoxelVertexPoint> out;
|
||||||
out.reserve(cubes.size()*6);
|
out.reserve(cubes.size()*6);
|
||||||
|
|||||||
@@ -77,28 +77,19 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
|||||||
Удалённые мешы хранятся в памяти N количество кадров
|
Удалённые мешы хранятся в памяти N количество кадров
|
||||||
*/
|
*/
|
||||||
struct ThreadVertexObj_t {
|
struct ThreadVertexObj_t {
|
||||||
|
// Сессия будет выдана позже
|
||||||
|
// Предполагается что события будут только после того как сессия будет установлена,
|
||||||
|
// соответственно никто не попытаеся сюда обратится без событий
|
||||||
|
IServerSession *SSession = nullptr;
|
||||||
|
Vulkan *VkInst;
|
||||||
|
|
||||||
// Здесь не хватает стадии работы с текстурами
|
// Здесь не хватает стадии работы с текстурами
|
||||||
enum class EnumStage {
|
struct StateObj_t {
|
||||||
// Постройка буфера команд на рисовку
|
EnumRenderStage Stage = EnumRenderStage::Render;
|
||||||
// В этот период не должно быть изменений в таблице,
|
volatile bool ChunkMesh_IsUse = false, ServerSession_InUse = false;
|
||||||
// хранящей указатели на данные для рендера ChunkMesh
|
};
|
||||||
// Можно работать с миром
|
|
||||||
// Здесь нужно дождаться завершения работы с ChunkMesh
|
|
||||||
ComposingCommandBuffer,
|
|
||||||
// В этот период можно менять ChunkMesh
|
|
||||||
// Можно работать с миром
|
|
||||||
Render,
|
|
||||||
// В этот период нельзя работать с миром
|
|
||||||
// Можно менять ChunkMesh
|
|
||||||
// Здесь нужно дождаться завершения работы с миром, только в
|
|
||||||
// этом этапе могут приходить события изменения чанков и определений
|
|
||||||
WorldUpdate,
|
|
||||||
|
|
||||||
Shutdown
|
SpinlockObject<StateObj_t> State;
|
||||||
} Stage = EnumStage::Render;
|
|
||||||
|
|
||||||
volatile bool ChunkMesh_IsUse = false, ServerSession_InUse = false;
|
|
||||||
|
|
||||||
struct ChunkObj_t {
|
struct ChunkObj_t {
|
||||||
// Сортированный список уникальных значений
|
// Сортированный список уникальных значений
|
||||||
@@ -108,18 +99,15 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
|||||||
VertexPool<NodeVertexStatic>::Pointer NodePointer;
|
VertexPool<NodeVertexStatic>::Pointer NodePointer;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<WorldId_t,
|
|
||||||
std::unordered_map<Pos::GlobalRegion, std::array<ChunkObj_t, 4*4*4>>
|
|
||||||
> ChunkMesh;
|
|
||||||
|
|
||||||
ThreadVertexObj_t(Vulkan* vkInst)
|
ThreadVertexObj_t(Vulkan* vkInst)
|
||||||
: VertexPool_Voxels(vkInst),
|
: VkInst(vkInst),
|
||||||
|
VertexPool_Voxels(vkInst),
|
||||||
VertexPool_Nodes(vkInst),
|
VertexPool_Nodes(vkInst),
|
||||||
Thread(&ThreadVertexObj_t::run, this)
|
Thread(&ThreadVertexObj_t::run, this)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~ThreadVertexObj_t() {
|
~ThreadVertexObj_t() {
|
||||||
Stage = EnumStage::Shutdown;
|
State.lock()->Stage = EnumRenderStage::Shutdown;
|
||||||
Thread.join();
|
Thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,20 +132,90 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Синхронизация потока рендера мира
|
// Синхронизация потока рендера мира
|
||||||
void pushStage(EnumStage stage) {
|
void pushStage(EnumRenderStage stage) {
|
||||||
if(Stage == EnumStage::Shutdown)
|
auto lock = State.lock();
|
||||||
|
|
||||||
|
if(lock->Stage == EnumRenderStage::Shutdown)
|
||||||
MAKE_ERROR("Остановка из-за ошибки ThreadVertex");
|
MAKE_ERROR("Остановка из-за ошибки ThreadVertex");
|
||||||
|
|
||||||
assert(Stage != stage);
|
assert(lock->Stage != stage);
|
||||||
|
|
||||||
Stage = stage;
|
lock->Stage = stage;
|
||||||
if(stage == EnumStage::ComposingCommandBuffer) {
|
|
||||||
while(ChunkMesh_IsUse);
|
if(stage == EnumRenderStage::ComposingCommandBuffer) {
|
||||||
} else if(stage == EnumStage::WorldUpdate) {
|
if(lock->ChunkMesh_IsUse) {
|
||||||
while(ServerSession_InUse);
|
lock.unlock();
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<
|
||||||
|
std::vector<std::tuple<Pos::GlobalChunk, std::pair<VkBuffer, int>, uint32_t>>,
|
||||||
|
std::vector<std::tuple<Pos::GlobalChunk, std::pair<VkBuffer, int>, uint32_t>>
|
||||||
|
> getChunksForRender(WorldId_t worldId, Pos::Object pos, uint8_t distance, glm::mat4 projView, Pos::GlobalRegion x64offset) {
|
||||||
|
Pos::GlobalRegion center = pos >> Pos::Object_t::BS_Bit >> 4 >> 2;
|
||||||
|
|
||||||
|
std::vector<std::tuple<Pos::GlobalChunk, std::pair<VkBuffer, int>, uint32_t>> vertexVoxels;
|
||||||
|
std::vector<std::tuple<Pos::GlobalChunk, std::pair<VkBuffer, int>, uint32_t>> vertexNodes;
|
||||||
|
|
||||||
|
auto iterWorld = ChunkMesh.find(worldId);
|
||||||
|
if(iterWorld == ChunkMesh.end())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
for(int z = -distance; z <= distance; z++) {
|
||||||
|
for(int y = -distance; y <= distance; y++) {
|
||||||
|
for(int x = -distance; x <= distance; x++) {
|
||||||
|
Pos::GlobalRegion region = center + Pos::GlobalRegion(x, y, z);
|
||||||
|
glm::vec3 begin = glm::vec3(region - x64offset);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if(temp.x >= -1 && temp.x <= 1
|
||||||
|
&& temp.y >= -1 && temp.y <= 1
|
||||||
|
&& temp.z >= 0 && temp.z <= 1
|
||||||
|
) {
|
||||||
|
isVisible = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isVisible)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto iterRegion = iterWorld->second.find(region);
|
||||||
|
if(iterRegion == iterWorld->second.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Pos::GlobalChunk local = Pos::GlobalChunk(region) << 2;
|
||||||
|
|
||||||
|
for(size_t index = 0; index < iterRegion->second.size(); index++) {
|
||||||
|
auto &chunk = iterRegion->second[index];
|
||||||
|
|
||||||
|
if(chunk.VoxelPointer)
|
||||||
|
vertexVoxels.emplace_back(local+Pos::GlobalChunk(Pos::bvec4u().unpack(index)), VertexPool_Voxels.map(chunk.VoxelPointer), chunk.VoxelPointer.VertexCount);
|
||||||
|
if(chunk.NodePointer)
|
||||||
|
vertexNodes.emplace_back(local+Pos::GlobalChunk(Pos::bvec4u().unpack(index)), VertexPool_Nodes.map(chunk.NodePointer), chunk.NodePointer.VertexCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::pair{vertexVoxels, vertexNodes};
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Буферы для хранения вершин
|
// Буферы для хранения вершин
|
||||||
VertexPool<VoxelVertexPoint> VertexPool_Voxels;
|
VertexPool<VoxelVertexPoint> VertexPool_Voxels;
|
||||||
@@ -168,6 +226,10 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
|||||||
// Список чанков на перерисовку
|
// Список чанков на перерисовку
|
||||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalChunk>> ChangedContent_Chunk;
|
std::unordered_map<WorldId_t, std::vector<Pos::GlobalChunk>> ChangedContent_Chunk;
|
||||||
std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>> ChangedContent_RegionRemove;
|
std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>> ChangedContent_RegionRemove;
|
||||||
|
// Меши
|
||||||
|
std::unordered_map<WorldId_t,
|
||||||
|
std::unordered_map<Pos::GlobalRegion, std::array<ChunkObj_t, 4*4*4>>
|
||||||
|
> ChunkMesh;
|
||||||
// Внешний поток
|
// Внешний поток
|
||||||
std::thread Thread;
|
std::thread Thread;
|
||||||
|
|
||||||
@@ -190,10 +252,14 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
~VulkanContext() {
|
~VulkanContext() {
|
||||||
ThreadVertexObj.pushStage(ThreadVertexObj_t::EnumStage::Shutdown);
|
ThreadVertexObj.pushStage(EnumRenderStage::Shutdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUpdate();
|
void onUpdate();
|
||||||
|
|
||||||
|
void setServerSession(IServerSession* ssession) {
|
||||||
|
ThreadVertexObj.SSession = ssession;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<VulkanContext> VKCTX;
|
std::shared_ptr<VulkanContext> VKCTX;
|
||||||
@@ -249,6 +315,8 @@ public:
|
|||||||
|
|
||||||
void setServerSession(IServerSession *serverSession) {
|
void setServerSession(IServerSession *serverSession) {
|
||||||
ServerSession = serverSession;
|
ServerSession = serverSession;
|
||||||
|
if(VKCTX)
|
||||||
|
VKCTX->setServerSession(serverSession);
|
||||||
assert(serverSession);
|
assert(serverSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,6 +332,7 @@ public:
|
|||||||
|
|
||||||
void beforeDraw();
|
void beforeDraw();
|
||||||
void drawWorld(GlobalTime gTime, float dTime, VkCommandBuffer drawCmd);
|
void drawWorld(GlobalTime gTime, float dTime, VkCommandBuffer drawCmd);
|
||||||
|
void pushStage(EnumRenderStage stage);
|
||||||
|
|
||||||
static std::vector<VoxelVertexPoint> generateMeshForVoxelChunks(const std::vector<VoxelCube> cubes);
|
static std::vector<VoxelVertexPoint> generateMeshForVoxelChunks(const std::vector<VoxelCube> cubes);
|
||||||
static std::vector<NodeVertexStatic> generateMeshForNodeChunks(const Node* nodes);
|
static std::vector<NodeVertexStatic> generateMeshForNodeChunks(const Node* nodes);
|
||||||
|
|||||||
@@ -111,25 +111,47 @@ public:
|
|||||||
|
|
||||||
class Lock {
|
class Lock {
|
||||||
public:
|
public:
|
||||||
Lock(SpinlockObject* obj, std::atomic_flag& lock)
|
Lock(SpinlockObject* obj, std::atomic_flag& flag)
|
||||||
: obj(obj), lock(lock) {
|
: Obj(obj), Flag(&flag) {
|
||||||
while (lock.test_and_set(std::memory_order_acquire));
|
while (flag.test_and_set(std::memory_order_acquire));
|
||||||
}
|
}
|
||||||
|
|
||||||
~Lock() {
|
~Lock() {
|
||||||
if(obj)
|
if(Obj)
|
||||||
lock.clear(std::memory_order_release);
|
Flag->clear(std::memory_order_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
T& get() const { assert(obj); return obj->value; }
|
Lock(const Lock&) = delete;
|
||||||
T* operator->() const { assert(obj); return &obj->value; }
|
Lock(Lock&& obj)
|
||||||
T& operator*() const { assert(obj); return obj->value; }
|
: Obj(obj.Obj), Flag(obj.Flag)
|
||||||
|
{
|
||||||
|
obj.Obj = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void unlock() { obj = nullptr; lock.clear(std::memory_order_release);}
|
Lock& operator=(const Lock&) = delete;
|
||||||
|
Lock& operator=(Lock&& obj) {
|
||||||
|
if(this == &obj)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
if(Obj)
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
Obj = obj.Obj;
|
||||||
|
obj.Obj = nullptr;
|
||||||
|
Flag = obj.Flag;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& get() const { assert(Obj); return Obj->value; }
|
||||||
|
T* operator->() const { assert(Obj); return &Obj->value; }
|
||||||
|
T& operator*() const { assert(Obj); return Obj->value; }
|
||||||
|
|
||||||
|
void unlock() { assert(Obj); Obj = nullptr; Flag->clear(std::memory_order_release);}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SpinlockObject* obj;
|
SpinlockObject *Obj;
|
||||||
std::atomic_flag& lock;
|
std::atomic_flag *Flag;
|
||||||
};
|
};
|
||||||
|
|
||||||
Lock lock() {
|
Lock lock() {
|
||||||
|
|||||||
Reference in New Issue
Block a user