Blender V4.3
wm_xr.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
13#include "BKE_global.hh"
14#include "BKE_idprop.hh"
15#include "BKE_main.hh"
16#include "BKE_report.hh"
17
18#include "DNA_scene_types.h"
20
21#include "ED_screen.hh"
22
23#include "GHOST_C-api.h"
24
25#ifdef WIN32
26# include "GPU_platform.hh"
27#endif
28
29#include "MEM_guardedalloc.h"
30
31#include "WM_api.hh"
32
33#include "wm_xr_intern.hh"
34
38
39/* -------------------------------------------------------------------- */
40
41static void wm_xr_error_handler(const GHOST_XrError *error)
42{
43 wmXrErrorHandlerData *handler_data = static_cast<wmXrErrorHandlerData *>(error->customdata);
44 wmWindowManager *wm = handler_data->wm;
45 wmWindow *root_win = wm->xr.runtime ? wm->xr.runtime->session_root_win : nullptr;
46
47 BKE_reports_clear(&wm->runtime->reports);
48 WM_report(RPT_ERROR, error->user_message);
49 /* Rely on the fallback when `root_win` is nullptr. */
50 WM_report_banner_show(wm, root_win);
51
52 if (wm->xr.runtime) {
53 /* Just play safe and destroy the entire runtime data, including context. */
55 }
56}
57
59{
60 if (wm->xr.runtime && wm->xr.runtime->context) {
61 return true;
62 }
63 static wmXrErrorHandlerData error_customdata;
64
65 /* Set up error handling. */
66 error_customdata.wm = wm;
67 GHOST_XrErrorHandler(wm_xr_error_handler, &error_customdata);
68
69 {
70 const GHOST_TXrGraphicsBinding gpu_bindings_candidates[] = {
71 GHOST_kXrGraphicsOpenGL,
72#ifdef WIN32
73 GHOST_kXrGraphicsD3D11,
74#endif
75 };
76 GHOST_XrContextCreateInfo create_info{
77 /*gpu_binding_candidates*/ gpu_bindings_candidates,
78 /*gpu_binding_candidates_count*/ ARRAY_SIZE(gpu_bindings_candidates),
79 };
80 GHOST_XrContextHandle context;
81
82 if (G.debug & G_DEBUG_XR) {
83 create_info.context_flag |= GHOST_kXrContextDebug;
84 }
85 if (G.debug & G_DEBUG_XR_TIME) {
86 create_info.context_flag |= GHOST_kXrContextDebugTime;
87 }
88#ifdef WIN32
90 create_info.context_flag |= GHOST_kXrContextGpuNVIDIA;
91 }
92#endif
93
94 if (!(context = GHOST_XrContextCreate(&create_info))) {
95 return false;
96 }
97
98 /* Set up context callbacks. */
99 GHOST_XrGraphicsContextBindFuncs(context,
102 GHOST_XrDrawViewFunc(context, wm_xr_draw_view);
103 GHOST_XrPassthroughEnabledFunc(context, wm_xr_passthrough_enabled);
104 GHOST_XrDisablePassthroughFunc(context, wm_xr_disable_passthrough);
105
106 if (!wm->xr.runtime) {
108 wm->xr.runtime->context = context;
109 }
110 }
111 BLI_assert(wm->xr.runtime && wm->xr.runtime->context);
112
113 return true;
114}
115
117{
118 if (wm->xr.runtime != nullptr) {
120 }
123 wm->xr.session_settings.shading.prop = nullptr;
124 }
125}
126
128{
129 if (wm->xr.runtime && wm->xr.runtime->context) {
131
132 /* Process OpenXR action events. */
133 if (WM_xr_session_is_ready(&wm->xr)) {
135 }
136
137 /* #wm_window_events_process() uses the return value to determine if it can put the main thread
138 * to sleep for some milliseconds. We never want that to happen while the VR session runs on
139 * the main thread. So always return true. */
140 return true;
141 }
142 return false;
143}
144
145/* -------------------------------------------------------------------- */
150{
151 wmXrRuntimeData *runtime = static_cast<wmXrRuntimeData *>(
152 MEM_callocN(sizeof(*runtime), __func__));
153 return runtime;
154}
155
157{
158 /* Note that this function may be called twice, because of an indirect recursion: If a session is
159 * running while WM-XR calls this function, calling GHOST_XrContextDestroy() will call this
160 * again, because it's also set as the session exit callback. So nullptr-check and nullptr
161 * everything that is freed here. */
162
163 /* We free all runtime XR data here, so if the context is still alive, destroy it. */
164 if ((*runtime)->context != nullptr) {
165 GHOST_XrContextHandle context = (*runtime)->context;
166 /* Prevent recursive #GHOST_XrContextDestroy() call by nulling the context pointer before
167 * the first call, see comment above. */
168 (*runtime)->context = nullptr;
169
170 if ((*runtime)->area) {
171 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
173 ED_area_offscreen_free(wm, win, (*runtime)->area);
174 (*runtime)->area = nullptr;
175 }
176 wm_xr_session_data_free(&(*runtime)->session_state);
177 WM_xr_actionmaps_clear(*runtime);
178
179 GHOST_XrContextDestroy(context);
180 }
181 MEM_SAFE_FREE(*runtime);
182}
183
184 /* XR Runtime Data. */
#define G_MAIN
@ G_DEBUG_XR
@ G_DEBUG_XR_TIME
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1227
void BKE_reports_clear(ReportList *reports)
Definition report.cc:81
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ARRAY_SIZE(arr)
void ED_area_offscreen_free(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:2184
GHOST C-API function and type declarations.
GHOST_TSuccess GHOST_XrEventsHandle(GHOST_XrContextHandle xr_contexthandle)
GHOST_XrContextHandle GHOST_XrContextCreate(const GHOST_XrContextCreateInfo *create_info)
Definition GHOST_Xr.cc:20
void GHOST_XrContextDestroy(GHOST_XrContextHandle xr_contexthandle)
Definition GHOST_Xr.cc:38
void GHOST_XrErrorHandler(GHOST_XrErrorHandlerFn handler_fn, void *customdata)
Definition GHOST_Xr.cc:43
@ GPU_DRIVER_ANY
@ GPU_OS_WIN
@ GPU_DEVICE_NVIDIA
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define G(x, y, z)
static void error(const char *str)
struct IDProperty * prop
struct View3DShading shading
WindowManagerRuntimeHandle * runtime
XrSessionSettings session_settings
struct wmXrRuntimeData * runtime
wmWindowManager * wm
Definition wm_xr.cc:36
GHOST_XrContextHandle context
wmWindow * session_root_win
void WM_report(eReportType type, const char *message)
void WM_report_banner_show(wmWindowManager *wm, wmWindow *win)
bool wm_xr_init(wmWindowManager *wm)
Definition wm_xr.cc:58
static void wm_xr_error_handler(const GHOST_XrError *error)
Definition wm_xr.cc:41
void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
Definition wm_xr.cc:156
wmXrRuntimeData * wm_xr_runtime_data_create()
Definition wm_xr.cc:149
bool wm_xr_events_handle(wmWindowManager *wm)
Definition wm_xr.cc:127
void wm_xr_exit(wmWindowManager *wm)
Definition wm_xr.cc:116
void WM_xr_actionmaps_clear(wmXrRuntimeData *runtime)
bool wm_xr_passthrough_enabled(void *customdata)
Check if XR passthrough is enabled.
void wm_xr_disable_passthrough(void *customdata)
Disable XR passthrough if not supported.
void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
Draw a viewport for a single eye.
void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle context)
void wm_xr_session_actions_update(wmWindowManager *wm)
void * wm_xr_session_gpu_binding_context_create()
wmWindow * wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm, const wmXrRuntimeData *runtime_data)
void wm_xr_session_data_free(wmXrSessionState *state)
bool WM_xr_session_is_ready(const wmXrData *xr)