diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-02-14 19:59:48 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-02-14 20:59:42 +0300 |
commit | ab7e7a005bde711d14493d51ee26ea297fa99e47 (patch) | |
tree | 8ba24ec2fa94bf443df481f3ec5e3e769dc7f83c | |
parent | 1e9ef2a25e08462a020de3897bc3b68a782c4120 (diff) |
GWN: Add new dynamic type of batches and remove
Theses batches keeps their memory chuck allocated after transfer to be reused and updated very often.
NOTE: This commit break instancing in DRW. (it's fixed in the next commit)
-rw-r--r-- | intern/gawain/gawain/gwn_vertex_buffer.h | 13 | ||||
-rw-r--r-- | intern/gawain/src/gwn_vertex_buffer.c | 97 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 8 |
3 files changed, 73 insertions, 45 deletions
diff --git a/intern/gawain/gawain/gwn_vertex_buffer.h b/intern/gawain/gawain/gwn_vertex_buffer.h index 50a4e1aa2f6..34f12754f40 100644 --- a/intern/gawain/gawain/gwn_vertex_buffer.h +++ b/intern/gawain/gawain/gwn_vertex_buffer.h @@ -13,6 +13,7 @@ #include "gwn_vertex_format.h" +#define VRAM_USAGE 1 // How to create a Gwn_VertBuf: // 1) verts = GWN_vertbuf_create() or GWN_vertbuf_init(verts) // 2) GWN_vertformat_attr_add(verts->format, ...) @@ -24,15 +25,22 @@ typedef struct Gwn_VertBuf { Gwn_VertFormat format; unsigned vertex_ct; - bool own_data; // does gawain own the data an is able to free it + unsigned alloc_ct; // size in vertex of alloced data +#if VRAM_USAGE + unsigned vram_size; // size in byte of data present in the VRAM +#endif + unsigned data_dirty : 1; // does the data has been touched since last transfert + unsigned data_dynamic : 1; // do we keep the RAM allocation for further updates? + unsigned data_resized : 1; // does the data has been resized since last transfert GLubyte* data; // NULL indicates data in VRAM (unmapped) or not yet allocated GLuint vbo_id; // 0 indicates not yet sent to VRAM } Gwn_VertBuf; Gwn_VertBuf* GWN_vertbuf_create(void); Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat*); +Gwn_VertBuf* GWN_vertbuf_create_dynamic_with_format(const Gwn_VertFormat*); -void GWN_vertbuf_clear(Gwn_VertBuf* verts); +void GWN_vertbuf_clear(Gwn_VertBuf*); void GWN_vertbuf_discard(Gwn_VertBuf*); void GWN_vertbuf_init(Gwn_VertBuf*); @@ -40,7 +48,6 @@ void GWN_vertbuf_init_with_format(Gwn_VertBuf*, const Gwn_VertFormat*); unsigned GWN_vertbuf_size_get(const Gwn_VertBuf*); void GWN_vertbuf_data_alloc(Gwn_VertBuf*, unsigned v_ct); -void GWN_vertbuf_data_set(Gwn_VertBuf*, unsigned v_ct, void* data, bool pass_ownership); void GWN_vertbuf_data_resize(Gwn_VertBuf*, unsigned v_ct); // The most important set_attrib variant is the untyped one. Get it right first. diff --git a/intern/gawain/src/gwn_vertex_buffer.c b/intern/gawain/src/gwn_vertex_buffer.c index 2bab0bc378b..32bef765390 100644 --- a/intern/gawain/src/gwn_vertex_buffer.c +++ b/intern/gawain/src/gwn_vertex_buffer.c @@ -38,6 +38,13 @@ Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat* format) // TODO: implement those memory savings } +Gwn_VertBuf* GWN_vertbuf_create_dynamic_with_format(const Gwn_VertFormat* format) + { + Gwn_VertBuf* verts = GWN_vertbuf_create_with_format(format); + verts->data_dynamic = true; + return verts; + } + void GWN_vertbuf_init(Gwn_VertBuf* verts) { memset(verts, 0, sizeof(Gwn_VertBuf)); @@ -58,12 +65,12 @@ void GWN_vertbuf_clear(Gwn_VertBuf* verts) { if (verts->vbo_id) { GWN_buf_id_free(verts->vbo_id); - vbo_memory_usage -= GWN_vertbuf_size_get(verts); - } -#if KEEP_SINGLE_COPY - else +#if VRAM_USAGE + vbo_memory_usage -= verts->vram_size; #endif - if (verts->data && verts->own_data) + } + + if (verts->data) { free(verts->data); verts->data = NULL; @@ -75,12 +82,12 @@ void GWN_vertbuf_discard(Gwn_VertBuf* verts) if (verts->vbo_id) { GWN_buf_id_free(verts->vbo_id); - vbo_memory_usage -= GWN_vertbuf_size_get(verts); - } -#if KEEP_SINGLE_COPY - else +#if VRAM_USAGE + vbo_memory_usage -= verts->vram_size; #endif - if (verts->data && verts->own_data) + } + + if (verts->data) { free(verts->data); } @@ -101,33 +108,22 @@ void GWN_vertbuf_data_alloc(Gwn_VertBuf* verts, unsigned v_ct) VertexFormat_pack(format); verts->vertex_ct = v_ct; - verts->own_data = true; // Data initially lives in main memory. Will be transferred to VRAM when we "prime" it. verts->data = malloc(GWN_vertbuf_size_get(verts)); } -void GWN_vertbuf_data_set(Gwn_VertBuf* verts, unsigned v_ct, void* data, bool pass_ownership) - { - Gwn_VertFormat* format = &verts->format; - if (!format->packed) - VertexFormat_pack(format); - - verts->vertex_ct = v_ct; - verts->own_data = pass_ownership; - - // Data initially lives in main memory. Will be transferred to VRAM when we "prime" it. - verts->data = data; - } - void GWN_vertbuf_data_resize(Gwn_VertBuf* verts, unsigned v_ct) { #if TRUST_NO_ONE assert(verts->vertex_ct != v_ct); // allow this? assert(verts->data != NULL); // has already been allocated - assert(verts->vbo_id == 0); // has not been sent to VRAM + assert(verts->vbo_id == 0 || verts->data_dynamic); // has not been sent to VRAM #endif + // for dynamic buffers + verts->data_resized = true; + verts->vertex_ct = v_ct; verts->data = realloc(verts->data, GWN_vertbuf_size_get(verts)); // TODO: skip realloc if v_ct < existing vertex count @@ -139,6 +135,8 @@ void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, unsigned a_idx, unsigned v_idx, co const Gwn_VertFormat* format = &verts->format; const Gwn_VertAttr* a = format->attribs + a_idx; + verts->data_dirty = true; + #if TRUST_NO_ONE assert(a_idx < format->attrib_ct); assert(v_idx < verts->vertex_ct); @@ -153,6 +151,8 @@ void GWN_vertbuf_attr_fill(Gwn_VertBuf* verts, unsigned a_idx, const void* data) const Gwn_VertFormat* format = &verts->format; const Gwn_VertAttr* a = format->attribs + a_idx; + verts->data_dirty = true; + #if TRUST_NO_ONE assert(a_idx < format->attrib_ct); #endif @@ -167,6 +167,8 @@ void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf* verts, unsigned a_idx, unsigned s const Gwn_VertFormat* format = &verts->format; const Gwn_VertAttr* a = format->attribs + a_idx; + verts->data_dirty = true; + #if TRUST_NO_ONE assert(a_idx < format->attrib_ct); assert(verts->data != NULL); // data must be in main mem @@ -209,31 +211,58 @@ void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, unsigned a_idx, Gwn_VertB static void VertexBuffer_prime(Gwn_VertBuf* verts) { - const unsigned buffer_sz = GWN_vertbuf_size_get(verts); + unsigned buffer_sz = GWN_vertbuf_size_get(verts); + +#if VRAM_USAGE + vbo_memory_usage += buffer_sz; + verts->vram_size = buffer_sz; +#endif verts->vbo_id = GWN_buf_id_alloc(); glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); // fill with delicious data & send to GPU the first time only - glBufferData(GL_ARRAY_BUFFER, buffer_sz, verts->data, GL_STATIC_DRAW); - - vbo_memory_usage += buffer_sz; + glBufferData(GL_ARRAY_BUFFER, verts->vram_size, verts->data, (verts->data_dynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); -#if KEEP_SINGLE_COPY // now that GL has a copy, discard original - if (verts->own_data) + if (!verts->data_dynamic) { free(verts->data); verts->data = NULL; } + + verts->data_dirty = false; + } + +static void VertexBuffer_update(Gwn_VertBuf* verts) + { + unsigned buffer_sz = GWN_vertbuf_size_get(verts); + +#if VRAM_USAGE + vbo_memory_usage -= verts->vram_size; + vbo_memory_usage += buffer_sz; + verts->vram_size = buffer_sz; #endif + + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + + // fill with delicious data & send to GPU ... AGAIN + if (verts->data_resized) + glBufferData(GL_ARRAY_BUFFER, buffer_sz, verts->data, GL_DYNAMIC_DRAW); + else + glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data); // .. todo try glMapBuffer + + verts->data_dirty = false; + verts->data_resized = false; } void GWN_vertbuf_use(Gwn_VertBuf* verts) { - if (verts->vbo_id) - glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); - else + if (!verts->vbo_id) VertexBuffer_prime(verts); + else if (verts->data_dirty) + VertexBuffer_update(verts); + else + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); } unsigned GWN_vertbuf_get_memory_usage(void) diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index db1046039d5..6feab32f8e1 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1188,13 +1188,9 @@ static void shgroup_dynamic_batch(DRWShadingGroup *shgroup) /* Upload Data */ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&interface->vbo_format); - if (interface->inst_data) { - GWN_vertbuf_data_set(vbo, nbr, DRW_instance_data_get(interface->inst_data), false); - } else { /* Use unitialized memory. This is for dummy vertex buffers. */ /* XXX TODO do not alloc at all. */ GWN_vertbuf_data_alloc(vbo, nbr); - } /* TODO make the batch dynamic instead of freeing it every times */ if (shgroup->batch_geom) @@ -1218,13 +1214,9 @@ static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) /* Upload Data */ Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&interface->vbo_format); - if (interface->inst_data) { - GWN_vertbuf_data_set(vbo, nbr, DRW_instance_data_get(interface->inst_data), false); - } else { /* Use unitialized memory. This is for dummy vertex buffers. */ /* XXX TODO do not alloc at all. */ GWN_vertbuf_data_alloc(vbo, nbr); - } /* TODO make the batch dynamic instead of freeing it every times */ if (shgroup->instancing_geom) |