[Bf-blender-cvs] [10f0954] GPU_data_request: manage GL buffer IDs in a thread-safe way

Mike Erwin noreply at git.blender.org
Tue Apr 21 08:29:32 CEST 2015


Commit: 10f095463ca9a9bbeb123bf899c992c6d91f13e5
Author: Mike Erwin
Date:   Tue Apr 21 00:30:30 2015 -0400
Branches: GPU_data_request
https://developer.blender.org/rB10f095463ca9a9bbeb123bf899c992c6d91f13e5

manage GL buffer IDs in a thread-safe way

Old way was causing crash in GL when DerivedMesh discarded its
GPUxBatch from another thread.

New way deletes ID when safe to do so, otherwise “orphans” the ID to be
deleted later.

===================================================================

A	source/blender/gpu/intern/gpux_buffer_id.c
A	source/blender/gpu/intern/gpux_buffer_id.h
M	source/blender/gpu/intern/gpux_element.c
M	source/blender/gpu/intern/gpux_vbo.c

===================================================================

diff --git a/source/blender/gpu/intern/gpux_buffer_id.c b/source/blender/gpu/intern/gpux_buffer_id.c
new file mode 100644
index 0000000..6c02721
--- /dev/null
+++ b/source/blender/gpu/intern/gpux_buffer_id.c
@@ -0,0 +1,95 @@
+#include "gpux_buffer_id.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#define ORPHAN_DEBUG
+
+#ifdef ORPHAN_DEBUG
+  #include <stdio.h>
+#endif
+
+#define ORPHANED_BUFFER_MAX 48
+static GLuint orphaned_buffer_ids[ORPHANED_BUFFER_MAX];
+static unsigned orphaned_buffer_ct = 0;
+
+#define ORPHANED_VAO_MAX 16
+static GLuint orphaned_vao_ids[ORPHANED_VAO_MAX];
+static unsigned orphaned_vao_ct = 0;
+
+static ThreadMutex orphan_mutex = BLI_MUTEX_INITIALIZER;
+
+GLuint buffer_id_alloc()
+{
+	BLI_assert(BLI_thread_is_main());
+
+	GLuint new_buffer_id;
+
+	/* delete orphaned IDs */
+	BLI_mutex_lock(&orphan_mutex);
+	if (orphaned_buffer_ct) {
+#ifdef ORPHAN_DEBUG
+		printf("deleting %d orphaned VBO%s\n", orphaned_buffer_ct, orphaned_buffer_ct == 1 ? "" : "s");
+#endif
+		glDeleteBuffers(orphaned_buffer_ct, orphaned_buffer_ids);
+		orphaned_buffer_ct = 0;
+	}
+	BLI_mutex_unlock(&orphan_mutex);
+
+	glGenBuffers(1, &new_buffer_id);
+	return new_buffer_id;
+}
+
+void buffer_id_free(GLuint buffer_id)
+{
+	if (BLI_thread_is_main()) {
+		glDeleteBuffers(1, &buffer_id);
+	}
+	else {
+		/* add this ID to the orphaned list */
+		BLI_mutex_lock(&orphan_mutex);
+		BLI_assert(orphaned_buffer_ct < ORPHANED_BUFFER_MAX); /* increase MAX if needed */
+#ifdef ORPHAN_DEBUG
+		printf("orphaning VBO %d\n", buffer_id);
+#endif
+		orphaned_buffer_ids[orphaned_buffer_ct++] = buffer_id;
+		BLI_mutex_unlock(&orphan_mutex);
+	}
+}
+
+GLuint vao_id_alloc()
+{
+	BLI_assert(BLI_thread_is_main());
+
+	GLuint new_vao_id;
+
+	/* delete orphaned IDs */
+	BLI_mutex_lock(&orphan_mutex);
+	if (orphaned_vao_ct) {
+#ifdef ORPHAN_DEBUG
+		printf("deleting %d orphaned VAO%s\n", orphaned_vao_ct, orphaned_vao_ct == 1 ? "" : "s");
+#endif
+		glDeleteVertexArrays(orphaned_vao_ct, orphaned_vao_ids);
+		orphaned_vao_ct = 0;
+	}
+	BLI_mutex_unlock(&orphan_mutex);
+
+	glGenVertexArrays(1, &new_vao_id);
+	return new_vao_id;
+}
+
+void vao_id_free(GLuint vao_id)
+{
+	if (BLI_thread_is_main()) {
+		glDeleteVertexArrays(1, &vao_id);
+	}
+	else {
+		/* add this ID to the orphaned list */
+		BLI_mutex_lock(&orphan_mutex);
+		BLI_assert(orphaned_vao_ct < ORPHANED_VAO_MAX); /* increase MAX if needed */
+#ifdef ORPHAN_DEBUG
+		printf("orphaning VAO %d\n", vao_id);
+#endif
+		orphaned_vao_ids[orphaned_vao_ct++] = vao_id;
+		BLI_mutex_unlock(&orphan_mutex);
+	}
+}
diff --git a/source/blender/gpu/intern/gpux_buffer_id.h b/source/blender/gpu/intern/gpux_buffer_id.h
new file mode 100644
index 0000000..c6bf185
--- /dev/null
+++ b/source/blender/gpu/intern/gpux_buffer_id.h
@@ -0,0 +1,19 @@
+#ifndef BLENDER_GL_BUFFER_ID
+#define BLENDER_GL_BUFFER_ID
+
+/* Manage GL buffer IDs in a thread-safe way
+ * Use these instead of glGenBuffers & its friends
+ * - alloc must be called from main thread
+ * - free can be called from any thread
+ * private for now since GPUx uses this internally
+ * Mike Erwin, April 2015 */
+
+#include "GPU_glew.h"
+
+GLuint buffer_id_alloc();
+void buffer_id_free(GLuint buffer_id);
+
+GLuint vao_id_alloc();
+void vao_id_free(GLuint vao_id);
+
+#endif /* BLENDER_GL_BUFFER_ID */
diff --git a/source/blender/gpu/intern/gpux_element.c b/source/blender/gpu/intern/gpux_element.c
index 4cf2412..41dda57 100644
--- a/source/blender/gpu/intern/gpux_element.c
+++ b/source/blender/gpu/intern/gpux_element.c
@@ -1,5 +1,6 @@
 
 #include "gpux_element_private.h"
