Fix crash with OpenGL rendering in multiple threads on macOS.
authorEdmund Kapusniak <edmundmk>
Mon, 11 Jun 2018 18:50:14 +0000 (20:50 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Mon, 11 Jun 2018 19:10:24 +0000 (21:10 +0200)
On macOS we must always go through BLI_thread_local_get/set().

Differential Revision: https://developer.blender.org/D3470

release/scripts/addons
source/blender/gpu/intern/gpu_framebuffer.c
source/blender/gpu/intern/gpu_init_exit.c
source/blender/gpu/intern/gpu_private.h

index ebd058d..c88411f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit ebd058d7a6438d137522063bb3286c8acc325ca6
+Subproject commit c88411ff7776a2db5d6ef6117a1b2faa42a95611
index f86da2e..6e791f6 100644 (file)
@@ -42,7 +42,9 @@
 #include "GPU_shader.h"
 #include "GPU_texture.h"
 
-static ThreadLocal(GLuint) g_currentfb;
+#include "intern/gpu_private.h"
+
+static ThreadLocal(void*) g_currentfb;
 
 typedef enum {
        GPU_FB_DEPTH_ATTACHMENT = 0,
@@ -163,6 +165,26 @@ static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
        }
 }
 
+void gpu_framebuffer_module_init(void)
+{
+    BLI_thread_local_create(g_currentfb);
+}
+
+void gpu_framebuffer_module_exit(void)
+{
+    BLI_thread_local_delete(g_currentfb);
+}
+
+static uint gpu_framebuffer_current_get()
+{
+       return GET_UINT_FROM_POINTER(BLI_thread_local_get(g_currentfb));
+}
+
+static void gpu_framebuffer_current_set(uint object)
+{
+       BLI_thread_local_set(g_currentfb, SET_UINT_IN_POINTER(object));
+}
+
 /* GPUFrameBuffer */
 
 GPUFrameBuffer *GPU_framebuffer_create(void)
@@ -188,8 +210,8 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb)
        /* This restores the framebuffer if it was bound */
        glDeleteFramebuffers(1, &fb->object);
 
-       if (g_currentfb == fb->object) {
-               g_currentfb = 0;
+       if (gpu_framebuffer_current_get() == fb->object) {
+               gpu_framebuffer_current_set(0);
        }
 
        MEM_freeN(fb);
@@ -341,7 +363,7 @@ static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb)
        GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT];
        int numslots = 0;
 
-       BLI_assert(g_currentfb == fb->object);
+       BLI_assert(gpu_framebuffer_current_get() == fb->object);
 
        /* Update attachments */
        for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
@@ -385,10 +407,10 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb)
        if (fb->object == 0)
                gpu_framebuffer_init(fb);
 
-       if (g_currentfb != fb->object)
+       if (gpu_framebuffer_current_get() != fb->object)
                glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
 
-       g_currentfb = fb->object;
+       gpu_framebuffer_current_set(fb->object);
 
        if (fb->dirty_flag != 0)
                gpu_framebuffer_update_attachments(fb);
@@ -409,20 +431,20 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb)
 
 void GPU_framebuffer_restore(void)
 {
-       if (g_currentfb != 0) {
+       if (gpu_framebuffer_current_get() != 0) {
                glBindFramebuffer(GL_FRAMEBUFFER, 0);
-               g_currentfb = 0;
+               gpu_framebuffer_current_set(0);
        }
 }
 
 bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
 {
-       return (fb->object == g_currentfb) && (fb->object != 0);
+       return (fb->object == gpu_framebuffer_current_get()) && (fb->object != 0);
 }
 
 unsigned int GPU_framebuffer_current_get(void)
 {
-       return g_currentfb;
+       return gpu_framebuffer_current_get();
 }
 
 bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
@@ -513,7 +535,7 @@ void GPU_framebuffer_blit(
 {
        BLI_assert(blit_buffers != 0);
 
-       GLuint prev_fb = g_currentfb;
+       GLuint prev_fb = gpu_framebuffer_current_get();
 
        /* Framebuffers must be up to date. This simplify this function. */
        if (fb_read->dirty_flag != 0 || fb_read->object == 0) {
@@ -573,7 +595,7 @@ void GPU_framebuffer_blit(
        }
        else {
                glBindFramebuffer(GL_FRAMEBUFFER, prev_fb);
-               g_currentfb = prev_fb;
+               gpu_framebuffer_current_set(prev_fb);
        }
 }
 
@@ -586,13 +608,13 @@ void GPU_framebuffer_recursive_downsample(
         void (*callback)(void *userData, int level), void *userData)
 {
        /* Framebuffer must be up to date and bound. This simplify this function. */
-       if (g_currentfb != fb->object || fb->dirty_flag != 0 || fb->object == 0) {
+       if (gpu_framebuffer_current_get() != fb->object || fb->dirty_flag != 0 || fb->object == 0) {
                GPU_framebuffer_bind(fb);
        }
        /* HACK: We make the framebuffer appear not bound in order to
         * not trigger any error in GPU_texture_bind().  */
-       GLuint prev_fb = g_currentfb;
-       g_currentfb = 0;
+       GLuint prev_fb = gpu_framebuffer_current_get();
+       gpu_framebuffer_current_set(0);
 
        int i;
        int current_dim[2] = {fb->width, fb->height};
@@ -640,7 +662,7 @@ void GPU_framebuffer_recursive_downsample(
                }
        }
 
-       g_currentfb = prev_fb;
+       gpu_framebuffer_current_set(prev_fb);
 }
 
 /* GPUOffScreen */
index 92ad9d8..78d4f49 100644 (file)
@@ -60,6 +60,7 @@ void GPU_init(void)
        GPU_texture_orphans_init();
        GPU_material_orphans_init();
        gpu_codegen_init();
+       gpu_framebuffer_module_init();
 
        if (G.debug & G_DEBUG_GPU)
                gpu_debug_init();
@@ -89,6 +90,7 @@ void GPU_exit(void)
        if (G.debug & G_DEBUG_GPU)
                gpu_debug_exit();
 
+       gpu_framebuffer_module_exit();
        gpu_codegen_exit();
 
        gpu_extensions_exit(); /* must come last */
index 72627e3..996ba9c 100644 (file)
@@ -33,4 +33,8 @@ void gpu_extensions_exit(void);
 void gpu_debug_init(void);
 void gpu_debug_exit(void);
 
+/* gpu_framebuffer.c */
+void gpu_framebuffer_module_init(void);
+void gpu_framebuffer_module_exit(void);
+
 #endif  /* __GPU_PRIVATE_H__ */