Fix: Blender crashes opening a file with compositor

Blender crashes when opening a file that has an interactive compositor
active, while also having a script that invokes the compositor upon file
load.

This is caused by the same system GPU context being active in two
threads at the same time, which happens when the GPU context for the
compositor is created in the main thread, it is made current during
creation, but it is not reset to the main GPU context of the drawable
because it is null. So when the GPU compositor actually executes, it
makes the GPU context current again but in its own thread, causing a
BadAccess error in X11 and potentially other window systems.

The reason why the drawable is nullptr is because it is reset in the
existing window manager when opening a new file while Blender is open,
but it is never initialized for the new window manager. The drawable
info should be moved from the old window manager to the new window
manager in wm_file_read_setup_wm_use_new, but it is preemptively reset
by the wm_window_clear_drawable call before it it is moved. This is done
in wm_file_read_setup_wm_substitute_old_window.

So to fix this, we move wm_window_clear_drawable after the code block
where wm_file_read_setup_wm_substitute_old_window gets called.
This commit is contained in:
Omar Emara
2024-10-07 18:34:54 +03:00
parent 301c853b9c
commit 0a70360eb6

View File

@@ -386,9 +386,6 @@ static void wm_file_read_setup_wm_use_new(bContext *C,
wm->init_flag = 0;
wm->winactive = nullptr;
/* Clearing drawable of old WM before deleting any context to avoid clearing the wrong wm. */
wm_window_clear_drawable(old_wm);
bool has_match = false;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
LISTBASE_FOREACH (wmWindow *, old_win, &old_wm->windows) {
@@ -407,6 +404,9 @@ static void wm_file_read_setup_wm_use_new(bContext *C,
static_cast<wmWindow *>(wm->windows.first));
}
/* Clearing drawable of old WM before deleting any context to avoid clearing the wrong wm. */
wm_window_clear_drawable(old_wm);
wm_setup_data->old_wm = nullptr;
wm_close_and_free(C, old_wm);
/* Don't handle user counts as this is only ever called once #G_MAIN has already been freed via