From 1b3f9ecd0d0bdf20de24f72d73517cc97d925a15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 19 Feb 2018 23:50:52 +0100 Subject: 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. --- intern/gawain/gawain/gwn_context.h | 34 ++++++++ intern/gawain/gawain/gwn_vertex_array_id.h | 34 ++++++++ intern/gawain/src/gwn_vertex_array_id.cpp | 136 +++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 intern/gawain/gawain/gwn_context.h create mode 100644 intern/gawain/gawain/gwn_vertex_array_id.h create mode 100644 intern/gawain/src/gwn_vertex_array_id.cpp (limited to 'intern/gawain') 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 +#include +#include +#include + +#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 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(); + } + } -- cgit v1.2.3