diff options
author | Jon Bergli Heier <snakebite@jvnv.net> | 2011-04-04 00:01:39 +0200 |
---|---|---|
committer | Jon Bergli Heier <snakebite@jvnv.net> | 2011-04-04 00:01:39 +0200 |
commit | 095be9811eaccd92cee156b4c486fb92b77cdcd2 (patch) | |
tree | 354d6f28f0efd721748c0e052921b443ee86bd79 | |
parent | 61fe986e9ad6d1f26275e2ffd72cae0c2542256c (diff) |
Threaded VBO creation.
A secondary memory-mapped VBO is filled in a separate thread, which
replaces the main VBO when work is done.
-rw-r--r-- | SConstruct | 2 | ||||
-rw-r--r-- | main.cpp | 14 | ||||
-rw-r--r-- | quadtree.cpp | 159 | ||||
-rw-r--r-- | quadtree.h | 17 | ||||
-rw-r--r-- | scene.cpp | 1 |
5 files changed, 135 insertions, 58 deletions
@@ -8,7 +8,7 @@ AddOption('--release', action = 'store_true') AddOption('--profiling', action = 'store_true') env.Append(CPPPATH = ['.']) -env.Append(LIBS = ['GL', 'GLU']) +env.Append(LIBS = ['GL', 'GLU', 'boost_thread']) env.ParseConfig('sdl-config --cflags --libs') env.ParseConfig('pkg-config --cflags --libs SDL_image') env.ParseConfig('pkg-config --cflags --libs ftgl') @@ -76,24 +76,14 @@ int main(int argc, char **argv) { bool gravity = true; SDL_WarpMouse(video::width/2, video::height/2); unsigned int last_time = SDL_GetTicks(); - unsigned int last_update = SDL_GetTicks(); - /*boost::timer t; - double last_time = 0;*/ Vector3 selected; Quadtree::QuadNode *node; Quadtree::QuadNode *last_node = NULL; scene.update(); while(running) { unsigned int time = SDL_GetTicks(); - //double time = t.elapsed(); - //t.restart(); unsigned int steps = time - last_time + 1; - //double steps = (time - last_time) * 1000; last_time = time; - /*if(time - last_update > 5000) { - scene.update(); - last_update = time; - }*/ bool do_select = 0; int sx, sy; while(SDL_PollEvent(&event)) { @@ -297,8 +287,8 @@ int main(int argc, char **argv) { float height = font->LineHeight(); glColor3f(1, 1, 1); glTranslatef(0, video::height-height, 0); - font->Render((boost::format("%dx%d %d levels %d nodes tree creation time: %f steps: %d") - % scene.qt->width % scene.qt->height % scene.qt->levels % scene.qt->nodes % scene.qt->init_time % steps).str().c_str()); + font->Render((boost::format("%dx%d %d levels %d nodes tree creation time: %f steps: %d update: %d") + % scene.qt->width % scene.qt->height % scene.qt->levels % scene.qt->nodes % scene.qt->init_time % steps % scene.qt->thread_running).str().c_str()); //glTranslatef(0, height, 0); //font->Render((boost::format("selected: %x") % selected).str().c_str()); glTranslatef(0, -height, 0); diff --git a/quadtree.cpp b/quadtree.cpp index 782837c..7fdf24f 100644 --- a/quadtree.cpp +++ b/quadtree.cpp @@ -19,6 +19,8 @@ Quadtree::Quadtree(int width, int height, float *heightmap, int levels) { vbo_object = 0; root = NULL; heights = heightmap; + thread_done = thread_running = false; + thread_buffer = NULL; create_nodes(levels); } @@ -310,6 +312,16 @@ Vector3 Quadtree::QuadNode::get_normal(int index) { } void Quadtree::update(float x, float z) { + if(!node_lock.try_lock()) { + return; + } + + /* + * Lock won't be held until this function calls make_vbo(), + * which creates the update thread. + */ + node_lock.unlock(); + bool changed = false; std::queue<QuadNode*> q; @@ -406,24 +418,25 @@ unsigned int Quadtree::count_nodes() { return count; } -void Quadtree::make_vbo() { - nodes = count_nodes(); - if(vbo_object) - glDeleteBuffers(1, &vbo_object); - glGenBuffers(1, &vbo_object); - glBindBuffer(GL_ARRAY_BUFFER, vbo_object); - const size_t vertex_chunk_size = sizeof(float)*3*12; +Quadtree::UpdateThread::UpdateThread(Quadtree *t, float *b) { + tree = t; + buffer = b; +} + +void Quadtree::UpdateThread::operator()() { + tree->vbo_lock.lock(); + tree->node_lock.lock(); + + unsigned int nodes = tree->nodes; + const size_t vertex_chunk_size = 3*12; const size_t vertices_size = vertex_chunk_size*nodes; const size_t normal_chunk_size = vertex_chunk_size; const size_t normals_size = normal_chunk_size*nodes; - const size_t tex_coord_chunk_size = sizeof(float)*2*12; - const size_t tex_coords_size = tex_coord_chunk_size*nodes; - - glBufferData(GL_ARRAY_BUFFER, vertices_size + normals_size + tex_coords_size, NULL, GL_DYNAMIC_DRAW); + const size_t tex_coord_chunk_size = 2*12; + //const size_t tex_coords_size = tex_coord_chunk_size*nodes; std::queue<Quadtree::QuadNode*> q; - q.push(root); - vertices = nodes*12; + q.push(tree->root); unsigned int index = 0; while(!q.empty()) { Quadtree::QuadNode* node = q.front(); @@ -433,11 +446,6 @@ void Quadtree::make_vbo() { q.push(node->children[j]); continue; } - float v[3*12]; - float n[3*12]; - v[0] = node->vertex_array[0]; - v[1] = node->vertex_array[1]; - v[2] = node->vertex_array[2]; float tex_coords[4][3][2] = { {{.5, .5}, {0, 0}, {0, 1}}, {{.5, .5}, {0, 1}, {1, 1}}, @@ -445,11 +453,17 @@ void Quadtree::make_vbo() { {{.5, .5}, {1, 0}, {0, 0}} }; for(int i = 0; i < 4; i++) { + float *v = buffer + vertex_chunk_size*index + 3*3*i; for(int j = 0; j < 3; j++) { - tex_coords[i][j][0] *= node->width; - tex_coords[i][j][1] *= node->height; + float *tc = buffer + vertices_size + normals_size + tex_coord_chunk_size*index + 6*i + 2*j; + tc[0] = tex_coords[i][j][0]*node->width; + tc[1] = tex_coords[i][j][1]*node->height; } + v[0] = node->vertex_array[0]; + v[1] = node->vertex_array[1]; + v[2] = node->vertex_array[2]; + v[3] = node->vertex_array[i*3+3]; v[4] = node->vertex_array[i*3+4]; v[5] = node->vertex_array[i*3+5]; @@ -457,15 +471,16 @@ void Quadtree::make_vbo() { v[6] = node->vertex_array[i == 3 ? 3 : (i*3+6)]; v[7] = node->vertex_array[i == 3 ? 4 : (i*3+7)]; v[8] = node->vertex_array[i == 3 ? 5 : (i*3+8)]; - glBufferSubData(GL_ARRAY_BUFFER, vertex_chunk_size*index + sizeof(float)*3*3*i, sizeof(float)*3*3, v); } + float *n = buffer + vertices_size + normal_chunk_size*index; + /* interpolate normals per vertex between nodes */ - QuadNode *left = get_left(node); - QuadNode *right = get_right(node); - QuadNode *up = get_up(node); - QuadNode *down = get_down(node); + QuadNode *left = tree->get_left(node); + QuadNode *right = tree->get_right(node); + QuadNode *up = tree->get_up(node); + QuadNode *down = tree->get_down(node); // midpoint { @@ -488,10 +503,10 @@ void Quadtree::make_vbo() { v += down->get_normal(2); } if(left && down) { - QuadNode *n = get_left(down); - if(n) { - v += n->get_normal(0); - v += n->get_normal(1); + QuadNode *temp = tree->get_left(down); + if(temp) { + v += temp->get_normal(0); + v += temp->get_normal(1); } } v /= v.length(); @@ -512,10 +527,10 @@ void Quadtree::make_vbo() { v += down->get_normal(0); } if(down && right) { - QuadNode *n = get_down(right); - if(n) { - v += n->get_normal(1); - v += n->get_normal(2); + QuadNode *temp = tree->get_down(right); + if(temp) { + v += temp->get_normal(1); + v += temp->get_normal(2); } } v /= v.length(); @@ -536,10 +551,10 @@ void Quadtree::make_vbo() { v += up->get_normal(3); } if(up && right) { - QuadNode *n = get_right(up); - if(n) { - v += n->get_normal(2); - v += n->get_normal(3); + QuadNode *temp = tree->get_right(up); + if(temp) { + v += temp->get_normal(2); + v += temp->get_normal(3); } } v /= v.length(); @@ -560,10 +575,10 @@ void Quadtree::make_vbo() { v += left->get_normal(1); } if(left && up) { - QuadNode *n = get_left(up); - if(n) { - v += n->get_normal(0); - v += n->get_normal(3); + QuadNode *temp = tree->get_left(up); + if(temp) { + v += temp->get_normal(0); + v += temp->get_normal(3); } } v /= v.length(); @@ -572,11 +587,66 @@ void Quadtree::make_vbo() { n[17] = n[23] = v.z; } - glBufferSubData(GL_ARRAY_BUFFER, vertices_size + normal_chunk_size*index, normal_chunk_size, n); - - glBufferSubData(GL_ARRAY_BUFFER, vertices_size + normals_size + tex_coord_chunk_size*index, tex_coord_chunk_size, tex_coords); index++; } + + tree->thread_done = true; + tree->thread_running = false; + + tree->node_lock.unlock(); + tree->vbo_lock.unlock(); +} + +void Quadtree::make_vbo() { + if(thread_running || thread_done || thread_buffer) + return; + + nodes = count_nodes(); + glGenBuffers(1, &temp_vbo); + glBindBuffer(GL_ARRAY_BUFFER, temp_vbo); + + const size_t vertex_chunk_size = sizeof(float)*3*12; + const size_t vertices_size = vertex_chunk_size*nodes; + const size_t normal_chunk_size = vertex_chunk_size; + const size_t normals_size = normal_chunk_size*nodes; + const size_t tex_coord_chunk_size = sizeof(float)*2*12; + const size_t tex_coords_size = tex_coord_chunk_size*nodes; + + buf_size = sizeof(float)*(vertices_size + normals_size + tex_coords_size); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*(vertices_size + normals_size + tex_coords_size), NULL, GL_STATIC_DRAW); + + thread_buffer = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + + thread_running = true; + boost::thread(UpdateThread(this, thread_buffer)); +} + +void Quadtree::update_vbo() { + if(!vbo_lock.try_lock()) { + return; + } + + if(!thread_done || !thread_buffer || thread_running) { + vbo_lock.unlock(); + return; + } + + thread_done = false; + + glBindBuffer(GL_ARRAY_BUFFER, temp_vbo); + glBufferData(GL_ARRAY_BUFFER, buf_size, thread_buffer, GL_STATIC_DRAW); + + thread_buffer = NULL; + + vertices = nodes*12; + + if(vbo_object) + glDeleteBuffers(1, &vbo_object); + vbo_object = temp_vbo; + temp_vbo = 0; + + vbo_lock.unlock(); } Quadtree::QuadNode* Quadtree::find(float x, float y, int level) { @@ -624,4 +694,3 @@ Quadtree::QuadNode *Quadtree::get_down(Quadtree::QuadNode *node) { return NULL; return n; } - @@ -3,8 +3,18 @@ #include "vector.h" +#include <boost/thread.hpp> + class Quadtree { public: + + struct UpdateThread { + Quadtree *tree; + float *buffer; + UpdateThread(Quadtree *t, float *b); + void operator()(); + }; + struct QuadNode { Quadtree *tree; QuadNode *parent; @@ -29,9 +39,15 @@ class Quadtree { }; float *heights; + float *thread_buffer; + size_t buf_size; + bool thread_done, thread_running; + boost::mutex vbo_lock; + boost::mutex node_lock; int width, height, levels; float init_time; QuadNode *root; + unsigned int temp_vbo; unsigned int vbo_object; unsigned int nodes; unsigned int vertices; @@ -43,6 +59,7 @@ class Quadtree { void create_nodes(int levels); unsigned int count_nodes(); void make_vbo(); + void update_vbo(); QuadNode *find(float x, float y, int level = -1); QuadNode *get_left(QuadNode *node); QuadNode *get_right(QuadNode *node); @@ -92,4 +92,5 @@ bool Scene::select(int x, int y, float& px, float& py, float& pz) { void Scene::update() { qt->update(pos.x, pos.z); + qt->update_vbo(); } |