fallimentary attempt at fixing memory management with onetbb
parent
00cdd22e10
commit
1ec529fae5
|
@ -116,7 +116,7 @@ public:
|
|||
|
||||
|
||||
private:
|
||||
glm::vec3 cameraPos = glm::vec3(512.0, 80.0f, 512.0f);
|
||||
glm::vec3 cameraPos = glm::vec3(512.0, 256.0f, 512.0f);
|
||||
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
|
||||
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 direction = glm::vec3(0.0f);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include "globals.hpp"
|
||||
|
||||
// Seconds to be passed outside of render distance for a chunk to be destroyed
|
||||
#define UNLOAD_TIMEOUT 10
|
||||
#define UNLOAD_TIMEOUT 0
|
||||
|
||||
#define MESHING_PRIORITY_NORMAL 0
|
||||
#define MESHING_PRIORITY_PLAYER_EDIT 10
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
#include "shader.hpp"
|
||||
|
||||
namespace renderer{
|
||||
typedef oneapi::tbb::concurrent_unordered_set<Chunk::Chunk*> RenderSet;
|
||||
//typedef oneapi::tbb::concurrent_unordered_set<Chunk::Chunk*> RenderSet;
|
||||
typedef oneapi::tbb::concurrent_queue<Chunk::Chunk*> RenderQueue;
|
||||
|
||||
void init(GLFWwindow* window);
|
||||
void render();
|
||||
|
@ -20,7 +21,7 @@ namespace renderer{
|
|||
void saveScreenshot(bool forceFullHD=false);
|
||||
|
||||
Shader* getRenderShader();
|
||||
RenderSet& getChunksToRender();
|
||||
RenderQueue& getChunksToRender();
|
||||
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*>& getMeshDataQueue();
|
||||
|
||||
};
|
||||
|
|
|
@ -7,4 +7,4 @@ set(SOURCE_FILES main.cpp chunk.cpp chunkmanager.cpp chunkmesher.cpp chunkgenera
|
|||
add_executable(OpenGLTest ${SOURCE_FILES})
|
||||
|
||||
target_link_libraries(OpenGLTest glfw tbb glad glm imgui)
|
||||
install(TARGETS OpenGLTest DESTINATION ${DIVISIBLE_INSTALL_BIN_DIR})
|
||||
install(TARGETS OpenGLTest DESTINATION)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#include "chunkmanager.hpp"
|
||||
|
||||
#include <oneapi/tbb.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
#include <oneapi/tbb.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/ext.hpp>
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
|
@ -63,7 +63,7 @@ namespace chunkmanager
|
|||
chunkmesher::getMeshDataQueue().push(new chunkmesher::MeshData());
|
||||
|
||||
should_run = true;
|
||||
update_thread = std::thread(update);
|
||||
//update_thread = std::thread(update);
|
||||
gen_thread = std::thread(generate);
|
||||
mesh_thread = std::thread(mesh);
|
||||
|
||||
|
@ -92,11 +92,14 @@ namespace chunkmanager
|
|||
}
|
||||
|
||||
oneapi::tbb::concurrent_queue<Chunk::Chunk*> chunks_todelete;
|
||||
oneapi::tbb::concurrent_queue<Chunk::Chunk*> chunks_primary_delete;
|
||||
int nUnloaded{0};
|
||||
int already{0};
|
||||
bool first{true};
|
||||
void update(){
|
||||
while(should_run) {
|
||||
}
|
||||
|
||||
void primary_thread_update(){
|
||||
int chunkX=static_cast<int>(theCamera.getAtomicPosX() / CHUNK_SIZE);
|
||||
int chunkY=static_cast<int>(theCamera.getAtomicPosY() / CHUNK_SIZE);
|
||||
int chunkZ=static_cast<int>(theCamera.getAtomicPosZ() / CHUNK_SIZE);
|
||||
|
@ -139,43 +142,66 @@ namespace chunkmanager
|
|||
|
||||
|
||||
debug::window::set_parameter("update_chunks_total", (int) (chunks.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){
|
||||
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);
|
||||
if(a->second->getState(Chunk::CHUNK_STATE_MESH_LOADED)) chunks_todelete.push(a->second);
|
||||
//nUnloaded++;
|
||||
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_EMPTY)){
|
||||
continue;
|
||||
}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;
|
||||
int distx = a->second->getPosition().x - chunkX;
|
||||
int disty = a->second->getPosition().y - chunkY;
|
||||
int distz = a->second->getPosition().z - chunkZ;
|
||||
if(distx >= -RENDER_DISTANCE && distx < RENDER_DISTANCE &&
|
||||
disty >= -RENDER_DISTANCE && disty < RENDER_DISTANCE &&
|
||||
distz >= -RENDER_DISTANCE && distz < RENDER_DISTANCE){
|
||||
|
||||
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));
|
||||
// reset out-of-vision and unload flags
|
||||
a->second->setState(Chunk::CHUNK_STATE_OUTOFVISION, false);
|
||||
a->second->setState(Chunk::CHUNK_STATE_UNLOADED, false);
|
||||
|
||||
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().push(a->second);
|
||||
}
|
||||
}else{
|
||||
renderer::getChunksToRender().insert(a->second);
|
||||
if(a->second->getState(Chunk::CHUNK_STATE_OUTOFVISION)){
|
||||
// If chunk was already out and enough time has passed
|
||||
if(glfwGetTime() - a->second->unload_timer > UNLOAD_TIMEOUT){
|
||||
// Mark the chunk to be unloaded
|
||||
a->second->setState(Chunk::CHUNK_STATE_UNLOADED, true);
|
||||
}
|
||||
} else{
|
||||
// Mark has out of vision and annotate when it started
|
||||
a->second->setState(Chunk::CHUNK_STATE_OUTOFVISION, true);
|
||||
a->second->setState(Chunk::CHUNK_STATE_UNLOADED, false);
|
||||
a->second->unload_timer = glfwGetTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -191,15 +217,13 @@ namespace chunkmanager
|
|||
|
||||
//std::cout << n->getState(Chunk::CHUNK_STATE_GENERATED) << "\n";
|
||||
if(chunks.erase(index)){
|
||||
//n->deleteBuffers();
|
||||
delete n;
|
||||
nUnloaded++;
|
||||
}else
|
||||
std::cout << "failed to free chunk at" << glm::to_string(n->getPosition()) <<
|
||||
std::endl;
|
||||
}
|
||||
|
||||
debug::window::set_parameter("update_chunks_freed", nUnloaded);
|
||||
}
|
||||
}
|
||||
|
||||
// uint32_t is fine, since i'm limiting the coordinate to only use up to ten bits (1023). There's actually two spare bits
|
||||
|
@ -212,14 +236,11 @@ namespace chunkmanager
|
|||
|
||||
void stop() {
|
||||
should_run=false;
|
||||
update_thread.join();
|
||||
//update_thread.join();
|
||||
gen_thread.join();
|
||||
mesh_thread.join();
|
||||
}
|
||||
void destroy(){
|
||||
for(const auto& n : chunks){
|
||||
delete n.second;
|
||||
}
|
||||
}
|
||||
|
||||
void blockpick(bool place){
|
||||
|
|
|
@ -117,8 +117,6 @@ namespace debug{
|
|||
std::any_cast<int>(parameters.at("update_chunks_total")));
|
||||
ImGui::Text("Chunks freed from memory: %d",
|
||||
std::any_cast<int>(parameters.at("update_chunks_freed")));
|
||||
ImGui::Text("Bucket size: %d",
|
||||
std::any_cast<int>(parameters.at("update_chunks_bucket")));
|
||||
ImGui::Text("Chunks explored: %d",
|
||||
std::any_cast<int>(parameters.at("update_chunks_explored")));
|
||||
}
|
||||
|
|
|
@ -106,6 +106,8 @@ int main()
|
|||
// Render pass
|
||||
renderer::render();
|
||||
|
||||
chunkmanager::primary_thread_update();
|
||||
|
||||
// Swap buffers to avoid tearing
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
|
|
122
src/renderer.cpp
122
src/renderer.cpp
|
@ -15,15 +15,14 @@
|
|||
#include "stb_image_write.h"
|
||||
|
||||
namespace renderer{
|
||||
RenderSet chunks_torender;
|
||||
oneapi::tbb::concurrent_vector<Chunk::Chunk*> render_todelete;
|
||||
RenderQueue chunks_torender;
|
||||
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*> MeshDataQueue;
|
||||
|
||||
Shader* theShader, *quadShader;
|
||||
GLuint chunkTexture;
|
||||
|
||||
Shader* getRenderShader() { return theShader; }
|
||||
RenderSet& getChunksToRender(){ return chunks_torender; }
|
||||
RenderQueue& getChunksToRender(){ return chunks_torender; }
|
||||
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*>& getMeshDataQueue(){ return MeshDataQueue; }
|
||||
|
||||
GLuint renderTexFrameBuffer, renderTex, renderTexDepthBuffer, quadVAO, quadVBO;
|
||||
|
@ -147,102 +146,59 @@ namespace renderer{
|
|||
chunkmesher::getMeshDataQueue().push(m);
|
||||
}
|
||||
|
||||
for(auto& c : chunks_torender){
|
||||
//float dist = glm::distance(c->getPosition(), cameraChunkPos);
|
||||
//if(static_cast<int>(dist) <= RENDER_DISTANCE + 1){
|
||||
int distx = c->getPosition().x - cameraChunkPos.x;
|
||||
int disty = c->getPosition().y - cameraChunkPos.y;
|
||||
int distz = c->getPosition().z - cameraChunkPos.z;
|
||||
if(distx >= -RENDER_DISTANCE && distx < RENDER_DISTANCE &&
|
||||
disty >= -RENDER_DISTANCE && disty < RENDER_DISTANCE &&
|
||||
distz >= -RENDER_DISTANCE && distz < RENDER_DISTANCE){
|
||||
if(!c->getState(Chunk::CHUNK_STATE_MESH_LOADED)) continue;
|
||||
Chunk::Chunk* c;
|
||||
while(chunks_torender.try_pop(c)){
|
||||
if(!c->getState(Chunk::CHUNK_STATE_MESH_LOADED)) continue;
|
||||
|
||||
total++;
|
||||
|
||||
// reset out-of-vision and unload flags
|
||||
c->setState(Chunk::CHUNK_STATE_OUTOFVISION, false);
|
||||
c->setState(Chunk::CHUNK_STATE_UNLOADED, false);
|
||||
if(c->numVertices > 0)
|
||||
{
|
||||
|
||||
if(c->numVertices > 0)
|
||||
{
|
||||
// Increase total vertex count
|
||||
vertices += c->numVertices;
|
||||
|
||||
// Increase total vertex count
|
||||
vertices += c->numVertices;
|
||||
// Perform frustum culling and eventually render
|
||||
glm::vec3 chunk = c->getPosition();
|
||||
glm::vec4 chunkW = glm::vec4(chunk.x*static_cast<float>(CHUNK_SIZE), chunk.y*static_cast<float>(CHUNK_SIZE), chunk.z*static_cast<float>(CHUNK_SIZE),1.0);
|
||||
glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk);
|
||||
|
||||
// Perform frustum culling and eventually render
|
||||
glm::vec3 chunk = c->getPosition();
|
||||
glm::vec4 chunkW = glm::vec4(chunk.x*static_cast<float>(CHUNK_SIZE), chunk.y*static_cast<float>(CHUNK_SIZE), chunk.z*static_cast<float>(CHUNK_SIZE),1.0);
|
||||
glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk);
|
||||
// Check if all the corners of the chunk are outside any of the planes
|
||||
// TODO (?) implement frustum culling as per (Inigo Quilez)[https://iquilezles.org/articles/frustumcorrect/], and check each
|
||||
// plane against each corner of the chunk
|
||||
bool out=false;
|
||||
int a{0};
|
||||
for(int p = 0; p < 6; p++){
|
||||
a = 0;
|
||||
for(int i = 0; i < 8; i++) a += glm::dot(frustumPlanes[p], glm::vec4(chunkW.x + ((float)(i & 1))*CHUNK_SIZE, chunkW.y
|
||||
+ ((float)((i & 2) >> 1))*CHUNK_SIZE, chunkW.z + ((float)((i & 4) >> 2))*CHUNK_SIZE, 1.0)) < 0.0;
|
||||
|
||||
// Check if all the corners of the chunk are outside any of the planes
|
||||
// TODO (?) implement frustum culling as per (Inigo Quilez)[https://iquilezles.org/articles/frustumcorrect/], and check each
|
||||
// plane against each corner of the chunk
|
||||
bool out=false;
|
||||
int a{0};
|
||||
for(int p = 0; p < 6; p++){
|
||||
a = 0;
|
||||
for(int i = 0; i < 8; i++) a += glm::dot(frustumPlanes[p], glm::vec4(chunkW.x + ((float)(i & 1))*CHUNK_SIZE, chunkW.y
|
||||
+ ((float)((i & 2) >> 1))*CHUNK_SIZE, chunkW.z + ((float)((i & 4) >> 2))*CHUNK_SIZE, 1.0)) < 0.0;
|
||||
|
||||
if(a==8){
|
||||
out=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!out)
|
||||
{
|
||||
theShader->setMat4("model", model);
|
||||
theShader->setMat4("view", theCamera.getView());
|
||||
theShader->setMat4("projection", theCamera.getProjection());
|
||||
|
||||
glBindVertexArray(c->VAO);
|
||||
glDrawArrays(GL_POINTS, 0, c->numVertices);
|
||||
glBindVertexArray(0);
|
||||
|
||||
toGpu++;
|
||||
if(a==8){
|
||||
out=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// When the chunk is outside render distance
|
||||
|
||||
/*if(c->getState(Chunk::CHUNK_STATE_OUTOFVISION)){
|
||||
oof++;
|
||||
if(glfwGetTime() - c->unload_timer > UNLOAD_TIMEOUT){
|
||||
// If chunk was already out and enough time has passed
|
||||
// Mark the chunk to be unloaded
|
||||
// And mark is to be removed from the render set
|
||||
render_todelete.push_back(c);
|
||||
}
|
||||
} else{
|
||||
// Mark has out of vision and annotate when it started
|
||||
c->setState(Chunk::CHUNK_STATE_OUTOFVISION, true);
|
||||
c->setState(Chunk::CHUNK_STATE_UNLOADED, false);
|
||||
c->unload_timer = glfwGetTime();
|
||||
}*/
|
||||
c->setState(Chunk::CHUNK_STATE_OUTOFVISION, true);
|
||||
c->setState(Chunk::CHUNK_STATE_UNLOADED, true);
|
||||
//render_todelete.push_back(c);
|
||||
oof++;
|
||||
if (!out)
|
||||
{
|
||||
theShader->setMat4("model", model);
|
||||
theShader->setMat4("view", theCamera.getView());
|
||||
theShader->setMat4("projection", theCamera.getProjection());
|
||||
|
||||
glBindVertexArray(c->VAO);
|
||||
glDrawArrays(GL_POINTS, 0, c->numVertices);
|
||||
glBindVertexArray(0);
|
||||
|
||||
toGpu++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
total = chunks_torender.size();
|
||||
debug::window::set_parameter("render_chunks_total", total);
|
||||
debug::window::set_parameter("render_chunks_rendered", toGpu);
|
||||
debug::window::set_parameter("render_chunks_culled", total-toGpu);
|
||||
debug::window::set_parameter("render_chunks_oof", oof);
|
||||
debug::window::set_parameter("render_chunks_deleted", (int) (render_todelete.size()));
|
||||
debug::window::set_parameter("render_chunks_vertices", vertices);
|
||||
|
||||
/*for(auto& c : render_todelete){
|
||||
// we can get away with unsafe erase as access to the container is only done by this
|
||||
// thread
|
||||
chunks_torender.unsafe_erase(c);
|
||||
c->setState(Chunk::CHUNK_STATE_UNLOADED, true);
|
||||
//c->deleteBuffers();
|
||||
}
|
||||
render_todelete.clear();*/
|
||||
|
||||
/* DISPLAY TEXTURE ON A QUAD THAT FILLS THE SCREEN */
|
||||
// Now to render the quad, with the texture on top
|
||||
// Switch to the default frame buffer
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "oneapi/tbb/concurrent_hash_map.h"
|
||||
#include "oneapi/tbb/tbb_allocator.h"
|
||||
|
||||
typedef oneapi::tbb::concurrent_hash_map<int, int, oneapi::tbb::tbb_allocator<int>> CTable;
|
||||
|
||||
CTable table;
|
||||
void f(){
|
||||
/*while(table.size() > 0){
|
||||
std::cout << "---------------\n";
|
||||
oneapi::tbb::parallel_for(table.range(), [=](Table::range_type &r){
|
||||
for(Table::const_iterator a = r.begin(); a != r.end(); a++){
|
||||
std::cout << a->first << ": " << a->second << std::endl;
|
||||
}
|
||||
});
|
||||
}*/
|
||||
}
|
||||
|
||||
int main(){
|
||||
std::thread t = std::thread(f);
|
||||
|
||||
//Table::accessor a;
|
||||
/*table.emplace(a, std::make_pair(0, "zero"));
|
||||
table.emplace(a, std::make_pair(1, "one"));
|
||||
table.emplace(a, std::make_pair(2, "two"));
|
||||
table.emplace(a, std::make_pair(3, "three"));
|
||||
table.emplace(a, std::make_pair(4, "four"));
|
||||
table.emplace(a, std::make_pair(5, "five"));*/
|
||||
|
||||
t.join();
|
||||
}
|
Loading…
Reference in New Issue