Fix T55776: crash with multiple windows and reload new.

There were a number of cases where immActivate() and immDeactivate() could
get out of sync, causing crashes due to using a freed mutex lock. Refactor
the code now to hopefully avoid this always.
This commit is contained in:
Brecht Van Lommel 2018-07-09 23:33:20 +02:00
parent 845899d373
commit 8373544df3
Notes: blender-bot 2023-02-14 10:32:59 +01:00
Referenced by issue #55776, Crash when open multiple window then reload new
6 changed files with 61 additions and 55 deletions

View File

@ -77,8 +77,6 @@ void immInit(void)
glBindBuffer(GL_ARRAY_BUFFER, 0);
initialized = true;
immActivate();
}
void immActivate(void)
@ -106,7 +104,6 @@ void immDeactivate(void)
void immDestroy(void)
{
immDeactivate();
GWN_buf_id_free(imm.vbo_id);
initialized = false;
}

View File

@ -143,17 +143,11 @@ static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
}
/* also used by buffer swap switching */
static void rna_userdef_dpi_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
static void rna_userdef_dpi_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
/* font's are stored at each DPI level, without this we can easy load 100's of fonts */
BLF_cache_clear();
/* force setting drawable again */
wmWindowManager *wm = bmain->wm.first;
if (wm) {
wm->windrawable = NULL;
}
WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
}

View File

@ -186,13 +186,18 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
ED_editors_exit(C);
}
static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
static void wm_window_substitute_old(wmWindowManager *oldwm, wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
{
win->ghostwin = oldwin->ghostwin;
win->gwnctx = oldwin->gwnctx;
win->active = oldwin->active;
if (win->active)
if (win->active) {
wm->winactive = win;
}
if (oldwm->windrawable == oldwin) {
oldwm->windrawable = NULL;
wm->windrawable = win;
}
if (!G.background) /* file loading in background mode still calls this */
GHOST_SetWindowUserData(win->ghostwin, win); /* pointer back */
@ -281,13 +286,13 @@ static void wm_window_match_replace_by_file_wm(
if (oldwin->winid == win->winid) {
has_match = true;
wm_window_substitute_old(wm, oldwin, win);
wm_window_substitute_old(oldwm, wm, oldwin, win);
}
}
}
/* make sure at least one window is kept open so we don't lose the context, check T42303 */
if (!has_match) {
wm_window_substitute_old(wm, oldwm->windows.first, wm->windows.first);
wm_window_substitute_old(oldwm, wm, oldwm->windows.first, wm->windows.first);
}
wm_close_and_free_all(C, current_wm_list);

View File

@ -491,8 +491,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
#endif
GPU_free_unused_buffers(G_MAIN);
GPU_exit();
}
BKE_blender_free(); /* blender.c, does entire library and spacetypes */
@ -515,6 +513,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
if (opengl_is_init) {
GPU_pass_cache_free();
DRW_opengl_context_destroy();
GPU_exit();
}
#ifdef WITH_INTERNATIONAL

View File

