Blender V5.0
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
12
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#include "GPU_context.hh"
26
27#include "MEM_guardedalloc.h"
28
29#include "WM_api.hh"
30
31#include "wm_xr_intern.hh"
32
36
37/* -------------------------------------------------------------------- */
38
39static void wm_xr_error_handler(const GHOST_XrError *error)
40{
41 wmXrErrorHandlerData *handler_data = static_cast<wmXrErrorHandlerData *>(error->customdata);
42 wmWindowManager *wm = handler_data->wm;
43 wmWindow *root_win = wm->xr.runtime ? wm->xr.runtime->session_root_win : nullptr;
44
45 BKE_reports_clear(&wm->runtime->reports);
46 WM_global_report(RPT_ERROR, error->user_message);
47 /* Rely on the fallback when `root_win` is nullptr. */
48 WM_report_banner_show(wm, root_win);
49
50 if (wm->xr.runtime) {
51 /* Just play safe and destroy the entire runtime data, including context. */
53 }
54}
55
57{
58 if (wm->xr.runtime && wm->xr.runtime->context) {
59 return true;
60 }
61 static wmXrErrorHandlerData error_customdata;
62
63 /* Set up error handling. */
64 error_customdata.wm = wm;
65 GHOST_XrErrorHandler(wm_xr_error_handler, &error_customdata);
66
67 {
68 blender::Vector<GHOST_TXrGraphicsBinding> gpu_bindings_candidates;
69 switch (GPU_backend_get_type()) {
70#ifdef WITH_OPENGL_BACKEND
72 gpu_bindings_candidates.append(GHOST_kXrGraphicsOpenGL);
73# ifdef WIN32
74 gpu_bindings_candidates.append(GHOST_kXrGraphicsOpenGLD3D11);
75# endif
76 break;
77#endif
78
79#ifdef WITH_VULKAN_BACKEND
81 gpu_bindings_candidates.append(GHOST_kXrGraphicsVulkan);
82# ifdef WIN32
83 gpu_bindings_candidates.append(GHOST_kXrGraphicsVulkanD3D11);
84# endif
85 break;
86#endif
87
88 default:
89 break;
90 }
91
92 GHOST_XrContextCreateInfo create_info{
93 /*gpu_binding_candidates*/ gpu_bindings_candidates.data(),
94 /*gpu_binding_candidates_count*/ uint32_t(gpu_bindings_candidates.size()),
95 };
96 GHOST_XrContextHandle context;
97
98 if (G.debug & G_DEBUG_XR) {
99 create_info.context_flag |= GHOST_kXrContextDebug;
100 }
101 if (G.debug & G_DEBUG_XR_TIME) {
102 create_info.context_flag |= GHOST_kXrContextDebugTime;
103 }
104#ifdef WIN32
106 create_info.context_flag |= GHOST_kXrContextGpuNVIDIA;
107 }
108#endif
109
110 if (!(context = GHOST_XrContextCreate(&create_info))) {
111 return false;
112 }
113
114 /* Set up context callbacks. */
115 GHOST_XrGraphicsContextBindFuncs(context,
118 GHOST_XrDrawViewFunc(context, wm_xr_draw_view);
119 GHOST_XrPassthroughEnabledFunc(context, wm_xr_passthrough_enabled);
120 GHOST_XrDisablePassthroughFunc(context, wm_xr_disable_passthrough);
121
122 if (!wm->xr.runtime) {
124 wm->xr.runtime->context = context;
125 }
126 }
127 BLI_assert(wm->xr.runtime && wm->xr.runtime->context);
128
129 return true;
130}
131
133{
134 if (wm->xr.runtime != nullptr) {
136 }
137
138 /* See #wm_xr_data_free for logic that frees window-manager XR data
139 * that may exist even when built without XR. */
140}
141
143{
144 if (wm->xr.runtime && wm->xr.runtime->context) {
146
147 /* Process OpenXR action events. */
148 if (WM_xr_session_is_ready(&wm->xr)) {
150 }
151
152 /* #wm_window_events_process() uses the return value to determine if it can put the main thread
153 * to sleep for some milliseconds. We never want that to happen while the VR session runs on
154 * the main thread. So always return true. */
155 return true;
156 }
157 return false;
158}
159
160/* -------------------------------------------------------------------- */
163
165{
167 return runtime;
168}
169
171{
172 /* Note that this function may be called twice, because of an indirect recursion: If a session is
173 * running while WM-XR calls this function, calling GHOST_XrContextDestroy() will call this
174 * again, because it's also set as the session exit callback. So nullptr-check and nullptr
175 * everything that is freed here. */
176
177 /* We free all runtime XR data here, so if the context is still alive, destroy it. */
178 if ((*runtime)->context != nullptr) {
179 GHOST_XrContextHandle context = (*runtime)->context;
180 /* Prevent recursive #GHOST_XrContextDestroy() call by nulling the context pointer before
181 * the first call, see comment above. */
182 (*runtime)->context = nullptr;
183
184 if ((*runtime)->area) {
185 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
187
188 WM_event_remove_handlers_by_area(&win->handlers, (*runtime)->area);
189 ED_area_offscreen_free(wm, win, (*runtime)->area);
190 (*runtime)->area = nullptr;
191 }
192 wm_xr_session_data_free(&(*runtime)->session_state);
193 WM_xr_actionmaps_clear(*runtime);
194
195 GHOST_XrContextDestroy(context);
196 }
197 MEM_SAFE_FREE(*runtime);
198}
199 /* XR Runtime Data. */
@ G_DEBUG_XR
@ G_DEBUG_XR_TIME
#define G_MAIN
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_reports_clear(ReportList *reports)
Definition report.cc:109
#define BLI_assert(a)
Definition BLI_assert.h:46
void ED_area_offscreen_free(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:2279
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
GPUBackendType GPU_backend_get_type()
@ GPU_DEVICE_NVIDIA
bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
@ GPU_DRIVER_ANY
@ GPU_OS_WIN
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
int64_t size() const
void append(const T &value)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
#define G(x, y, z)
static void error(const char *str)
WindowManagerRuntimeHandle * runtime
struct wmXrRuntimeData * runtime
wmWindowManager * wm
Definition wm_xr.cc:34
GHOST_XrContextHandle context
wmWindow * session_root_win
void WM_global_report(eReportType type, const char *message)
void WM_report_banner_show(wmWindowManager *wm, wmWindow *win)
void WM_event_remove_handlers_by_area(ListBase *handlers, const ScrArea *area)
bool wm_xr_init(wmWindowManager *wm)
Definition wm_xr.cc:56
static void wm_xr_error_handler(const GHOST_XrError *error)
Definition wm_xr.cc:39
void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
Definition wm_xr.cc:170
wmXrRuntimeData * wm_xr_runtime_data_create()
Definition wm_xr.cc:164
bool wm_xr_events_handle(wmWindowManager *wm)
Definition wm_xr.cc:142
void wm_xr_exit(wmWindowManager *wm)
Definition wm_xr.cc:132
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)