Fix T79324: Crash when changing View Layer while VR session runs

Proper handling of View Layers for the VR session was never implemented.
Now the View Layer of the VR session follows the window the session was
started in.
Note that if this window is closed, we fallback to another window. This
is done to avoid the overhead it would take to maintain a separate
depsgraph for the VR view. Instead we always share some already visible
View Layer (and hence the depsgraph).
This commit is contained in:
Julian Eisel 2020-08-10 17:29:35 +02:00 committed by Jeroen Bakker
parent 112416e4fb
commit fa2a13bcb9
Notes: blender-bot 2023-05-22 12:40:41 +02:00
Referenced by issue #79324, VR scene inspection - crash with view layers
Referenced by issue #77348, Blender LTS: Maintenance Task 2.83
4 changed files with 58 additions and 6 deletions

View File

@ -3734,6 +3734,7 @@ static int wm_xr_session_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C);
/* Lazy-create xr context - tries to dynlink to the runtime, reading active_runtime.json. */
@ -3742,7 +3743,7 @@ static int wm_xr_session_toggle_exec(bContext *C, wmOperator *UNUSED(op))
}
v3d->runtime.flag |= V3D_RUNTIME_XR_SESSION_ROOT;
wm_xr_session_toggle(wm, wm_xr_session_update_screen_on_exit_cb);
wm_xr_session_toggle(wm, win, wm_xr_session_update_screen_on_exit_cb);
wm_xr_session_update_screen(bmain, &wm->xr);
WM_event_add_notifier(C, NC_WM | ND_XR_DATA_CHANGED, NULL);

View File

@ -45,7 +45,11 @@ typedef struct wmXrSessionState {
typedef struct wmXrRuntimeData {
GHOST_XrContextHandle context;
/* Although this struct is internal, RNA gets a handle to this for state information queries. */
/** The window the session was started in. Stored to be able to follow its view-layer. This may
* be an invalid reference, i.e. the window may have been closed. */
wmWindow *session_root_win;
/** Although this struct is internal, RNA gets a handle to this for state information queries. */
wmXrSessionState session_state;
wmXrSessionExitFn exit_fn;
} wmXrRuntimeData;

View File

@ -19,7 +19,10 @@
*/
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "DEG_depsgraph.h"
@ -68,7 +71,9 @@ static void wm_xr_session_begin_info_create(wmXrData *xr_data,
r_begin_info->exit_customdata = xr_data;
}
void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn)
void wm_xr_session_toggle(wmWindowManager *wm,
wmWindow *session_root_win,
wmXrSessionExitFn session_exit_fn)
{
wmXrData *xr_data = &wm->xr;
@ -78,6 +83,7 @@ void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn
else {
GHOST_XrSessionBeginInfo begin_info;
xr_data->runtime->session_root_win = session_root_win;
xr_data->runtime->session_state.is_started = true;
xr_data->runtime->exit_fn = session_exit_fn;
@ -154,6 +160,43 @@ static void wm_xr_session_draw_data_populate(wmXrData *xr_data,
wm_xr_session_base_pose_calc(r_draw_data->scene, settings, &r_draw_data->base_pose);
}
static wmWindow *wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm,
const wmXrRuntimeData *runtime_data)
{
if (runtime_data->session_root_win &&
BLI_findindex(&wm->windows, runtime_data->session_root_win) != -1) {
/* Root window is still valid, use it. */
return runtime_data->session_root_win;
}
/* Otherwise, fallback. */
return wm->windows.first;
}
/**
* Get the scene and depsgraph shown in the VR session's root window (the window the session was
* started from) if still available. If it's not available, use some fallback window.
*
* It's important that the VR session follows some existing window, otherwise it would need to have
* an own depsgraph, which is an expense we should avoid.
*/
static void wm_xr_session_scene_and_evaluated_depsgraph_get(Main *bmain,
const wmWindowManager *wm,
Scene **r_scene,
Depsgraph **r_depsgraph)
{
const wmWindow *root_win = wm_xr_session_root_window_or_fallback_get(wm, wm->xr.runtime);
/* Follow the scene & view layer shown in the root 3D View. */
Scene *scene = WM_window_get_active_scene(root_win);
ViewLayer *view_layer = WM_window_get_active_view_layer(root_win);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, false);
BLI_assert(scene && view_layer && depsgraph);
BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
*r_scene = scene;
*r_depsgraph = depsgraph;
}
void wm_xr_session_draw_data_update(const wmXrSessionState *state,
const XrSessionSettings *settings,
const GHOST_XrDrawViewInfo *draw_view,
@ -288,13 +331,17 @@ static void wm_xr_session_surface_draw(bContext *C)
{
wmXrSurfaceData *surface_data = g_xr_surface->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
Main *bmain = CTX_data_main(C);
wmXrDrawData draw_data;
if (!GHOST_XrSessionIsRunning(wm->xr.runtime->context)) {
return;
}
wm_xr_session_draw_data_populate(
&wm->xr, CTX_data_scene(C), CTX_data_ensure_evaluated_depsgraph(C), &draw_data);
Scene *scene;
Depsgraph *depsgraph;
wm_xr_session_scene_and_evaluated_depsgraph_get(bmain, wm, &scene, &depsgraph);
wm_xr_session_draw_data_populate(&wm->xr, scene, depsgraph, &draw_data);
GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data);

View File

@ -29,7 +29,7 @@ typedef void (*wmXrSessionExitFn)(const wmXrData *xr_data);
/* wm_xr.c */
bool wm_xr_init(wmWindowManager *wm);
void wm_xr_exit(wmWindowManager *wm);
void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn);
void wm_xr_session_toggle(wmWindowManager *wm, wmWindow *win, wmXrSessionExitFn session_exit_fn);
bool wm_xr_events_handle(wmWindowManager *wm);
#endif