GPU: Make changes to GPUIndexBuf and GPUVertBuf to allow multithreading
authorClément Foucault <foucault.clem@gmail.com>
Sat, 8 Dec 2018 17:15:57 +0000 (18:15 +0100)
committerClément Foucault <foucault.clem@gmail.com>
Mon, 10 Dec 2018 18:02:17 +0000 (19:02 +0100)
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.

source/blender/gpu/GPU_element.h
source/blender/gpu/intern/gpu_element.c
source/blender/gpu/intern/gpu_vertex_buffer.c

index c16a3d8b4a1c7f4a29683c7d4129b2da54fbf84e..b8a42b7c880b16e6bcb1a4df4e6c3336c6c6edf3 100644 (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;
 
index 5efb193c3adec7d151d3c5db1fa51a8b26cd992f..ef98e4a328b5ae25e504330cb2257864ea26ffdf 100644 (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);
 }
index b6058a2cb7940c2156bf4b5bb0d65dba83e7ef92..a5c560fb17b8925982afeb8b139592d2866cf0d7 100644 (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);