[Bf-blender-cvs] [1b3f9ecd0d0] blender2.8: Gawain: Add new context/vao manager.

Clément Foucault noreply at git.blender.org
Wed Feb 21 15:28:39 CET 2018


Commit: 1b3f9ecd0d0bdf20de24f72d73517cc97d925a15
Author: Clément Foucault
Date:   Mon Feb 19 23:50:52 2018 +0100
Branches: blender2.8
https://developer.blender.org/rB1b3f9ecd0d0bdf20de24f72d73517cc97d925a15

Gawain: Add new context/vao manager.

This allows allocation of VAOs from different opengl contexts and thread as long as the drawing happens in the same context.

Allocation is thread safe as long as we abide by the "one opengl context per thread" rule.

We can still free from any thread and actual freeing will occur at new vao allocation or next context binding.

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

A	intern/gawain/gawain/gwn_context.h
A	intern/gawain/gawain/gwn_vertex_array_id.h
A	intern/gawain/src/gwn_vertex_array_id.cpp
M	source/blender/blenloader/intern/readfile.c
M	source/blender/makesdna/DNA_windowmanager_types.h
M	source/blender/windowmanager/intern/wm_files.c
M	source/blender/windowmanager/intern/wm_window.c

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

diff --git a/intern/gawain/gawain/gwn_context.h b/intern/gawain/gawain/gwn_context.h
new file mode 100644
index 00000000000..3addce762b3
--- /dev/null
+++ b/intern/gawain/gawain/gwn_context.h
@@ -0,0 +1,34 @@
+
+// Gawain context
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2018 Mike Erwin
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+// This interface allow Gawain to manage VAOs for mutiple context and threads.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gwn_common.h"
+#include "gwn_batch.h"
+#include "gwn_shader_interface.h"
+
+typedef struct Gwn_Context Gwn_Context;
+
+Gwn_Context* GWN_context_create(void);
+void GWN_context_discard(Gwn_Context*);
+
+void GWN_context_active_set(Gwn_Context*);
+Gwn_Context* GWN_context_active_get(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/intern/gawain/gawain/gwn_vertex_array_id.h b/intern/gawain/gawain/gwn_vertex_array_id.h
new file mode 100644
index 00000000000..6d2a059b9bd
--- /dev/null
+++ b/intern/gawain/gawain/gwn_vertex_array_id.h
@@ -0,0 +1,34 @@
+
+// Gawain buffer IDs
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2018 Mike Erwin, Clément Foucault
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+// Manage GL vertex array IDs in a thread-safe way
+// Use these instead of glGenBuffers & its friends
+// - alloc must be called from a thread that is bound
+//   to the context that will be used for drawing with
+//   this vao.
+// - free can be called from any thread
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gwn_common.h"
+#include "gwn_context.h"
+
+GLuint GWN_vao_default(void);
+GLuint GWN_vao_alloc_new(void);
+void GWN_vao_free_new(GLuint vao_id, Gwn_Context*);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/intern/gawain/src/gwn_vertex_array_id.cpp b/intern/gawain/src/gwn_vertex_array_id.cpp
new file mode 100644
index 00000000000..602c1c4919c
--- /dev/null
+++ b/intern/gawain/src/gwn_vertex_array_id.cpp
@@ -0,0 +1,136 @@
+
+// Gawain vertex array IDs
+//
+// This code is part of the Gawain library, with modifications
+// specific to integration with Blender.
+//
+// Copyright 2016 Mike Erwin, Clément Foucault
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
+// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.#include "buffer_id.h"
+
+#include "gwn_vertex_array_id.h"
+#include "gwn_context.h"
+#include <vector>
+#include <string.h>
+#include <pthread.h>
+#include <mutex>
+
+#if TRUST_NO_ONE
+extern "C" {
+extern int BLI_thread_is_main(void); // Blender-specific function
+}
+
+static bool thread_is_main()
+	{
+	// "main" here means the GL context's thread
+	return BLI_thread_is_main();
+	}
+#endif
+
+struct Gwn_Context {
+	GLuint default_vao;
+	std::vector<GLuint> orphaned_vertarray_ids;
+	std::mutex orphans_mutex; // todo: try spinlock instead
+#if TRUST_NO_ONE
+	pthread_t thread; // Thread on which this context is active.
+#endif
+};
+
+static thread_local Gwn_Context* active_ctx = NULL;
+
+static void clear_orphans(Gwn_Context* ctx)
+	{
+	ctx->orphans_mutex.lock();
+	if (!ctx->orphaned_vertarray_ids.empty())
+		{
+		unsigned orphan_ct = (unsigned)ctx->orphaned_vertarray_ids.size();
+		glDeleteVertexArrays(orphan_ct, ctx->orphaned_vertarray_ids.data());
+		ctx->orphaned_vertarray_ids.clear();
+		}
+	ctx->orphans_mutex.unlock();
+	}
+
+Gwn_Context* GWN_context_create(void)
+	{
+#if TRUST_NO_ONE
+	assert(thread_is_main());
+#endif
+	Gwn_Context* ctx = (Gwn_Context*)calloc(1, sizeof(Gwn_Context));
+	glGenVertexArrays(1, &ctx->default_vao);
+	GWN_context_active_set(ctx);
+	return ctx;
+	}
+
+// to be called after GWN_context_active_set(ctx_to_destroy)
+void GWN_context_discard(Gwn_Context* ctx)
+	{
+#if TRUST_NO_ONE
+	// Make sure no other thread has locked it.
+	assert(ctx == active_ctx);
+	assert(ctx->thread == pthread_self());
+	assert(ctx->orphaned_vertarray_ids.empty());
+#endif
+	glDeleteVertexArrays(1, &ctx->default_vao);
+	free(ctx);
+	active_ctx = NULL;
+	}
+
+// ctx can be NULL
+void GWN_context_active_set(Gwn_Context* ctx)
+	{
+#if TRUST_NO_ONE
+	if (active_ctx)
+		active_ctx->thread = 0;
+	// Make sure no other context is already bound to this thread.
+	if (ctx)
+		{
+		// Make sure no other thread has locked it.
+		assert(ctx->thread == 0);
+		ctx->thread = pthread_self();
+		}
+#endif
+	if (ctx)
+		clear_orphans(ctx);
+	active_ctx = ctx;
+	}
+
+Gwn_Context* GWN_context_active_get(void)
+	{
+	return active_ctx;
+	}
+
+GLuint GWN_vao_default(void)
+	{
+#if TRUST_NO_ONE
+	assert(active_ctx); // need at least an active context
+	assert(active_ctx->thread == pthread_self()); // context has been activated by another thread!
+#endif
+	return active_ctx->default_vao;
+	}
+
+GLuint GWN_vao_alloc_new(void)
+	{
+#if TRUST_NO_ONE
+	assert(active_ctx); // need at least an active context
+	assert(active_ctx->thread == pthread_self()); // context has been activated by another thread!
+#endif
+	clear_orphans(active_ctx);
+
+	GLuint new_vao_id = 0;
+	glGenVertexArrays(1, &new_vao_id);
+	return new_vao_id;
+	}
+
+// this can be called from multiple thread
+void GWN_vao_free_new(GLuint vao_id, Gwn_Context* ctx)
+	{
+	if (ctx == active_ctx)
+		glDeleteVertexArrays(1, &vao_id);
+	else
+		{
+		ctx->orphans_mutex.lock();
+		ctx->orphaned_vertarray_ids.emplace_back(vao_id);
+		ctx->orphans_mutex.unlock();
+		}
+	}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 6e89ed36add..38149ae94ae 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -6496,6 +6496,7 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
 		oldnewmap_insert(fd->globmap, hook, win->workspace_hook, 0);
 
 		win->ghostwin = NULL;
+		win->gwnctx = NULL;
 		win->eventstate = NULL;
 		win->tweak = NULL;
 #ifdef WIN32
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index d67f86dd99c..9e1d5e4ec93 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -180,6 +180,7 @@ typedef struct wmWindow {
 	struct wmWindow *next, *prev;
 
 	void *ghostwin;             /* don't want to include ghost.h stuff */
+	void *gwnctx;               /* don't want to include gawin stuff */
 
 	struct Scene *scene;     /* The scene displayed in this window. */
 	struct Scene *new_scene; /* temporary when switching */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 98606379a61..34006fe87b8 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -182,6 +182,7 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
 static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
 {
 	win->ghostwin = oldwin->ghostwin;
+	win->gwnctx = oldwin->gwnctx;
 	win->active = oldwin->active;
 	if (win->active)
 		wm->winactive = win;
@@ -190,6 +191,7 @@ static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWi
 		GHOST_SetWindowUserData(win->ghostwin, win);    /* pointer back */
 
 	oldwin->ghostwin = NULL;
+	oldwin->gwnctx = NULL;
 
 	win->eventstate = oldwin->eventstate;
 	oldwin->eventstate = NULL;
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 9aecee75a15..3268841334d 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -87,6 +87,8 @@
 
 #include "UI_resources.h"
 
+#include "../../../intern/gawain/gawain/gwn_context.h"
+
 /* for assert */
 #ifndef NDEBUG
 #  include "BLI_threads.h"
@@ -169,11 +171,17 @@ static void wm_window_check_position(rcti *rect)
 }
 
 
-static void wm_ghostwindow_destroy(wmWindow *win) 
+static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
 {
 	if (win->ghostwin) {
+		/* We need this window's opengl context active to discard it. */
+		wm_window_make_drawable(wm, win);
+		/* Delete local gawain objects.  */
+		GWN_context_discard(win->gwnctx);
+
 		GHOST_DisposeWindow(g_system, win->ghostwin);
 		win->ghostwin = NULL;
+		win->gwnctx = NULL;
 	}
 }
 
@@ -192,11 +200,6 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
 			CTX_wm_window_set(C, NULL);
 	}
 
-	/* always set drawable and active to NULL,
-	 * prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
-	wm->windrawable = NULL;
-	wm->winactive = NULL;
-
 	/* end running jobs, a job end also removes its timer */
 	for (wt = wm->timers.first; wt; wt = wtnext) {
 		wtnext = wt->next;
@@ -217,7 +220,12 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
 
 	wm_draw_data_free(win);
 
-	wm_ghostwindow_destroy(win);
+	wm_ghostwindow_destroy(wm, win);
+
+	/* always set drawable and active to NULL,
+	 * prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
+	wm->windrawable = NULL;
+	wm->winactive = NULL;
 
 	BKE_workspace_instance_hook_free(G.main, win->workspace_hook);
 	MEM_freeN(win->stereo3d_format);
@@ -484,6 +492,8 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
 	
 	if (ghostwin) {
 		GHOST_RectangleHandle bounds;
+
+		win->gwnctx = GWN_context_create();
 		
 		/* the new window has already been made drawable upon creation */
 		wm->windrawable = win;
@@ -1000,7 +1010,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
 {
 	if (win != wm->windrawable && win->ghostwin) {
 //		win->lmbut = 0;	/* 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list