Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/gpu/intern/gpu_vertex_array_id.cpp')
-rw-r--r--source/blender/gpu/intern/gpu_vertex_array_id.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/source/blender/gpu/intern/gpu_vertex_array_id.cpp b/source/blender/gpu/intern/gpu_vertex_array_id.cpp
new file mode 100644
index 00000000000..de5be15ec19
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_vertex_array_id.cpp
@@ -0,0 +1,196 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 by Mike Erwin.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Clément Foucault
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/gwn_vertex_array_id.cpp
+ * \ingroup gpu
+ *
+ * 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
+ */
+
+#include "gpu_batch_private.h"
+#include "GPU_vertex_array_id.h"
+#include "GPU_context.h"
+#include <vector>
+#include <string.h>
+#include <pthread.h>
+#include <mutex>
+#include <unordered_set>
+
+#if TRUST_NO_ONE
+#if 0
+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
+#endif
+
+struct Gwn_Context {
+ GLuint default_vao;
+ std::unordered_set<Gwn_Batch*> batches; /* Batches that have VAOs from this context */
+ 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. */
+ bool thread_is_used;
+
+ Gwn_Context() {
+ thread_is_used = false;
+ }
+#endif
+};
+
+#if defined(_MSC_VER) && (_MSC_VER == 1800)
+#define thread_local __declspec(thread)
+thread_local Gwn_Context* active_ctx = NULL;
+#else
+static thread_local Gwn_Context* active_ctx = NULL;
+#endif
+
+static void clear_orphans(Gwn_Context* ctx)
+{
+ ctx->orphans_mutex.lock();
+ if (!ctx->orphaned_vertarray_ids.empty()) {
+ uint orphan_len = (uint)ctx->orphaned_vertarray_ids.size();
+ glDeleteVertexArrays(orphan_len, 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 = new 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(pthread_equal(pthread_self(), ctx->thread));
+ assert(ctx->orphaned_vertarray_ids.empty());
+#endif
+ /* delete remaining vaos */
+ while (!ctx->batches.empty()) {
+ /* this removes the array entry */
+ gwn_batch_vao_cache_clear(*ctx->batches.begin());
+ }
+ glDeleteVertexArrays(1, &ctx->default_vao);
+ delete 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_is_used = false;
+ }
+ /* Make sure no other context is already bound to this thread. */
+ if (ctx) {
+ /* Make sure no other thread has locked it. */
+ assert(ctx->thread_is_used == false);
+ ctx->thread = pthread_self();
+ ctx->thread_is_used = true;
+ }
+#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(pthread_equal(pthread_self(), active_ctx->thread)); /* context has been activated by another thread! */
+#endif
+ return active_ctx->default_vao;
+}
+
+GLuint GWN_vao_alloc(void)
+{
+#if TRUST_NO_ONE
+ assert(active_ctx); /* need at least an active context */
+ assert(pthread_equal(pthread_self(), active_ctx->thread)); /* 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(GLuint vao_id, Gwn_Context* ctx)
+{
+#if TRUST_NO_ONE
+ assert(ctx);
+#endif
+ 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();
+ }
+}
+
+void gwn_context_add_batch(Gwn_Context* ctx, Gwn_Batch* batch)
+{
+ ctx->batches.emplace(batch);
+}
+
+void gwn_context_remove_batch(Gwn_Context* ctx, Gwn_Batch* batch)
+{
+ ctx->orphans_mutex.lock();
+ ctx->batches.erase(batch);
+ ctx->orphans_mutex.unlock();
+}