GPU: Make changes to GPUIndexBuf and GPUVertBuf to allow multithreading

This is a small change. We delay all gl calls at the first use of the
GPUIndexBuf / GPUVertBuf in order to be able to create multiple buffers
from different threads without having many gl contexts.
This commit is contained in:
Clément Foucault 2018-12-08 18:15:57 +01:00
parent a99eb0ca68
commit 33cc3344a2
3 changed files with 27 additions and 16 deletions

View File

@ -54,6 +54,7 @@ typedef struct GPUIndexBuf {
uint base_index;
#endif
uint32_t ibo_id; /* 0 indicates not yet sent to VRAM */
void *data; /* non-NULL indicates not yet sent to VRAM */
bool use_prim_restart;
} GPUIndexBuf;

View File

@ -260,6 +260,7 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
#endif
elem->index_len = builder->index_len;
elem->use_prim_restart = builder->use_prim_restart;
elem->ibo_id = 0; /* Created at first use. */
#if GPU_TRACK_INDEX_RANGE
uint range = index_range(builder->data, builder->index_len, &elem->min_index, &elem->max_index);
@ -284,25 +285,31 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
elem->gl_index_type = convert_index_type_to_gl(elem->index_type);
#endif
if (elem->ibo_id == 0) {
elem->ibo_id = GPU_buf_alloc();
}
/* send data to GPU */
/* GL_ELEMENT_ARRAY_BUFFER changes the state of the last VAO bound,
* so we use the GL_ARRAY_BUFFER here to create a buffer without
* interfering in the VAO state. */
glBindBuffer(GL_ARRAY_BUFFER, elem->ibo_id);
glBufferData(GL_ARRAY_BUFFER, GPU_indexbuf_size_get(elem), builder->data, GL_STATIC_DRAW);
/* discard builder (one-time use) */
MEM_freeN(builder->data);
/* Transfer data ownership to GPUIndexBuf.
* It will be uploaded upon first use. */
elem->data = builder->data;
builder->data = NULL;
/* other fields are safe to leave */
}
static void indexbuf_upload_data(GPUIndexBuf *elem)
{
/* send data to GPU */
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GPU_indexbuf_size_get(elem), elem->data, GL_STATIC_DRAW);
/* No need to keep copy of data in system memory. */
MEM_freeN(elem->data);
elem->data = NULL;
}
void GPU_indexbuf_use(GPUIndexBuf *elem)
{
if (elem->ibo_id == 0) {
elem->ibo_id = GPU_buf_alloc();
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->ibo_id);
if (elem->data != NULL) {
indexbuf_upload_data(elem);
}
}
void GPU_indexbuf_discard(GPUIndexBuf *elem)
@ -310,5 +317,8 @@ void GPU_indexbuf_discard(GPUIndexBuf *elem)
if (elem->ibo_id) {
GPU_buf_free(elem->ibo_id);
}
if (elem->data) {
MEM_freeN(elem->data);
}
MEM_freeN(elem);
}

View File

@ -119,10 +119,6 @@ void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len)
/* catch any unnecessary use */
assert(verts->vertex_alloc != v_len || verts->data == NULL);
#endif
/* only create the buffer the 1st time */
if (verts->vbo_id == 0) {
verts->vbo_id = GPU_buf_alloc();
}
/* discard previous data if any */
if (verts->data) {
MEM_freeN(verts->data);
@ -260,6 +256,10 @@ static void VertBuffer_upload_data(GPUVertBuf *verts)
void GPU_vertbuf_use(GPUVertBuf *verts)
{
/* only create the buffer the 1st time */
if (verts->vbo_id == 0) {
verts->vbo_id = GPU_buf_alloc();
}
glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
if (verts->dirty) {
VertBuffer_upload_data(verts);