The open source OpenXR runtime
at mr/scanout-values 782 lines 22 kB view raw
1// Copyright 2019-2024, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Multi client wrapper compositor. 6 * @author Pete Black <pblack@collabora.com> 7 * @author Jakob Bornecrantz <jakob@collabora.com> 8 * @author Korcan Hussein <korcan.hussein@collabora.com> 9 * @ingroup comp_multi 10 */ 11 12#include "xrt/xrt_config_os.h" 13#include "xrt/xrt_session.h" 14 15#include "os/os_time.h" 16#include "os/os_threading.h" 17 18#include "util/u_var.h" 19#include "util/u_misc.h" 20#include "util/u_time.h" 21#include "util/u_wait.h" 22#include "util/u_debug.h" 23#include "util/u_trace_marker.h" 24#include "util/u_distortion_mesh.h" 25 26#ifdef XRT_OS_LINUX 27#include "util/u_linux.h" 28#endif 29 30#include "multi/comp_multi_private.h" 31#include "multi/comp_multi_interface.h" 32 33#include <math.h> 34#include <stdio.h> 35#include <assert.h> 36#include <stdarg.h> 37#include <stdlib.h> 38#include <string.h> 39 40#ifdef XRT_GRAPHICS_SYNC_HANDLE_IS_FD 41#include <unistd.h> 42#endif 43 44 45/* 46 * 47 * Render thread. 48 * 49 */ 50 51static void 52do_projection_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) 53{ 54 struct xrt_device *xdev = layer->xdev; 55 56 // Cast away 57 struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; 58 59 // Do not need to copy the reference, but should verify the pointers for consistency 60 for (uint32_t j = 0; j < data->view_count; j++) { 61 if (layer->xscs[j] == NULL) { 62 U_LOG_E("Invalid swap chain for projection layer #%u!", i); 63 return; 64 } 65 } 66 67 if (xdev == NULL) { 68 U_LOG_E("Invalid xdev for projection layer #%u!", i); 69 return; 70 } 71 72 xrt_comp_layer_projection(xc, xdev, layer->xscs, data); 73} 74 75static void 76do_projection_layer_depth(struct xrt_compositor *xc, 77 struct multi_compositor *mc, 78 struct multi_layer_entry *layer, 79 uint32_t i) 80{ 81 struct xrt_device *xdev = layer->xdev; 82 83 struct xrt_swapchain *xsc[XRT_MAX_VIEWS]; 84 struct xrt_swapchain *d_xsc[XRT_MAX_VIEWS]; 85 // Cast away 86 struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; 87 88 for (uint32_t j = 0; j < data->view_count; j++) { 89 xsc[j] = layer->xscs[j]; 90 d_xsc[j] = layer->xscs[j + data->view_count]; 91 92 if (xsc[j] == NULL || d_xsc[j] == NULL) { 93 U_LOG_E("Invalid swap chain for projection layer #%u!", i); 94 return; 95 } 96 } 97 98 if (xdev == NULL) { 99 U_LOG_E("Invalid xdev for projection layer #%u!", i); 100 return; 101 } 102 103 104 xrt_comp_layer_projection_depth(xc, xdev, xsc, d_xsc, data); 105} 106 107static bool 108do_single(struct xrt_compositor *xc, 109 struct multi_compositor *mc, 110 struct multi_layer_entry *layer, 111 uint32_t i, 112 const char *name, 113 struct xrt_device **out_xdev, 114 struct xrt_swapchain **out_xcs, 115 struct xrt_layer_data **out_data) 116{ 117 struct xrt_device *xdev = layer->xdev; 118 struct xrt_swapchain *xcs = layer->xscs[0]; 119 120 if (xcs == NULL) { 121 U_LOG_E("Invalid swapchain for layer #%u '%s'!", i, name); 122 return false; 123 } 124 125 if (xdev == NULL) { 126 U_LOG_E("Invalid xdev for layer #%u '%s'!", i, name); 127 return false; 128 } 129 130 // Cast away 131 struct xrt_layer_data *data = (struct xrt_layer_data *)&layer->data; 132 133 *out_xdev = xdev; 134 *out_xcs = xcs; 135 *out_data = data; 136 137 return true; 138} 139 140static void 141do_quad_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) 142{ 143 struct xrt_device *xdev = NULL; 144 struct xrt_swapchain *xcs = NULL; 145 struct xrt_layer_data *data = NULL; 146 147 if (!do_single(xc, mc, layer, i, "quad", &xdev, &xcs, &data)) { 148 return; 149 } 150 151 xrt_comp_layer_quad(xc, xdev, xcs, data); 152} 153 154static void 155do_cube_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) 156{ 157 struct xrt_device *xdev = NULL; 158 struct xrt_swapchain *xcs = NULL; 159 struct xrt_layer_data *data = NULL; 160 161 if (!do_single(xc, mc, layer, i, "cube", &xdev, &xcs, &data)) { 162 return; 163 } 164 165 xrt_comp_layer_cube(xc, xdev, xcs, data); 166} 167 168static void 169do_cylinder_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) 170{ 171 struct xrt_device *xdev = NULL; 172 struct xrt_swapchain *xcs = NULL; 173 struct xrt_layer_data *data = NULL; 174 175 if (!do_single(xc, mc, layer, i, "cylinder", &xdev, &xcs, &data)) { 176 return; 177 } 178 179 xrt_comp_layer_cylinder(xc, xdev, xcs, data); 180} 181 182static void 183do_equirect1_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) 184{ 185 struct xrt_device *xdev = NULL; 186 struct xrt_swapchain *xcs = NULL; 187 struct xrt_layer_data *data = NULL; 188 189 if (!do_single(xc, mc, layer, i, "equirect1", &xdev, &xcs, &data)) { 190 return; 191 } 192 193 xrt_comp_layer_equirect1(xc, xdev, xcs, data); 194} 195 196static void 197do_equirect2_layer(struct xrt_compositor *xc, struct multi_compositor *mc, struct multi_layer_entry *layer, uint32_t i) 198{ 199 struct xrt_device *xdev = NULL; 200 struct xrt_swapchain *xcs = NULL; 201 struct xrt_layer_data *data = NULL; 202 203 if (!do_single(xc, mc, layer, i, "equirect2", &xdev, &xcs, &data)) { 204 return; 205 } 206 207 xrt_comp_layer_equirect2(xc, xdev, xcs, data); 208} 209 210static int 211overlay_sort_func(const void *a, const void *b) 212{ 213 struct multi_compositor *mc_a = *(struct multi_compositor **)a; 214 struct multi_compositor *mc_b = *(struct multi_compositor **)b; 215 216 if (mc_a->state.z_order < mc_b->state.z_order) { 217 return -1; 218 } 219 220 if (mc_a->state.z_order > mc_b->state.z_order) { 221 return 1; 222 } 223 224 return 0; 225} 226 227static enum xrt_blend_mode 228find_active_blend_mode(struct multi_compositor **overlay_sorted_clients, size_t size) 229{ 230 if (overlay_sorted_clients == NULL) 231 return XRT_BLEND_MODE_OPAQUE; 232 233 const struct multi_compositor *first_visible = NULL; 234 for (size_t k = 0; k < size; ++k) { 235 const struct multi_compositor *mc = overlay_sorted_clients[k]; 236 assert(mc != NULL); 237 238 // if a focused client is found just return, "first_visible" has lower priority and can be ignored. 239 if (mc->state.focused) { 240 assert(mc->state.visible); 241 return mc->delivered.data.env_blend_mode; 242 } 243 244 if (first_visible == NULL && mc->state.visible) { 245 first_visible = mc; 246 } 247 } 248 if (first_visible != NULL) 249 return first_visible->delivered.data.env_blend_mode; 250 return XRT_BLEND_MODE_OPAQUE; 251} 252 253static void 254transfer_layers_locked(struct multi_system_compositor *msc, int64_t display_time_ns, int64_t system_frame_id) 255{ 256 COMP_TRACE_MARKER(); 257 258 struct xrt_compositor *xc = &msc->xcn->base; 259 260 struct multi_compositor *array[MULTI_MAX_CLIENTS] = {0}; 261 262 // To mark latching. 263 int64_t now_ns = os_monotonic_get_ns(); 264 265 size_t count = 0; 266 for (size_t k = 0; k < ARRAY_SIZE(array); k++) { 267 struct multi_compositor *mc = msc->clients[k]; 268 269 // Array can be empty 270 if (mc == NULL) { 271 continue; 272 } 273 274 // Even if it's not shown, make sure that frames are delivered. 275 multi_compositor_deliver_any_frames(mc, display_time_ns); 276 277 // None of the data in this slot is valid, don't check access it. 278 if (!mc->delivered.active) { 279 continue; 280 } 281 282 // The client isn't visible, do not submit it's layers. 283 if (!mc->state.visible) { 284 // Need to drop delivered frame as it shouldn't be reused. 285 multi_compositor_retire_delivered_locked(mc, now_ns); 286 continue; 287 } 288 289 // Just in case. 290 if (!mc->state.session_active) { 291 U_LOG_W("Session is visible but not active."); 292 293 // Need to drop delivered frame as it shouldn't be reused. 294 multi_compositor_retire_delivered_locked(mc, now_ns); 295 continue; 296 } 297 298 // The list_and_timing_lock is held when callign this function. 299 multi_compositor_latch_frame_locked(mc, now_ns, system_frame_id); 300 301 array[count++] = msc->clients[k]; 302 } 303 304 // Sort the stack array 305 qsort(array, count, sizeof(struct multi_compositor *), overlay_sort_func); 306 307 // find first (ordered by bottom to top) active client to retrieve xrt_layer_frame_data 308 const enum xrt_blend_mode blend_mode = find_active_blend_mode(array, count); 309 310 const struct xrt_layer_frame_data data = { 311 .frame_id = system_frame_id, 312 .display_time_ns = display_time_ns, 313 .env_blend_mode = blend_mode, 314 }; 315 xrt_comp_layer_begin(xc, &data); 316 317 // Copy all active layers. 318 for (size_t k = 0; k < count; k++) { 319 struct multi_compositor *mc = array[k]; 320 assert(mc != NULL); 321 322 for (uint32_t i = 0; i < mc->delivered.layer_count; i++) { 323 struct multi_layer_entry *layer = &mc->delivered.layers[i]; 324 325 switch (layer->data.type) { 326 case XRT_LAYER_PROJECTION: do_projection_layer(xc, mc, layer, i); break; 327 case XRT_LAYER_PROJECTION_DEPTH: do_projection_layer_depth(xc, mc, layer, i); break; 328 case XRT_LAYER_QUAD: do_quad_layer(xc, mc, layer, i); break; 329 case XRT_LAYER_CUBE: do_cube_layer(xc, mc, layer, i); break; 330 case XRT_LAYER_CYLINDER: do_cylinder_layer(xc, mc, layer, i); break; 331 case XRT_LAYER_EQUIRECT1: do_equirect1_layer(xc, mc, layer, i); break; 332 case XRT_LAYER_EQUIRECT2: do_equirect2_layer(xc, mc, layer, i); break; 333 default: U_LOG_E("Unhandled layer type '%i'!", layer->data.type); break; 334 } 335 } 336 } 337} 338 339static void 340broadcast_timings_to_clients(struct multi_system_compositor *msc, int64_t predicted_display_time_ns) 341{ 342 COMP_TRACE_MARKER(); 343 344 os_mutex_lock(&msc->list_and_timing_lock); 345 346 for (size_t i = 0; i < ARRAY_SIZE(msc->clients); i++) { 347 struct multi_compositor *mc = msc->clients[i]; 348 if (mc == NULL) { 349 continue; 350 } 351 352 os_mutex_lock(&mc->slot_lock); 353 mc->slot_next_frame_display = predicted_display_time_ns; 354 os_mutex_unlock(&mc->slot_lock); 355 } 356 357 os_mutex_unlock(&msc->list_and_timing_lock); 358} 359 360static void 361broadcast_timings_to_pacers(struct multi_system_compositor *msc, 362 int64_t predicted_display_time_ns, 363 int64_t predicted_display_period_ns, 364 int64_t diff_ns) 365{ 366 COMP_TRACE_MARKER(); 367 368 os_mutex_lock(&msc->list_and_timing_lock); 369 370 for (size_t i = 0; i < ARRAY_SIZE(msc->clients); i++) { 371 struct multi_compositor *mc = msc->clients[i]; 372 if (mc == NULL) { 373 continue; 374 } 375 376 u_pa_info( // 377 mc->upa, // 378 predicted_display_time_ns, // 379 predicted_display_period_ns, // 380 diff_ns); // 381 382 os_mutex_lock(&mc->slot_lock); 383 mc->slot_next_frame_display = predicted_display_time_ns; 384 os_mutex_unlock(&mc->slot_lock); 385 } 386 387 msc->last_timings.predicted_display_time_ns = predicted_display_time_ns; 388 msc->last_timings.predicted_display_period_ns = predicted_display_period_ns; 389 msc->last_timings.diff_ns = diff_ns; 390 391 os_mutex_unlock(&msc->list_and_timing_lock); 392} 393 394static void 395wait_frame(struct os_precise_sleeper *sleeper, struct xrt_compositor *xc, int64_t frame_id, int64_t wake_up_time_ns) 396{ 397 COMP_TRACE_MARKER(); 398 399 // Wait until the given wake up time. 400 u_wait_until(sleeper, wake_up_time_ns); 401 402 int64_t now_ns = os_monotonic_get_ns(); 403 404 // Signal that we woke up. 405 xrt_comp_mark_frame(xc, frame_id, XRT_COMPOSITOR_FRAME_POINT_WOKE, now_ns); 406} 407 408static void 409update_session_state_locked(struct multi_system_compositor *msc) 410{ 411 struct xrt_compositor *xc = &msc->xcn->base; 412 413 //! @todo Make this not be hardcoded. 414 const struct xrt_begin_session_info begin_session_info = { 415 .view_type = XRT_VIEW_TYPE_STEREO, 416 .ext_hand_tracking_enabled = false, 417 .ext_hand_tracking_data_source_enabled = false, 418 .ext_eye_gaze_interaction_enabled = false, 419 .ext_hand_interaction_enabled = false, 420 .htc_facial_tracking_enabled = false, 421 .fb_body_tracking_enabled = false, 422 .fb_face_tracking2_enabled = false, 423 .meta_body_tracking_full_body_enabled = false, 424 .meta_body_tracking_calibration_enabled = false, 425 }; 426 427 switch (msc->sessions.state) { 428 case MULTI_SYSTEM_STATE_INIT_WARM_START: 429 // Produce at least one frame on init. 430 msc->sessions.state = MULTI_SYSTEM_STATE_STOPPING; 431 xrt_comp_begin_session(xc, &begin_session_info); 432 U_LOG_I("Doing warm start, %u active app session(s).", (uint32_t)msc->sessions.active_count); 433 break; 434 435 case MULTI_SYSTEM_STATE_STOPPED: 436 if (msc->sessions.active_count == 0) { 437 break; 438 } 439 440 msc->sessions.state = MULTI_SYSTEM_STATE_RUNNING; 441 xrt_comp_begin_session(xc, &begin_session_info); 442 U_LOG_I("Started native session, %u active app session(s).", (uint32_t)msc->sessions.active_count); 443 break; 444 445 case MULTI_SYSTEM_STATE_RUNNING: 446 if (msc->sessions.active_count > 0) { 447 break; 448 } 449 450 msc->sessions.state = MULTI_SYSTEM_STATE_STOPPING; 451 U_LOG_D("Stopping native session, %u active app session(s).", (uint32_t)msc->sessions.active_count); 452 break; 453 454 case MULTI_SYSTEM_STATE_STOPPING: 455 // Just in case 456 if (msc->sessions.active_count > 0) { 457 msc->sessions.state = MULTI_SYSTEM_STATE_RUNNING; 458 U_LOG_D("Restarting native session, %u active app session(s).", 459 (uint32_t)msc->sessions.active_count); 460 break; 461 } 462 463 msc->sessions.state = MULTI_SYSTEM_STATE_STOPPED; 464 xrt_comp_end_session(xc); 465 U_LOG_I("Stopped native session, %u active app session(s).", (uint32_t)msc->sessions.active_count); 466 break; 467 468 case MULTI_SYSTEM_STATE_INVALID: 469 default: 470 U_LOG_E("Got invalid state %u", msc->sessions.state); 471 msc->sessions.state = MULTI_SYSTEM_STATE_STOPPING; 472 assert(false); 473 } 474} 475 476static int 477multi_main_loop(struct multi_system_compositor *msc) 478{ 479 U_TRACE_SET_THREAD_NAME("Multi Client Module"); 480 os_thread_helper_name(&msc->oth, "Multi Client Module"); 481 482#ifdef XRT_OS_LINUX 483 // Try to raise priority of this thread. 484 u_linux_try_to_set_realtime_priority_on_thread(U_LOGGING_INFO, "Multi Client Module"); 485#endif 486 487 struct xrt_compositor *xc = &msc->xcn->base; 488 489 // For wait frame. 490 struct os_precise_sleeper sleeper = {0}; 491 os_precise_sleeper_init(&sleeper); 492 493 // Protect the thread state and the sessions state. 494 os_thread_helper_lock(&msc->oth); 495 496 while (os_thread_helper_is_running_locked(&msc->oth)) { 497 498 // Updates msc->sessions.active depending on active client sessions. 499 update_session_state_locked(msc); 500 501 if (msc->sessions.state == MULTI_SYSTEM_STATE_STOPPED) { 502 // Sleep and wait to be signaled. 503 os_thread_helper_wait_locked(&msc->oth); 504 505 // Loop back to running and session check. 506 continue; 507 } 508 509 // Unlock the thread after the checks has been done. 510 os_thread_helper_unlock(&msc->oth); 511 512 int64_t frame_id = -1; 513 int64_t wake_up_time_ns = 0; 514 int64_t predicted_gpu_time_ns = 0; 515 int64_t predicted_display_time_ns = 0; 516 int64_t predicted_display_period_ns = 0; 517 518 // Get the information for the next frame. 519 xrt_comp_predict_frame( // 520 xc, // 521 &frame_id, // 522 &wake_up_time_ns, // 523 &predicted_gpu_time_ns, // 524 &predicted_display_time_ns, // 525 &predicted_display_period_ns); // 526 527 // Do this as soon as we have the new display time. 528 broadcast_timings_to_clients(msc, predicted_display_time_ns); 529 530 // Now we can wait. 531 wait_frame(&sleeper, xc, frame_id, wake_up_time_ns); 532 533 int64_t now_ns = os_monotonic_get_ns(); 534 int64_t diff_ns = predicted_display_time_ns - now_ns; 535 536 // Now we know the diff, broadcast to pacers. 537 broadcast_timings_to_pacers(msc, predicted_display_time_ns, predicted_display_period_ns, diff_ns); 538 539 xrt_comp_begin_frame(xc, frame_id); 540 541 // Make sure that the clients doesn't go away while we transfer layers. 542 os_mutex_lock(&msc->list_and_timing_lock); 543 transfer_layers_locked(msc, predicted_display_time_ns, frame_id); 544 os_mutex_unlock(&msc->list_and_timing_lock); 545 546 xrt_comp_layer_commit(xc, XRT_GRAPHICS_SYNC_HANDLE_INVALID); 547 548 // Re-lock the thread for check in while statement. 549 os_thread_helper_lock(&msc->oth); 550 } 551 552 // Clean up the sessions state. 553 switch (msc->sessions.state) { 554 case MULTI_SYSTEM_STATE_RUNNING: 555 case MULTI_SYSTEM_STATE_STOPPING: 556 U_LOG_I("Stopped native session, shutting down."); 557 xrt_comp_end_session(xc); 558 break; 559 case MULTI_SYSTEM_STATE_STOPPED: break; 560 default: assert(false); 561 } 562 563 os_thread_helper_unlock(&msc->oth); 564 565 os_precise_sleeper_deinit(&sleeper); 566 567 return 0; 568} 569 570static void * 571thread_func(void *ptr) 572{ 573 return (void *)(intptr_t)multi_main_loop((struct multi_system_compositor *)ptr); 574} 575 576 577/* 578 * 579 * System multi compositor functions. 580 * 581 */ 582 583static xrt_result_t 584system_compositor_set_state(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible, bool focused) 585{ 586 struct multi_system_compositor *msc = multi_system_compositor(xsc); 587 struct multi_compositor *mc = multi_compositor(xc); 588 (void)msc; 589 590 //! @todo Locking? 591 if (mc->state.visible != visible || mc->state.focused != focused) { 592 mc->state.visible = visible; 593 mc->state.focused = focused; 594 595 union xrt_session_event xse = XRT_STRUCT_INIT; 596 xse.type = XRT_SESSION_EVENT_STATE_CHANGE; 597 xse.state.visible = visible; 598 xse.state.focused = focused; 599 600 return multi_compositor_push_event(mc, &xse); 601 } 602 603 return XRT_SUCCESS; 604} 605 606static xrt_result_t 607system_compositor_set_z_order(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, int64_t z_order) 608{ 609 struct multi_system_compositor *msc = multi_system_compositor(xsc); 610 struct multi_compositor *mc = multi_compositor(xc); 611 (void)msc; 612 613 //! @todo Locking? 614 mc->state.z_order = z_order; 615 616 return XRT_SUCCESS; 617} 618 619static xrt_result_t 620system_compositor_set_main_app_visibility(struct xrt_system_compositor *xsc, struct xrt_compositor *xc, bool visible) 621{ 622 struct multi_system_compositor *msc = multi_system_compositor(xsc); 623 struct multi_compositor *mc = multi_compositor(xc); 624 (void)msc; 625 626 union xrt_session_event xse = XRT_STRUCT_INIT; 627 xse.type = XRT_SESSION_EVENT_OVERLAY_CHANGE; 628 xse.overlay.visible = visible; 629 630 return multi_compositor_push_event(mc, &xse); 631} 632 633static xrt_result_t 634system_compositor_notify_loss_pending(struct xrt_system_compositor *xsc, 635 struct xrt_compositor *xc, 636 int64_t loss_time_ns) 637{ 638 struct multi_system_compositor *msc = multi_system_compositor(xsc); 639 struct multi_compositor *mc = multi_compositor(xc); 640 (void)msc; 641 642 union xrt_session_event xse = XRT_STRUCT_INIT; 643 xse.type = XRT_SESSION_EVENT_LOSS_PENDING; 644 xse.loss_pending.loss_time_ns = loss_time_ns; 645 646 return multi_compositor_push_event(mc, &xse); 647} 648 649static xrt_result_t 650system_compositor_notify_lost(struct xrt_system_compositor *xsc, struct xrt_compositor *xc) 651{ 652 struct multi_system_compositor *msc = multi_system_compositor(xsc); 653 struct multi_compositor *mc = multi_compositor(xc); 654 (void)msc; 655 656 union xrt_session_event xse = XRT_STRUCT_INIT; 657 xse.type = XRT_SESSION_EVENT_LOST; 658 659 return multi_compositor_push_event(mc, &xse); 660} 661 662static xrt_result_t 663system_compositor_notify_display_refresh_changed(struct xrt_system_compositor *xsc, 664 struct xrt_compositor *xc, 665 float from_display_refresh_rate_hz, 666 float to_display_refresh_rate_hz) 667{ 668 struct multi_system_compositor *msc = multi_system_compositor(xsc); 669 struct multi_compositor *mc = multi_compositor(xc); 670 (void)msc; 671 672 union xrt_session_event xse = XRT_STRUCT_INIT; 673 xse.type = XRT_SESSION_EVENT_DISPLAY_REFRESH_RATE_CHANGE; 674 xse.display.from_display_refresh_rate_hz = from_display_refresh_rate_hz; 675 xse.display.to_display_refresh_rate_hz = to_display_refresh_rate_hz; 676 677 return multi_compositor_push_event(mc, &xse); 678} 679 680 681/* 682 * 683 * System compositor functions. 684 * 685 */ 686 687static xrt_result_t 688system_compositor_create_native_compositor(struct xrt_system_compositor *xsc, 689 const struct xrt_session_info *xsi, 690 struct xrt_session_event_sink *xses, 691 struct xrt_compositor_native **out_xcn) 692{ 693 struct multi_system_compositor *msc = multi_system_compositor(xsc); 694 695 return multi_compositor_create(msc, xsi, xses, out_xcn); 696} 697 698static void 699system_compositor_destroy(struct xrt_system_compositor *xsc) 700{ 701 struct multi_system_compositor *msc = multi_system_compositor(xsc); 702 703 // Destroy the render thread first, destroy also stops the thread. 704 os_thread_helper_destroy(&msc->oth); 705 706 u_paf_destroy(&msc->upaf); 707 708 xrt_comp_native_destroy(&msc->xcn); 709 710 os_mutex_destroy(&msc->list_and_timing_lock); 711 712 free(msc); 713} 714 715 716/* 717 * 718 * 'Exported' functions. 719 * 720 */ 721 722void 723multi_system_compositor_update_session_status(struct multi_system_compositor *msc, bool active) 724{ 725 os_thread_helper_lock(&msc->oth); 726 727 if (active) { 728 assert(msc->sessions.active_count < UINT32_MAX); 729 msc->sessions.active_count++; 730 731 // If the thread is sleeping wake it up. 732 os_thread_helper_signal_locked(&msc->oth); 733 } else { 734 assert(msc->sessions.active_count > 0); 735 msc->sessions.active_count--; 736 } 737 738 os_thread_helper_unlock(&msc->oth); 739} 740 741xrt_result_t 742comp_multi_create_system_compositor(struct xrt_compositor_native *xcn, 743 struct u_pacing_app_factory *upaf, 744 const struct xrt_system_compositor_info *xsci, 745 bool do_warm_start, 746 struct xrt_system_compositor **out_xsysc) 747{ 748 struct multi_system_compositor *msc = U_TYPED_CALLOC(struct multi_system_compositor); 749 msc->base.create_native_compositor = system_compositor_create_native_compositor; 750 msc->base.destroy = system_compositor_destroy; 751 msc->xmcc.set_state = system_compositor_set_state; 752 msc->xmcc.set_z_order = system_compositor_set_z_order; 753 msc->xmcc.set_main_app_visibility = system_compositor_set_main_app_visibility; 754 msc->xmcc.notify_loss_pending = system_compositor_notify_loss_pending; 755 msc->xmcc.notify_lost = system_compositor_notify_lost; 756 msc->xmcc.notify_display_refresh_changed = system_compositor_notify_display_refresh_changed; 757 msc->base.xmcc = &msc->xmcc; 758 msc->base.info = *xsci; 759 msc->upaf = upaf; 760 msc->xcn = xcn; 761 msc->sessions.active_count = 0; 762 msc->sessions.state = do_warm_start ? MULTI_SYSTEM_STATE_INIT_WARM_START : MULTI_SYSTEM_STATE_STOPPED; 763 764 os_mutex_init(&msc->list_and_timing_lock); 765 766 //! @todo Make the clients not go from IDLE to READY before we have completed a first frame. 767 // Make sure there is at least some sort of valid frame data here. 768 msc->last_timings.predicted_display_time_ns = os_monotonic_get_ns(); // As good as any time. 769 msc->last_timings.predicted_display_period_ns = U_TIME_1MS_IN_NS * 16; // Just a wild guess. 770 msc->last_timings.diff_ns = U_TIME_1MS_IN_NS * 5; // Make sure it's not zero at least. 771 772 int ret = os_thread_helper_init(&msc->oth); 773 if (ret < 0) { 774 return XRT_ERROR_THREADING_INIT_FAILURE; 775 } 776 777 os_thread_helper_start(&msc->oth, thread_func, msc); 778 779 *out_xsysc = &msc->base; 780 781 return XRT_SUCCESS; 782}