+#include "gpux_buffer_id.h"
 #include <stdlib.h>
 
 /* private functions */
@@ -82,7 +83,7 @@ void GPUx_element_list_discard(ElementList *el)
 {
 #ifdef USE_ELEM_VBO
 	if (el->vbo_id)
-		glDeleteBuffers(1, &el->vbo_id);
+		buffer_id_free(el->vbo_id);
 #endif /* USE_ELEM_VBO */
 
 	free(el->indices);
@@ -247,7 +248,7 @@ void GPUx_element_list_prime(ElementList *el)
   #ifdef TRUST_NO_ONE
 	assert(el->vbo_id == 0);
   #endif /* TRUST_NO_ONE */
-	glGenBuffers(1, &el->vbo_id);
+	el->vbo_id = buffer_id_alloc();
 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, el->vbo_id);
 	/* fill with delicious data & send to GPU the first time only */
 	glBufferData(GL_ELEMENT_ARRAY_BUFFER, GPUx_element_list_size(el), el->indices, GL_STATIC_DRAW);
diff --git a/source/blender/gpu/intern/gpux_vbo.c b/source/blender/gpu/intern/gpux_vbo.c
index 06b2387..42521d9 100644
--- a/source/blender/gpu/intern/gpux_vbo.c
+++ b/source/blender/gpu/intern/gpux_vbo.c
@@ -1,5 +1,6 @@
 
 #include "GPUx_vbo.h"
+#include "gpux_buffer_id.h"
 #include <stdlib.h>
 #include <string.h>
 
@@ -162,7 +163,7 @@ void GPUx_vertex_buffer_discard(VertexBuffer *buff)
 		Attrib *a = buff->attribs + a_idx;
 #ifdef USE_VBO
 		if (a->vbo_id)
-			glDeleteBuffers(1, &a->vbo_id);
+			buffer_id_free(a->vbo_id);
 #endif /* USE_VBO */
 #ifdef GENERIC_ATTRIB
 		free(a->name);
@@ -171,7 +172,7 @@ void GPUx_vertex_buffer_discard(VertexBuffer *buff)
 	}
 #ifdef USE_VAO
 	if (buff->vao_id)
-		glDeleteVertexArrays(1, &buff->vao_id);
+		vao_id_free(buff->vao_id);
 #endif /* USE_VAO */
 	free(buff->attribs);
 	free(buff);
@@ -362,7 +363,7 @@ void GPUx_vertex_buffer_use(VertexBuffer *buff)
 		return;
 	}
 	else {
-		glGenVertexArrays(1, &buff->vao_id);
+		buff->vao_id = vao_id_alloc();
 		glBindVertexArray(buff->vao_id);
 	}
 #endif /* USE_VAO */
@@ -380,7 +381,7 @@ void GPUx_vertex_buffer_use(VertexBuffer *buff)
 		if (a->vbo_id)
 			glBindBuffer(GL_ARRAY_BUFFER, a->vbo_id);
 		else {
-			glGenBuffers(1, &a->vbo_id);
+			a->vbo_id = buffer_id_alloc();
 			glBindBuffer(GL_ARRAY_BUFFER, a->vbo_id);
 			/* fill with delicious data & send to GPU the first time only */
 			glBufferData(GL_ARRAY_BUFFER, attrib_total_size(buff, a_idx), a->data, GL_STATIC_DRAW);
@@ -437,7 +438,7 @@ void GPUx_vertex_buffer_prime(VertexBuffer *buff)
 	assert(buff->vao_id == 0);
   #endif /* TRUST_NO_ONE */
 
-	glGenVertexArrays(1, &buff->vao_id);
+	buff->vao_id = vao_id_alloc();
 	glBindVertexArray(buff->vao_id);
 #endif /* USE_VAO */
 
@@ -460,7 +461,7 @@ void GPUx_vertex_buffer_prime(VertexBuffer *buff)
 		assert(a->vbo_id == 0);
   #endif /* TRUST_NO_ONE */
 
-		glGenBuffers(1, &a->vbo_id);
+		a->vbo_id = buffer_id_alloc();
 		glBindBuffer(GL_ARRAY_BUFFER, a->vbo_id);
 		/* fill with delicious data & send to GPU the first time only */
 		glBufferData(GL_ARRAY_BUFFER, attrib_total_size(buff, a_idx), a->data, GL_STATIC_DRAW);




More information about the Bf-blender-cvs mailing list