diff options
Diffstat (limited to 'source/blender/windowmanager/xr/intern/wm_xr.c')
-rw-r--r-- | source/blender/windowmanager/xr/intern/wm_xr.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/source/blender/windowmanager/xr/intern/wm_xr.c b/source/blender/windowmanager/xr/intern/wm_xr.c new file mode 100644 index 00000000000..69c9034d51f --- /dev/null +++ b/source/blender/windowmanager/xr/intern/wm_xr.c @@ -0,0 +1,163 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup wm + * + * All XR functionality is accessed through a #GHOST_XrContext handle. + * The lifetime of this context also determines the lifetime of the OpenXR instance, which is the + * representation of the OpenXR runtime connection within the application. + */ + +#include "BKE_global.h" +#include "BKE_idprop.h" +#include "BKE_report.h" + +#include "DNA_scene_types.h" +#include "DNA_windowmanager_types.h" + +#include "DEG_depsgraph.h" + +#include "MEM_guardedalloc.h" + +#include "GHOST_C-api.h" + +#include "WM_api.h" + +#include "wm_surface.h" +#include "wm_xr_intern.h" + +typedef struct { + wmWindowManager *wm; +} wmXrErrorHandlerData; + +/* -------------------------------------------------------------------- */ + +static void wm_xr_error_handler(const GHOST_XrError *error) +{ + wmXrErrorHandlerData *handler_data = error->customdata; + wmWindowManager *wm = handler_data->wm; + + BKE_reports_clear(&wm->reports); + WM_report(RPT_ERROR, error->user_message); + WM_report_banner_show(); + + if (wm->xr.runtime) { + /* Just play safe and destroy the entire runtime data, including context. */ + wm_xr_runtime_data_free(&wm->xr.runtime); + } +} + +bool wm_xr_init(wmWindowManager *wm) +{ + if (wm->xr.runtime && wm->xr.runtime->context) { + return true; + } + static wmXrErrorHandlerData error_customdata; + + /* Set up error handling */ + error_customdata.wm = wm; + GHOST_XrErrorHandler(wm_xr_error_handler, &error_customdata); + + { + const GHOST_TXrGraphicsBinding gpu_bindings_candidates[] = { + GHOST_kXrGraphicsOpenGL, +#ifdef WIN32 + GHOST_kXrGraphicsD3D11, +#endif + }; + GHOST_XrContextCreateInfo create_info = { + .gpu_binding_candidates = gpu_bindings_candidates, + .gpu_binding_candidates_count = ARRAY_SIZE(gpu_bindings_candidates), + }; + GHOST_XrContextHandle context; + + if (G.debug & G_DEBUG_XR) { + create_info.context_flag |= GHOST_kXrContextDebug; + } + if (G.debug & G_DEBUG_XR_TIME) { + create_info.context_flag |= GHOST_kXrContextDebugTime; + } + + if (!(context = GHOST_XrContextCreate(&create_info))) { + return false; + } + + /* Set up context callbacks */ + GHOST_XrGraphicsContextBindFuncs(context, + wm_xr_session_gpu_binding_context_create, + wm_xr_session_gpu_binding_context_destroy); + GHOST_XrDrawViewFunc(context, wm_xr_draw_view); + + if (!wm->xr.runtime) { + wm->xr.runtime = wm_xr_runtime_data_create(); + wm->xr.runtime->context = context; + } + } + BLI_assert(wm->xr.runtime && wm->xr.runtime->context); + + return true; +} + +void wm_xr_exit(wmWindowManager *wm) +{ + if (wm->xr.runtime != NULL) { + wm_xr_runtime_data_free(&wm->xr.runtime); + } + if (wm->xr.session_settings.shading.prop) { + IDP_FreeProperty(wm->xr.session_settings.shading.prop); + wm->xr.session_settings.shading.prop = NULL; + } +} + +bool wm_xr_events_handle(wmWindowManager *wm) +{ + if (wm->xr.runtime && wm->xr.runtime->context) { + return GHOST_XrEventsHandle(wm->xr.runtime->context); + } + return false; +} + +/* -------------------------------------------------------------------- */ +/** \name XR Runtime Data + * + * \{ */ + +wmXrRuntimeData *wm_xr_runtime_data_create(void) +{ + wmXrRuntimeData *runtime = MEM_callocN(sizeof(*runtime), __func__); + return runtime; +} + +void wm_xr_runtime_data_free(wmXrRuntimeData **runtime) +{ + /* Note that this function may be called twice, because of an indirect recursion: If a session is + * running while WM-XR calls this function, calling GHOST_XrContextDestroy() will call this + * again, because it's also set as the session exit callback. So NULL-check and NULL everything + * that is freed here. */ + + /* We free all runtime XR data here, so if the context is still alive, destroy it. */ + if ((*runtime)->context != NULL) { + GHOST_XrContextHandle context = (*runtime)->context; + /* Prevent recursive GHOST_XrContextDestroy() call by NULL'ing the context pointer before the + * first call, see comment above. */ + (*runtime)->context = NULL; + GHOST_XrContextDestroy(context); + } + MEM_SAFE_FREE(*runtime); +} + +/** \} */ /* XR Runtime Data */ |