Blender  V2.93
wm_xr_session.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include "BKE_context.h"
22 #include "BKE_main.h"
23 #include "BKE_scene.h"
24 
25 #include "BLI_listbase.h"
26 #include "BLI_math.h"
27 
28 #include "DEG_depsgraph.h"
29 
30 #include "DNA_camera_types.h"
31 
32 #include "DRW_engine.h"
33 
34 #include "GHOST_C-api.h"
35 
36 #include "GPU_viewport.h"
37 
38 #include "MEM_guardedalloc.h"
39 
40 #include "WM_api.h"
41 #include "WM_types.h"
42 
43 #include "wm_surface.h"
44 #include "wm_window.h"
45 #include "wm_xr_intern.h"
46 
48 static CLG_LogRef LOG = {"wm.xr"};
49 
50 /* -------------------------------------------------------------------- */
51 
52 static void wm_xr_session_exit_cb(void *customdata)
53 {
54  wmXrData *xr_data = customdata;
55 
56  xr_data->runtime->session_state.is_started = false;
57  if (xr_data->runtime->exit_fn) {
58  xr_data->runtime->exit_fn(xr_data);
59  }
60 
61  /* Free the entire runtime data (including session state and context), to play safe. */
63 }
64 
66  GHOST_XrSessionBeginInfo *r_begin_info)
67 {
68  /* WM-XR exit function, does some own stuff and calls callback passed to wm_xr_session_toggle(),
69  * to allow external code to execute its own session-exit logic. */
70  r_begin_info->exit_fn = wm_xr_session_exit_cb;
71  r_begin_info->exit_customdata = xr_data;
72 }
73 
75  wmWindow *session_root_win,
76  wmXrSessionExitFn session_exit_fn)
77 {
78  wmXrData *xr_data = &wm->xr;
79 
80  if (WM_xr_session_exists(xr_data)) {
81  GHOST_XrSessionEnd(xr_data->runtime->context);
82  }
83  else {
84  GHOST_XrSessionBeginInfo begin_info;
85 
86  xr_data->runtime->session_root_win = session_root_win;
87  xr_data->runtime->session_state.is_started = true;
88  xr_data->runtime->exit_fn = session_exit_fn;
89 
90  wm_xr_session_begin_info_create(xr_data, &begin_info);
91  GHOST_XrSessionStart(xr_data->runtime->context, &begin_info);
92  }
93 }
94 
100 {
101  return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started;
102 }
103 
105 {
107 }
108 
113 {
114  return WM_xr_session_exists(xr) && GHOST_XrSessionIsRunning(xr->runtime->context);
115 }
116 
118  const XrSessionSettings *settings,
119  GHOST_XrPose *r_base_pose)
120 {
121  const Object *base_pose_object = ((settings->base_pose_type == XR_BASE_POSE_OBJECT) &&
122  settings->base_pose_object) ?
123  settings->base_pose_object :
124  scene->camera;
125 
126  if (settings->base_pose_type == XR_BASE_POSE_CUSTOM) {
127  float tmp_quatx[4], tmp_quatz[4];
128 
129  copy_v3_v3(r_base_pose->position, settings->base_pose_location);
130  axis_angle_to_quat_single(tmp_quatx, 'X', M_PI_2);
131  axis_angle_to_quat_single(tmp_quatz, 'Z', settings->base_pose_angle);
132  mul_qt_qtqt(r_base_pose->orientation_quat, tmp_quatz, tmp_quatx);
133  }
134  else if (base_pose_object) {
135  float tmp_quat[4];
136  float tmp_eul[3];
137 
138  mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->obmat);
139 
140  /* Only use rotation around Z-axis to align view with floor. */
141  quat_to_eul(tmp_eul, tmp_quat);
142  tmp_eul[0] = M_PI_2;
143  tmp_eul[1] = 0;
144  eul_to_quat(r_base_pose->orientation_quat, tmp_eul);
145  }
146  else {
147  copy_v3_fl(r_base_pose->position, 0.0f);
148  axis_angle_to_quat_single(r_base_pose->orientation_quat, 'X', M_PI_2);
149  }
150 }
151 
153  Scene *scene,
155  wmXrDrawData *r_draw_data)
156 {
157  const XrSessionSettings *settings = &xr_data->session_settings;
158 
159  memset(r_draw_data, 0, sizeof(*r_draw_data));
160  r_draw_data->scene = scene;
161  r_draw_data->depsgraph = depsgraph;
162  r_draw_data->xr_data = xr_data;
163  r_draw_data->surface_data = g_xr_surface->customdata;
164 
165  wm_xr_session_base_pose_calc(r_draw_data->scene, settings, &r_draw_data->base_pose);
166 }
167 
169  const wmXrRuntimeData *runtime_data)
170 {
171  if (runtime_data->session_root_win &&
172  BLI_findindex(&wm->windows, runtime_data->session_root_win) != -1) {
173  /* Root window is still valid, use it. */
174  return runtime_data->session_root_win;
175  }
176  /* Otherwise, fallback. */
177  return wm->windows.first;
178 }
179 
188  const wmWindowManager *wm,
189  Scene **r_scene,
190  Depsgraph **r_depsgraph)
191 {
193 
194  /* Follow the scene & view layer shown in the root 3D View. */
196  ViewLayer *view_layer = WM_window_get_active_view_layer(root_win);
197 
199  BLI_assert(scene && view_layer && depsgraph);
201  *r_scene = scene;
202  *r_depsgraph = depsgraph;
203 }
204 
205 typedef enum wmXrSessionStateEvent {
211 
213  const XrSessionSettings *settings)
214 {
215  if (state->force_reset_to_base_pose) {
216  return true;
217  }
218  return ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) &&
219  ((state->prev_base_pose_type != settings->base_pose_type) ||
220  (state->prev_base_pose_object != settings->base_pose_object));
221 }
222 
224  const XrSessionSettings *settings)
225 {
226  if (!state->is_view_data_set) {
228  }
231  }
232 
233  const bool position_tracking_toggled = ((state->prev_settings_flag &
235  (settings->flag & XR_SESSION_USE_POSITION_TRACKING));
236  if (position_tracking_toggled) {
238  }
239 
241 }
242 
244  const XrSessionSettings *settings,
245  const GHOST_XrDrawViewInfo *draw_view,
246  wmXrDrawData *draw_data)
247 {
249  const bool use_position_tracking = (settings->flag & XR_SESSION_USE_POSITION_TRACKING);
250 
251  switch (event) {
253  if (use_position_tracking) {
254  /* We want to start the session exactly at landmark position.
255  * Run-times may have a non-[0,0,0] starting position that we have to subtract for that. */
256  copy_v3_v3(draw_data->eye_position_ofs, draw_view->local_pose.position);
257  }
258  else {
259  copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
260  }
261  break;
262  /* This should be triggered by the VR add-on if a landmark changes. */
264  if (use_position_tracking) {
265  /* Switch exactly to base pose, so use eye offset to cancel out current position delta. */
266  copy_v3_v3(draw_data->eye_position_ofs, draw_view->local_pose.position);
267  }
268  else {
269  copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
270  }
271  break;
273  if (use_position_tracking) {
274  /* Keep the current position, and let the user move from there. */
275  copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs);
276  }
277  else {
278  /* Back to the exact base-pose position. */
279  copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
280  }
281  break;
283  /* Keep previous offset when positional tracking is disabled. */
284  copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs);
285  break;
286  }
287 }
288 
294  const wmXrDrawData *draw_data,
295  const GHOST_XrDrawViewInfo *draw_view,
297 {
298  GHOST_XrPose viewer_pose;
299  const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING;
300 
301  mul_qt_qtqt(viewer_pose.orientation_quat,
302  draw_data->base_pose.orientation_quat,
303  draw_view->local_pose.orientation_quat);
304  copy_v3_v3(viewer_pose.position, draw_data->base_pose.position);
305  /* The local pose and the eye pose (which is copied from an earlier local pose) both are view
306  * space, so Y-up. In this case we need them in regular Z-up. */
307  viewer_pose.position[0] -= draw_data->eye_position_ofs[0];
308  viewer_pose.position[1] += draw_data->eye_position_ofs[2];
309  viewer_pose.position[2] -= draw_data->eye_position_ofs[1];
310  if (use_position_tracking) {
311  viewer_pose.position[0] += draw_view->local_pose.position[0];
312  viewer_pose.position[1] -= draw_view->local_pose.position[2];
313  viewer_pose.position[2] += draw_view->local_pose.position[1];
314  }
315 
316  copy_v3_v3(state->viewer_pose.position, viewer_pose.position);
317  copy_qt_qt(state->viewer_pose.orientation_quat, viewer_pose.orientation_quat);
318  wm_xr_pose_to_viewmat(&viewer_pose, state->viewer_viewmat);
319  /* No idea why, but multiplying by two seems to make it match the VR view more. */
320  state->focal_len = 2.0f *
321  fov_to_focallength(draw_view->fov.angle_right - draw_view->fov.angle_left,
323 
324  copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
325  state->prev_settings_flag = settings->flag;
326  state->prev_base_pose_type = settings->base_pose_type;
327  state->prev_base_pose_object = settings->base_pose_object;
328  state->is_view_data_set = true;
329  /* Assume this was already done through wm_xr_session_draw_data_update(). */
330  state->force_reset_to_base_pose = false;
331 }
332 
334 {
335  return xr->runtime ? &xr->runtime->session_state : NULL;
336 }
337 
338 bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3])
339 {
341  zero_v3(r_location);
342  return false;
343  }
344 
345  copy_v3_v3(r_location, xr->runtime->session_state.viewer_pose.position);
346  return true;
347 }
348 
349 bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4])
350 {
352  unit_qt(r_rotation);
353  return false;
354  }
355 
356  copy_v4_v4(r_rotation, xr->runtime->session_state.viewer_pose.orientation_quat);
357  return true;
358 }
359 
361  float r_viewmat[4][4],
362  float *r_focal_len)
363 {
365  unit_m4(r_viewmat);
366  *r_focal_len = 0.0f;
367  return false;
368  }
369 
371  *r_focal_len = xr->runtime->session_state.focal_len;
372 
373  return true;
374 }
375 
376 /* -------------------------------------------------------------------- */
392 {
393  wmXrSurfaceData *surface_data = g_xr_surface->customdata;
395  Main *bmain = CTX_data_main(C);
396  wmXrDrawData draw_data;
397 
398  if (!GHOST_XrSessionIsRunning(wm->xr.runtime->context)) {
399  return;
400  }
401 
402  Scene *scene;
406 
407  GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data);
408 
409  GPU_offscreen_unbind(surface_data->offscreen, false);
410 }
411 
413  const GHOST_XrDrawViewInfo *draw_view)
414 {
415  const bool size_changed = surface_data->offscreen &&
416  (GPU_offscreen_width(surface_data->offscreen) != draw_view->width) &&
417  (GPU_offscreen_height(surface_data->offscreen) != draw_view->height);
418  char err_out[256] = "unknown";
419  bool failure = false;
420 
421  if (surface_data->offscreen) {
422  BLI_assert(surface_data->viewport);
423 
424  if (!size_changed) {
425  return true;
426  }
427  GPU_viewport_free(surface_data->viewport);
428  GPU_offscreen_free(surface_data->offscreen);
429  }
430 
431  if (!(surface_data->offscreen = GPU_offscreen_create(
432  draw_view->width, draw_view->height, true, false, err_out))) {
433  failure = true;
434  }
435 
436  if (failure) {
437  /* Pass. */
438  }
439  else if (!(surface_data->viewport = GPU_viewport_create())) {
440  GPU_offscreen_free(surface_data->offscreen);
441  failure = true;
442  }
443 
444  if (failure) {
445  CLOG_ERROR(&LOG, "Failed to get buffer, %s\n", err_out);
446  return false;
447  }
448 
449  return true;
450 }
451 
453 {
454  wmXrSurfaceData *data = surface->customdata;
455 
456  if (data->viewport) {
457  GPU_viewport_free(data->viewport);
458  }
459  if (data->offscreen) {
460  GPU_offscreen_free(data->offscreen);
461  }
462 
463  MEM_freeN(surface->customdata);
464 
465  g_xr_surface = NULL;
466 }
467 
469 {
470  if (g_xr_surface) {
471  BLI_assert(false);
472  return g_xr_surface;
473  }
474 
475  wmSurface *surface = MEM_callocN(sizeof(*surface), __func__);
476  wmXrSurfaceData *data = MEM_callocN(sizeof(*data), "XrSurfaceData");
477 
480  surface->activate = DRW_xr_drawing_begin;
481  surface->deactivate = DRW_xr_drawing_end;
482 
483  surface->ghost_ctx = DRW_xr_opengl_context_get();
484  surface->gpu_ctx = DRW_xr_gpu_context_get();
485 
486  surface->customdata = data;
487 
489 
490  return surface;
491 }
492 
494 {
496 
498 
499  /* Some regions may need to redraw with updated session state after the session is entirely up
500  * and running. */
502 
503  return surface->ghost_ctx;
504 }
505 
507 {
508  if (g_xr_surface) { /* Might have been freed already */
510  }
511 
513 
514  /* Some regions may need to redraw with updated session state after the session is entirely
515  * stopped. */
517 }
518  /* XR-Session Surface */
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct Depsgraph * BKE_scene_get_depsgraph(const struct Scene *scene, const struct ViewLayer *view_layer)
void BKE_scene_graph_evaluated_ensure(struct Depsgraph *depsgraph, struct Main *bmain)
Definition: scene.c:2718
#define BLI_assert(a)
Definition: BLI_assert.h:58
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define M_PI_2
Definition: BLI_math_base.h:41
void unit_m4(float m[4][4])
Definition: rct.c:1140
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4])
Definition: math_matrix.c:2247
void unit_qt(float q[4])
Definition: math_rotation.c:46
void eul_to_quat(float quat[4], const float eul[3])
void quat_to_eul(float eul[3], const float quat[4])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
Definition: math_rotation.c:65
void axis_angle_to_quat_single(float q[4], const char axis, const float angle)
float fov_to_focallength(float fov, float sensor)
void copy_qt_qt(float q[4], const float a[4])
Definition: math_rotation.c:52
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
#define UNUSED(x)
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:204
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
#define DEFAULT_SENSOR_WIDTH
@ XR_SESSION_USE_POSITION_TRACKING
Definition: DNA_xr_types.h:52
@ XR_BASE_POSE_CUSTOM
Definition: DNA_xr_types.h:58
@ XR_BASE_POSE_OBJECT
Definition: DNA_xr_types.h:57
GHOST C-API function and type declarations.
GPUViewport * GPU_viewport_create(void)
Definition: gpu_viewport.c:144
void GPU_viewport_free(GPUViewport *viewport)
Definition: gpu_viewport.c:978
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
#define NC_WM
Definition: WM_types.h:276
#define ND_XR_DATA_CHANGED
Definition: WM_types.h:317
Scene scene
const Depsgraph * depsgraph
struct @203::@204 surface
void GPU_offscreen_free(GPUOffScreen *ofs)
void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore)
GPUOffScreen * GPU_offscreen_create(int width, int height, bool depth, bool high_bitdepth, char err_out[256])
int GPU_offscreen_width(const GPUOffScreen *ofs)
int GPU_offscreen_height(const GPUOffScreen *ofs)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static ulong state[N]
struct SELECTID_Context context
Definition: select_engine.c:47
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
float obmat[4][4]
struct Object * camera
float base_pose_location[3]
Definition: DNA_xr_types.h:38
Object * base_pose_object
Definition: DNA_xr_types.h:37
void * customdata
Definition: wm_surface.h:39
XrSessionSettings session_settings
struct wmXrRuntimeData * runtime
wmXrData * xr_data
Definition: wm_xr_intern.h:70
float eye_position_ofs[3]
Definition: wm_xr_intern.h:79
struct Depsgraph * depsgraph
Definition: wm_xr_intern.h:68
GHOST_XrPose base_pose
Definition: wm_xr_intern.h:76
wmXrSurfaceData * surface_data
Definition: wm_xr_intern.h:71
struct Scene * scene
Definition: wm_xr_intern.h:67
GHOST_XrContextHandle context
Definition: wm_xr_intern.h:50
wmXrSessionExitFn exit_fn
Definition: wm_xr_intern.h:58
wmXrSessionState session_state
Definition: wm_xr_intern.h:57
wmWindow * session_root_win
Definition: wm_xr_intern.h:54
float viewer_viewmat[4][4]
Definition: wm_xr_intern.h:33
bool force_reset_to_base_pose
Definition: wm_xr_intern.h:45
GHOST_XrPose viewer_pose
Definition: wm_xr_intern.h:31
struct GPUViewport * viewport
Definition: wm_xr_intern.h:63
struct GPUOffScreen * offscreen
Definition: wm_xr_intern.h:62
void WM_main_add_notifier(unsigned int type, void *reference)
void wm_surface_add(wmSurface *surface)
Definition: wm_surface.c:103
void wm_surface_remove(wmSurface *surface)
Definition: wm_surface.c:108
void wm_window_reset_drawable(void)
Definition: wm_window.c:1074
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
Definition: wm_window.c:2286
Scene * WM_window_get_active_scene(const wmWindow *win)
Definition: wm_window.c:2249
void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
Definition: wm_xr.c:149
void(* wmXrSessionExitFn)(const wmXrData *xr_data)
Definition: wm_xr.h:26
void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4])
Definition: wm_xr_draw.c:40
static void wm_xr_session_scene_and_evaluated_depsgraph_get(Main *bmain, const wmWindowManager *wm, Scene **r_scene, Depsgraph **r_depsgraph)
static void wm_xr_session_base_pose_calc(const Scene *scene, const XrSessionSettings *settings, GHOST_XrPose *r_base_pose)
wmXrSessionState * WM_xr_session_state_handle_get(const wmXrData *xr)
void WM_xr_session_base_pose_reset(wmXrData *xr)
static wmSurface * wm_xr_session_surface_create(void)
static void wm_xr_session_exit_cb(void *customdata)
Definition: wm_xr_session.c:52
static wmXrSessionStateEvent wm_xr_session_state_to_event(const wmXrSessionState *state, const XrSessionSettings *settings)
void wm_xr_session_draw_data_update(const wmXrSessionState *state, const XrSessionSettings *settings, const GHOST_XrDrawViewInfo *draw_view, wmXrDrawData *draw_data)
static void wm_xr_session_surface_free_data(wmSurface *surface)
static wmSurface * g_xr_surface
Definition: wm_xr_session.c:47
void wm_xr_session_toggle(wmWindowManager *wm, wmWindow *session_root_win, wmXrSessionExitFn session_exit_fn)
Definition: wm_xr_session.c:74
static void wm_xr_session_surface_draw(bContext *C)
Call Ghost-XR to draw a frame.
void * wm_xr_session_gpu_binding_context_create(void)
void wm_xr_session_state_update(const XrSessionSettings *settings, const wmXrDrawData *draw_data, const GHOST_XrDrawViewInfo *draw_view, wmXrSessionState *state)
static bool wm_xr_session_draw_data_needs_reset_to_base_pose(const wmXrSessionState *state, const XrSessionSettings *settings)
bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr, float r_viewmat[4][4], float *r_focal_len)
static CLG_LogRef LOG
Definition: wm_xr_session.c:48
static wmWindow * wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm, const wmXrRuntimeData *runtime_data)
bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, const GHOST_XrDrawViewInfo *draw_view)
wmXrSessionStateEvent
@ SESSION_STATE_EVENT_NONE
@ SESSION_STATE_EVENT_START
@ SESSION_STATE_EVENT_POSITON_TRACKING_TOGGLE
@ SESSION_STATE_EVENT_RESET_TO_BASE_POSE
bool WM_xr_session_is_ready(const wmXrData *xr)
bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3])
bool WM_xr_session_exists(const wmXrData *xr)
Definition: wm_xr_session.c:99
static void wm_xr_session_begin_info_create(wmXrData *xr_data, GHOST_XrSessionBeginInfo *r_begin_info)
Definition: wm_xr_session.c:65
static void wm_xr_session_draw_data_populate(wmXrData *xr_data, Scene *scene, Depsgraph *depsgraph, wmXrDrawData *r_draw_data)
bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4])
void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle UNUSED(context))