squashed commits

erase chunk buffers only after marking as to be deleted

update chunks around player with a cube instead of concentric spheres

only generate chunks around player, update all chunks use onetbb::parallel_for
fix-multithread
EmaMaker 2023-09-21 15:49:50 +02:00
parent 5f396a9801
commit 01f1f9da16
5 changed files with 88 additions and 81 deletions

View File

@ -36,9 +36,10 @@ namespace chunkmanager
void stop(); void stop();
void destroy(); void destroy();
oneapi::tbb::concurrent_queue<Chunk::Chunk*>& getDeleteVector(); oneapi::tbb::concurrent_queue<Chunk::Chunk*>& getDeleteVector();
std::array<std::array<int, 3>, chunks_volume>& getChunksIndices(); std::array<std::array<uint16_t, 3>, chunks_volume>& getChunksIndices();
Block getBlockAtPos(int x, int y, int z); Block getBlockAtPos(int x, int y, int z);
void update(); void update();
void primary_thread_update();
} }
#endif #endif

View File

@ -10,10 +10,11 @@
#define extr extern #define extr extern
#endif #endif
#define RENDER_DISTANCE 16 #define RENDER_DISTANCE 8
extr Camera theCamera; extr Camera theCamera;
constexpr int chunks_volume = static_cast<int>(1.333333333333*M_PI*(RENDER_DISTANCE*RENDER_DISTANCE*RENDER_DISTANCE)); //constexpr int chunks_volume = static_cast<int>(1.333333333333*M_PI*(RENDER_DISTANCE*RENDER_DISTANCE*RENDER_DISTANCE));
constexpr int chunks_volume = RENDER_DISTANCE*RENDER_DISTANCE*RENDER_DISTANCE*8;
extr bool wireframe; extr bool wireframe;
extr float sines[360]; extr float sines[360];

View File