@ -1283,6 +1283,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
/* initialize OpenGL immediate mode */
g_WS.gwn_context = GWN_context_create();
GPU_init();
immActivate();
/* initialize the font */
BLF_init();
@ -1551,8 +1552,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
GPU_shader_free_builtin_shaders();
GPU_exit();
if (g_WS.gwn_context) {
GWN_context_active_set(g_WS.gwn_context);
GWN_context_discard(g_WS.gwn_context);
@ -1561,6 +1560,9 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
BLF_exit();
immDeactivate();
GPU_exit();
GHOST_DisposeWindow(g_WS.ghost_system, g_WS.ghost_window);
/* early exit, IMB and BKE should be exited only in end */

View File

@ -122,6 +122,9 @@ static struct WMInitStruct {
/* ******** win open & close ************ */
static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate);
static void wm_window_clear_drawable(wmWindowManager *wm);
/* XXX this one should correctly check for apple top header...
* done for Cocoa : returns window contents (and not frame) max size*/
void wm_get_screensize(int *r_width, int *r_height)
@ -176,10 +179,19 @@ static void wm_window_check_position(rcti *rect)
if (rect->ymin < 0) rect->ymin = 0;
}
static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
{
if (win->ghostwin) {
if (win == wm->windrawable) {
/* Prevents non-drawable state of main windows (bugs #22967,
* #25071 and possibly #22477 too). */
wm_window_clear_drawable(wm);
}
if (win == wm->winactive) {
wm->winactive = NULL;
}
/* We need this window's opengl context active to discard it. */
GHOST_ActivateWindowDrawingContext(win->ghostwin);
GWN_context_active_set(win->gwnctx);
@ -191,9 +203,6 @@ static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
win->ghostwin = NULL;
win->gwnctx = NULL;
/* prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
wm->windrawable = NULL;
wm->winactive = NULL;
}
}
@ -513,21 +522,8 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
ED_screen_exit(C, win, screen);
}
if (win_other) {
BLF_batch_reset();
gpu_batch_presets_reset();
immDeactivate();
}
wm_window_free(C, wm, win);
/* keep imediatemode active before the next `wm_window_make_drawable` call */
if (win_other) {
GHOST_ActivateWindowDrawingContext(win_other->ghostwin);
GWN_context_active_set(win_other->gwnctx);
immActivate();
}
/* if temp screen, delete it after window free (it stops jobs that can access it) */
if (screen && screen->temp) {
Main *bmain = CTX_data_main(C);
@ -646,19 +642,19 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
if (ghostwin) {
GHOST_RectangleHandle bounds;
/* XXX Fix crash when a new window is created.
* However this should be move somewhere else. (fclem) */
BLF_batch_reset();
gpu_batch_presets_reset();
/* Clear drawable so we can set the new window. */
wm_window_clear_drawable(wm);
win->gwnctx = GWN_context_create();
/* the new window has already been made drawable upon creation */
wm->windrawable = win;
/* needed so we can detect the graphics card below */
GPU_init();
/* Set window as drawable upon creation. Note this has already been
* it has already been activated by GHOST_CreateWindow. */
bool activate = false;
wm_window_set_drawable(wm, win, activate);
win->ghostwin = ghostwin;
GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
@ -1095,24 +1091,41 @@ static int query_qual(modifierKeyType qual)
return val;
}
static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate)
{
BLI_assert(ELEM(wm->windrawable, NULL, win));
wm->windrawable = win;
if (activate) {
GHOST_ActivateWindowDrawingContext(win->ghostwin);
}
GWN_context_active_set(win->gwnctx);
immActivate();
}
static void wm_window_clear_drawable(wmWindowManager *wm)
{
if (wm->windrawable) {
BLF_batch_reset();
gpu_batch_presets_reset();
immDeactivate();
wm->windrawable = NULL;
}
}
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
{
BLI_assert(GPU_framebuffer_current_get() == 0);
if (win != wm->windrawable && win->ghostwin) {
// win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */
wm_window_clear_drawable(wm);
wm->windrawable = win;
if (G.debug & G_DEBUG_EVENTS) {
printf("%s: set drawable %d\n", __func__, win->winid);
}
BLF_batch_reset();
gpu_batch_presets_reset();
immDeactivate();
GHOST_ActivateWindowDrawingContext(win->ghostwin);
GWN_context_active_set(win->gwnctx);
immActivate();
wm_window_set_drawable(wm, win, true);
/* this can change per window */
WM_window_set_dpi(win);
@ -1132,12 +1145,8 @@ void wm_window_reset_drawable(void)
wmWindow *win = wm->windrawable;
if (win && win->ghostwin) {
BLF_batch_reset();
gpu_batch_presets_reset();
immDeactivate();
GHOST_ActivateWindowDrawingContext(win->ghostwin);
GWN_context_active_set(win->gwnctx);
immActivate();
wm_window_clear_drawable(wm);
wm_window_set_drawable(wm, win, true);
}
}