diff options
-rw-r--r-- | intern/gawain/gawain/gwn_vertex_buffer.h | 8 | ||||
-rw-r--r-- | intern/gawain/src/gwn_vertex_buffer.c | 137 |
2 files changed, 65 insertions, 80 deletions
diff --git a/intern/gawain/gawain/gwn_vertex_buffer.h b/intern/gawain/gawain/gwn_vertex_buffer.h index d9faae4f55f..ddb77368a02 100644 --- a/intern/gawain/gawain/gwn_vertex_buffer.h +++ b/intern/gawain/gawain/gwn_vertex_buffer.h @@ -25,13 +25,14 @@ typedef enum { // can be extended to support more types GWN_USAGE_STREAM, - GWN_USAGE_STATIC, + GWN_USAGE_STATIC, // do not keep data in memory GWN_USAGE_DYNAMIC } Gwn_UsageType; typedef struct Gwn_VertBuf { Gwn_VertFormat format; unsigned vertex_ct; + bool dirty; GLubyte* data; // NULL indicates data in VRAM (unmapped) GLuint vbo_id; // 0 indicates not yet allocated Gwn_UsageType usage; // usage hint for GL optimisation @@ -53,10 +54,7 @@ void GWN_vertbuf_init_with_format_ex(Gwn_VertBuf*, const Gwn_VertFormat*, Gwn_Us unsigned GWN_vertbuf_size_get(const Gwn_VertBuf*); void GWN_vertbuf_data_alloc(Gwn_VertBuf*, unsigned v_ct); -void GWN_vertbuf_data_resize_ex(Gwn_VertBuf*, unsigned v_ct, bool keep_data); - -#define GWN_vertbuf_data_resize(verts, v_ct) \ - GWN_vertbuf_data_resize_ex(verts, v_ct, true) +void GWN_vertbuf_data_resize(Gwn_VertBuf*, unsigned v_ct); // The most important set_attrib variant is the untyped one. Get it right first. // It takes a void* so the app developer is responsible for matching their app data types diff --git a/intern/gawain/src/gwn_vertex_buffer.c b/intern/gawain/src/gwn_vertex_buffer.c index 17c2a3e9364..39fc1885b92 100644 --- a/intern/gawain/src/gwn_vertex_buffer.c +++ b/intern/gawain/src/gwn_vertex_buffer.c @@ -52,6 +52,7 @@ void GWN_vertbuf_init(Gwn_VertBuf* verts, Gwn_UsageType usage) { memset(verts, 0, sizeof(Gwn_VertBuf)); verts->usage = usage; + verts->dirty = true; } void GWN_vertbuf_init_with_format_ex(Gwn_VertBuf* verts, const Gwn_VertFormat* format, Gwn_UsageType usage) @@ -72,6 +73,9 @@ void GWN_vertbuf_discard(Gwn_VertBuf* verts) #endif } + if (verts->data) + free(verts->data); + free(verts); } @@ -80,90 +84,58 @@ unsigned GWN_vertbuf_size_get(const Gwn_VertBuf* verts) return vertex_buffer_size(&verts->format, verts->vertex_ct); } +// create a new allocation, discarding any existing data void GWN_vertbuf_data_alloc(Gwn_VertBuf* verts, unsigned v_ct) { Gwn_VertFormat* format = &verts->format; if (!format->packed) VertexFormat_pack(format); - verts->vertex_ct = v_ct; - #if TRUST_NO_ONE - assert(verts->vbo_id == 0); + // catch any unnecessary use + assert(verts->vertex_ct != v_ct || verts->data == NULL); #endif - unsigned buffer_sz = GWN_vertbuf_size_get(verts); + // only create the buffer the 1st time + if (verts->vbo_id == 0) + verts->vbo_id = GWN_buf_id_alloc(); + + // discard previous data if any + if (verts->data) + free(verts->data); + #if VRAM_USAGE - vbo_memory_usage += buffer_sz; + vbo_memory_usage -= GWN_vertbuf_size_get(verts); #endif - // create an array buffer and map it to memory - verts->vbo_id = GWN_buf_id_alloc(); - glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); - glBufferData(GL_ARRAY_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage)); - verts->data = glMapBufferRange(GL_ARRAY_BUFFER, 0, buffer_sz, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + verts->dirty = true; + verts->vertex_ct = v_ct; + verts->data = malloc(sizeof(GLubyte) * GWN_vertbuf_size_get(verts)); + +#if VRAM_USAGE + vbo_memory_usage += GWN_vertbuf_size_get(verts); +#endif } -void GWN_vertbuf_data_resize_ex(Gwn_VertBuf* verts, unsigned v_ct, bool keep_data) +// resize buffer keeping existing data +void GWN_vertbuf_data_resize(Gwn_VertBuf* verts, unsigned v_ct) { #if TRUST_NO_ONE - assert(verts->vbo_id != 0); + assert(verts->data != NULL); + assert(verts->vertex_ct != v_ct); #endif - if (verts->vertex_ct == v_ct) - return; - - unsigned old_buf_sz = GWN_vertbuf_size_get(verts); - verts->vertex_ct = v_ct; - unsigned new_buf_sz = GWN_vertbuf_size_get(verts); #if VRAM_USAGE - vbo_memory_usage += new_buf_sz - old_buf_sz; + vbo_memory_usage -= GWN_vertbuf_size_get(verts); #endif - if (keep_data) - { - // we need to do a copy to keep the existing data - GLuint vbo_tmp; - glGenBuffers(1, &vbo_tmp); - // only copy the data that can fit in the new buffer - unsigned copy_sz = (old_buf_sz < new_buf_sz) ? old_buf_sz : new_buf_sz; - glBindBuffer(GL_COPY_WRITE_BUFFER, vbo_tmp); - glBufferData(GL_COPY_WRITE_BUFFER, copy_sz, NULL, GL_STREAM_COPY); - - glBindBuffer(GL_COPY_READ_BUFFER, verts->vbo_id); - // we cannot copy from/to a mapped buffer - if (verts->data) - glUnmapBuffer(GL_COPY_READ_BUFFER); - - // save data, resize the buffer, restore data - glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, copy_sz); - glBufferData(GL_COPY_READ_BUFFER, new_buf_sz, NULL, convert_usage_type_to_gl(verts->usage)); - glCopyBufferSubData(GL_COPY_WRITE_BUFFER, GL_COPY_READ_BUFFER, 0, 0, copy_sz); - - glDeleteBuffers(1, &vbo_tmp); - } - else - { - glBindBuffer(GL_COPY_READ_BUFFER, verts->vbo_id); - glBufferData(GL_COPY_READ_BUFFER, new_buf_sz, NULL, convert_usage_type_to_gl(verts->usage)); - } - - // if the buffer was mapped, update it's pointer - if (verts->data) - verts->data = glMapBufferRange(GL_COPY_READ_BUFFER, 0, new_buf_sz, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); - } - -static void VertexBuffer_map(Gwn_VertBuf* verts) - { - glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); - verts->data = glMapBufferRange(GL_ARRAY_BUFFER, 0, GWN_vertbuf_size_get(verts), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); - } + verts->dirty = true; + verts->vertex_ct = v_ct; + verts->data = realloc(verts->data, sizeof(GLubyte) * GWN_vertbuf_size_get(verts)); -static void VertexBuffer_unmap(Gwn_VertBuf* verts) - { - glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); - glUnmapBuffer(GL_ARRAY_BUFFER); - verts->data = NULL; +#if VRAM_USAGE + vbo_memory_usage += GWN_vertbuf_size_get(verts); +#endif } void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, unsigned a_idx, unsigned v_idx, const void* data) @@ -174,11 +146,10 @@ void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, unsigned a_idx, unsigned v_idx, co #if TRUST_NO_ONE assert(a_idx < format->attrib_ct); assert(v_idx < verts->vertex_ct); + assert(verts->data != NULL); #endif - if (verts->data == NULL) - VertexBuffer_map(verts); - + verts->dirty = true; memcpy((GLubyte*)verts->data + a->offset + v_idx * format->stride, data, a->sz); } @@ -203,13 +174,12 @@ void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf* verts, unsigned a_idx, unsigned s #if TRUST_NO_ONE assert(a_idx < format->attrib_ct); + assert(verts->data != NULL); #endif + verts->dirty = true; const unsigned vertex_ct = verts->vertex_ct; - if (verts->data == NULL) - VertexBuffer_map(verts); - if (format->attrib_ct == 1 && stride == format->stride) { // we can copy it all at once @@ -230,10 +200,10 @@ void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, unsigned a_idx, Gwn_VertB #if TRUST_NO_ONE assert(a_idx < format->attrib_ct); + assert(verts->data != NULL); #endif - if (verts->data == NULL) - VertexBuffer_map(verts); + verts->dirty = true; access->size = a->sz; access->stride = format->stride; @@ -244,13 +214,30 @@ void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, unsigned a_idx, Gwn_VertB #endif } +static void VertBuffer_upload_data(Gwn_VertBuf* verts) + { + unsigned buffer_sz = GWN_vertbuf_size_get(verts); + + // orphan the vbo to avoid sync + glBufferData(GL_ARRAY_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage)); + // upload data + glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data); + + if (verts->usage == GWN_USAGE_STATIC) + { + free(verts->data); + verts->data = NULL; + } + + verts->dirty = false; + } + void GWN_vertbuf_use(Gwn_VertBuf* verts) { - if (verts->data) - // this also calls glBindBuffer - VertexBuffer_unmap(verts); - else - glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + + if (verts->dirty) + VertBuffer_upload_data(verts); } unsigned GWN_vertbuf_get_memory_usage(void) |