@ -5,6 +5,8 @@
#include <vector> #include <vector>
#include <thread> #include <thread>
#include <oneapi/tbb.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
@ -24,7 +26,7 @@ namespace chunkmanager
// Concurrent hash table of chunks // Concurrent hash table of chunks
ChunkTable chunks; ChunkTable chunks;
// Chunk indices. Centered at (0,0,0), going in concentric sphere outwards // Chunk indices. Centered at (0,0,0), going in concentric sphere outwards
std::array<std::array<int, 3>, chunks_volume> chunks_indices; std::array<std::array<uint16_t, 3>, chunks_volume> chunks_indices;
/* Multithreading */ /* Multithreading */
std::atomic_bool should_run; std::atomic_bool should_run;
@ -40,45 +42,22 @@ namespace chunkmanager
int chunks_volume_real; int chunks_volume_real;
void init(){ void init(){
int index{0}; int index{0};
int rr{RENDER_DISTANCE * RENDER_DISTANCE}; constexpr int rr{RENDER_DISTANCE * RENDER_DISTANCE};
int xp{0}, x{0}; int xp{0}, x{0};
bool b = true; bool b = true;
// Iterate over all chunks, in concentric spheres starting fron the player and going outwards. Alternate left and right for(int i = -RENDER_DISTANCE; i < RENDER_DISTANCE; i++)
// Eq. of the sphere (x - a)² + (y - b)² + (z - c)² = r² for(int j = -RENDER_DISTANCE; j < RENDER_DISTANCE; j++)
while (xp <= RENDER_DISTANCE) for(int k = -RENDER_DISTANCE; k < RENDER_DISTANCE; k++){
{
// Alternate between left and right
if (b) x = +xp;
else x = -xp;
// Step 1. At current x, get the corresponding y values (2nd degree equation, up to 2 chunks_indices[index][0]=i;
// possible results) chunks_indices[index][1]=j;
int y1 = static_cast<int>(sqrt((rr) - x*x)); chunks_indices[index][2]=k;
for (int y = -y1 + 1 ; y <= y1; y++)
{
// Step 2. At both y's, get the corresponding z values
int z1 = static_cast<int>(sqrt( rr - x*x - y*y));
for (int z = -z1 + 1; z <= z1; z++){
chunks_indices[index][0] = x;
chunks_indices[index][1] = y;
chunks_indices[index][2] = z;
index++; index++;
} }
}
if (!b)
{
xp++;
b = true;
}
else b = false;
}
chunks_volume_real = index;
std::cout << index << std::endl;
// Also init mesh data queue // Also init mesh data queue
for(int i = 0; i < 10; i++) for(int i = 0; i < 10; i++)
chunkmesher::getMeshDataQueue().push(new chunkmesher::MeshData()); chunkmesher::getMeshDataQueue().push(new chunkmesher::MeshData());
@ -107,7 +86,6 @@ namespace chunkmanager
Chunk::Chunk* chunk = entry.first; Chunk::Chunk* chunk = entry.first;
if(chunk->getState(Chunk::CHUNK_STATE_GENERATED)){ if(chunk->getState(Chunk::CHUNK_STATE_GENERATED)){
chunkmesher::mesh(chunk); chunkmesher::mesh(chunk);
renderer::getChunksToRender().insert(chunk);
} }
} }
} }
@ -121,6 +99,19 @@ namespace chunkmanager
int chunkY=static_cast<int>(theCamera.getAtomicPosY() / CHUNK_SIZE); int chunkY=static_cast<int>(theCamera.getAtomicPosY() / CHUNK_SIZE);
int chunkZ=static_cast<int>(theCamera.getAtomicPosZ() / CHUNK_SIZE); int chunkZ=static_cast<int>(theCamera.getAtomicPosZ() / CHUNK_SIZE);
// Eventually create new chunks
for(int i = 0; i < chunks_volume; i++) {
const uint16_t x = chunks_indices[i][0] + chunkX;
const uint16_t y = chunks_indices[i][1] + chunkY;
const uint16_t z = chunks_indices[i][2] + chunkZ;
const uint32_t index = calculateIndex(x, y, z);
if(x > 1023 || y > 1023 || z > 1023) continue;
ChunkTable::accessor a, a1, a2, b1, b2, c1, c2;
if(!chunks.find(a, index)) chunks.emplace(a, std::make_pair(index, new Chunk::Chunk(glm::vec3(x,y,z))));
}
debug::window::set_parameter("px", theCamera.getAtomicPosX()); debug::window::set_parameter("px", theCamera.getAtomicPosX());
debug::window::set_parameter("py", theCamera.getAtomicPosY()); debug::window::set_parameter("py", theCamera.getAtomicPosY());
debug::window::set_parameter("pz", theCamera.getAtomicPosZ()); debug::window::set_parameter("pz", theCamera.getAtomicPosZ());
@ -131,46 +122,49 @@ namespace chunkmanager
debug::window::set_parameter("ly", theCamera.getFront().y); debug::window::set_parameter("ly", theCamera.getFront().y);
debug::window::set_parameter("lz", theCamera.getFront().z); debug::window::set_parameter("lz", theCamera.getFront().z);
// Update other chunks
for(int i = 0; i < chunks_volume_real; i++) {
const uint16_t x = chunks_indices[i][0] + chunkX;
const uint16_t y = chunks_indices[i][1] + chunkY;
const uint16_t z = chunks_indices[i][2] + chunkZ;
const uint32_t index = calculateIndex(x, y, z);
if(x > 1023 || y > 1023 || z > 1023) continue;
ChunkTable::accessor a, a1, a2, b1, b2, c1, c2;
if(!chunks.find(a, index)) chunks.emplace(a, std::make_pair(index, new Chunk::Chunk(glm::vec3(x,y,z))));
if(! (a->second->getState(Chunk::CHUNK_STATE_GENERATED))) {
chunks_to_generate_queue.push(std::make_pair(a->second, GENERATION_PRIORITY_NORMAL));
}else if(! (a->second->getState(Chunk::CHUNK_STATE_MESHED))){
if(
(x + 1 > 1023 || (chunks.find(a1, calculateIndex(x+1, y, z)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) &&
(x - 1 < 0|| (chunks.find(a1, calculateIndex(x-1, y, z)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) &&
(y + 1 > 1023 || (chunks.find(a1, calculateIndex(x, y+1, z)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) &&
(y - 1 < 0|| (chunks.find(a1, calculateIndex(x, y-1, z)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) &&
(z + 1 > 1023 || (chunks.find(a1, calculateIndex(x, y, z+1)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) &&
(z - 1 < 0|| (chunks.find(a1, calculateIndex(x, y, z-1)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED)))
)
chunks_to_mesh_queue.push(std::make_pair(a->second, MESHING_PRIORITY_NORMAL));
}
a.release();
}
debug::window::set_parameter("update_chunks_total", (int) (chunks.size())); debug::window::set_parameter("update_chunks_total", (int) (chunks.size()));
debug::window::set_parameter("update_chunks_bucket", (int) (chunks.max_size())); debug::window::set_parameter("update_chunks_bucket", (int) (chunks.max_size()));
// Perform needed operations on all the chunks
oneapi::tbb::parallel_for(chunks.range(), [](ChunkTable::range_type &r){
for(ChunkTable::const_iterator a = r.begin(); a != r.end(); a++){
if(a->second->getState(Chunk::CHUNK_STATE_UNLOADED)){
chunks_todelete.push(a->second);
continue;
}
if(! (a->second->getState(Chunk::CHUNK_STATE_GENERATED))) {
chunks_to_generate_queue.push(std::make_pair(a->second, GENERATION_PRIORITY_NORMAL));
}else if(! (a->second->getState(Chunk::CHUNK_STATE_MESHED))){
int x = a->second->getPosition().x;
int y = a->second->getPosition().y;
int z = a->second->getPosition().z;
ChunkTable::const_accessor a1;
if(
(x + 1 > 1023 || (chunks.find(a1, calculateIndex(x+1, y, z)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) &&
(x - 1 < 0|| (chunks.find(a1, calculateIndex(x-1, y, z)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) &&
(y + 1 > 1023 || (chunks.find(a1, calculateIndex(x, y+1, z)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) &&
(y - 1 < 0|| (chunks.find(a1, calculateIndex(x, y-1, z)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) &&
(z + 1 > 1023 || (chunks.find(a1, calculateIndex(x, y, z+1)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED))) &&
(z - 1 < 0|| (chunks.find(a1, calculateIndex(x, y, z-1)) &&
a1->second->getState(Chunk::CHUNK_STATE_GENERATED)))
)
chunks_to_mesh_queue.push(std::make_pair(a->second, MESHING_PRIORITY_NORMAL));
}else{
renderer::getChunksToRender().insert(a->second);
}
}
});
Chunk::Chunk* n; Chunk::Chunk* n;
nUnloaded = 0; ChunkTable::accessor a;
while(chunks_todelete.try_pop(n)){ while(chunks_todelete.try_pop(n)){
int x = static_cast<uint16_t>(n->getPosition().x); int x = static_cast<uint16_t>(n->getPosition().x);
int y = static_cast<uint16_t>(n->getPosition().y); int y = static_cast<uint16_t>(n->getPosition().y);
@ -178,10 +172,14 @@ namespace chunkmanager
if(x > 1023 || y > 1023 || z > 1023) continue; if(x > 1023 || y > 1023 || z > 1023) continue;
const uint32_t index = calculateIndex(x, y, z); const uint32_t index = calculateIndex(x, y, z);
chunks.erase(index); //std::cout << n->getState(Chunk::CHUNK_STATE_GENERATED) << "\n";
//delete n; if(chunks.erase(index)){
nUnloaded++; delete n;
nUnloaded++;
}
} }
debug::window::set_parameter("update_chunks_freed", nUnloaded);
} }
} }
@ -191,7 +189,7 @@ namespace chunkmanager
} }
oneapi::tbb::concurrent_queue<Chunk::Chunk*>& getDeleteVector(){ return chunks_todelete; } oneapi::tbb::concurrent_queue<Chunk::Chunk*>& getDeleteVector(){ return chunks_todelete; }
std::array<std::array<int, 3>, chunks_volume>& getChunksIndices(){ return chunks_indices; } std::array<std::array<uint16_t, 3>, chunks_volume>& getChunksIndices(){ return chunks_indices; }
void stop() { void stop() {
should_run=false; should_run=false;

View File

@ -115,8 +115,8 @@ namespace debug{
if(ImGui::CollapsingHeader("Chunks")){ if(ImGui::CollapsingHeader("Chunks")){
ImGui::Text("Total chunks present: %d", ImGui::Text("Total chunks present: %d",
std::any_cast<int>(parameters.at("update_chunks_total"))); std::any_cast<int>(parameters.at("update_chunks_total")));
/*ImGui::Text("Chunks freed from memory: %d", ImGui::Text("Chunks freed from memory: %d",
std::any_cast<int>(parameters.at("update_chunks_delete")));*/ std::any_cast<int>(parameters.at("update_chunks_freed")));
ImGui::Text("Bucket size: %d", ImGui::Text("Bucket size: %d",
std::any_cast<int>(parameters.at("update_chunks_bucket"))); std::any_cast<int>(parameters.at("update_chunks_bucket")));
} }

View File

@ -1,5 +1,8 @@
#include "renderer.hpp" #include "renderer.hpp"
#include <glm/ext.hpp>
#include <glm/gtx/string_cast.hpp>
#include <oneapi/tbb/concurrent_vector.h> #include <oneapi/tbb/concurrent_vector.h>
#include <oneapi/tbb/concurrent_queue.h> #include <oneapi/tbb/concurrent_queue.h>
@ -145,8 +148,11 @@ namespace renderer{
} }
for(auto& c : chunks_torender){ for(auto& c : chunks_torender){
float dist = glm::distance(c->getPosition(), cameraChunkPos); //float dist = glm::distance(c->getPosition(), cameraChunkPos);
if(dist <= static_cast<float>(RENDER_DISTANCE)){ //if(static_cast<int>(dist) <= RENDER_DISTANCE + 1){
if(abs(c->getPosition().x - cameraChunkPos.x) <= RENDER_DISTANCE &&
abs(c->getPosition().y - cameraChunkPos.y) <= RENDER_DISTANCE &&
abs(c->getPosition().z - cameraChunkPos.z) <= RENDER_DISTANCE){
if(!c->getState(Chunk::CHUNK_STATE_MESH_LOADED)) continue; if(!c->getState(Chunk::CHUNK_STATE_MESH_LOADED)) continue;
// Increase total vertex count // Increase total vertex count
@ -204,6 +210,7 @@ namespace renderer{
render_todelete.push_back(c); render_todelete.push_back(c);
} }
} else{ } else{
std::cout << "chunk at " << glm::to_string(c->getPosition()) << std::endl;
// Mark has out of vision and annotate when it started // Mark has out of vision and annotate when it started
c->setState(Chunk::CHUNK_STATE_OUTOFVISION, true); c->setState(Chunk::CHUNK_STATE_OUTOFVISION, true);
c->setState(Chunk::CHUNK_STATE_UNLOADED, false); c->setState(Chunk::CHUNK_STATE_UNLOADED, false);
@ -222,11 +229,11 @@ namespace renderer{
debug::window::set_parameter("render_chunks_vertices", vertices); debug::window::set_parameter("render_chunks_vertices", vertices);
for(auto& c : render_todelete){ for(auto& c : render_todelete){
c->deleteBuffers();
// we can get away with unsafe erase as access to the container is only done by this // we can get away with unsafe erase as access to the container is only done by this
// thread // thread
c->deleteBuffers();
chunks_torender.unsafe_erase(c); chunks_torender.unsafe_erase(c);
chunkmanager::getDeleteVector().push(c); c->setState(Chunk::CHUNK_STATE_UNLOADED, true);
} }
render_todelete.clear(); render_todelete.clear();