From 095be9811eaccd92cee156b4c486fb92b77cdcd2 Mon Sep 17 00:00:00 2001 From: Jon Bergli Heier Date: Mon, 4 Apr 2011 00:01:39 +0200 Subject: Threaded VBO creation. A secondary memory-mapped VBO is filled in a separate thread, which replaces the main VBO when work is done. --- quadtree.cpp | 159 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 114 insertions(+), 45 deletions(-) (limited to 'quadtree.cpp') 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 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 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; } - -- cgit v1.2.3