The open source OpenXR runtime
at main 398 lines 9.5 kB view raw
1// Copyright 2021, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief System compositor capable of supporting multiple clients: internal structs. 6 * @author Jakob Bornecrantz <jakob@collabora.com> 7 * @ingroup comp_multi 8 */ 9 10#pragma once 11 12#include "xrt/xrt_compiler.h" 13#include "xrt/xrt_defines.h" 14#include "xrt/xrt_limits.h" 15#include "xrt/xrt_compositor.h" 16 17#include "os/os_time.h" 18#include "os/os_threading.h" 19 20#include "util/u_pacing.h" 21 22#ifdef __cplusplus 23extern "C" { 24#endif 25 26 27/*! 28 * Number of max active clients. 29 * 30 * @todo Move to `xrt_limits.h`, or make dynamic to remove limit. 31 * @ingroup comp_multi 32 */ 33#define MULTI_MAX_CLIENTS 64 34 35/*! 36 * Number of max active layers per @ref multi_compositor. 37 * 38 * @todo Move to `xrt_limits.h` and share. 39 * @ingroup comp_multi 40 */ 41#define MULTI_MAX_LAYERS XRT_MAX_LAYERS 42 43 44/* 45 * 46 * Native compositor. 47 * 48 */ 49 50/*! 51 * Data for a single composition layer. 52 * 53 * Similar in function to @ref comp_layer 54 * 55 * @ingroup comp_multi 56 */ 57struct multi_layer_entry 58{ 59 /*! 60 * Device to get pose from. 61 */ 62 struct xrt_device *xdev; 63 64 /*! 65 * Pointers to swapchains. 66 * 67 * How many are actually used depends on the value of @p data.type 68 */ 69 struct xrt_swapchain *xscs[2 * XRT_MAX_VIEWS]; 70 71 /*! 72 * All basic (trivially-serializable) data associated with a layer, 73 * aside from which swapchain(s) are used. 74 */ 75 struct xrt_layer_data data; 76}; 77 78/*! 79 * Render state for a single client, including all layers. 80 * 81 * @ingroup comp_multi 82 */ 83struct multi_layer_slot 84{ 85 struct xrt_layer_frame_data data; 86 uint32_t layer_count; 87 struct multi_layer_entry layers[MULTI_MAX_LAYERS]; 88 bool active; 89}; 90 91/*! 92 * A single compositor for feeding the layers from one session/app into 93 * the multi-client-capable system compositor. 94 * 95 * An instance (usually an IPC server instance) might have several of 96 * these at once, feeding layers to a single multi-client-capable system 97 * compositor. 98 * 99 * @ingroup comp_multi 100 * @implements xrt_compositor_native 101 */ 102struct multi_compositor 103{ 104 struct xrt_compositor_native base; 105 106 // Client info. 107 struct xrt_session_info xsi; 108 109 //! Where events for this compositor should go. 110 struct xrt_session_event_sink *xses; 111 112 //! Owning system compositor. 113 struct multi_system_compositor *msc; 114 115 //! Used to implement wait frame, only used for in process. 116 struct os_precise_sleeper frame_sleeper; 117 118 //! Used when waiting for the scheduled frame to complete. 119 struct os_precise_sleeper scheduled_sleeper; 120 121 struct 122 { 123 bool visible; 124 bool focused; 125 126 int64_t z_order; 127 128 bool session_active; 129 } state; 130 131 struct 132 { 133 //! Fence to wait for. 134 struct xrt_compositor_fence *xcf; 135 136 //! Timeline semaphore to wait for. 137 struct xrt_compositor_semaphore *xcsem; 138 139 //! Timeline semaphore value to wait for. 140 uint64_t value; 141 142 //! Frame id of frame being waited on. 143 int64_t frame_id; 144 145 //! The wait thread itself 146 struct os_thread_helper oth; 147 148 //! Have we gotten to the loop? 149 bool alive; 150 151 //! Is the thread waiting, if so the client should block. 152 bool waiting; 153 154 /*! 155 * Is the client thread blocked? 156 * 157 * Set to true by the client thread, 158 * cleared by the wait thread to release the client thread. 159 */ 160 bool blocked; 161 } wait_thread; 162 163 //! Lock for all of the slots. 164 struct os_mutex slot_lock; 165 166 /*! 167 * The next which the next frames to be picked up will be displayed. 168 */ 169 int64_t slot_next_frame_display; 170 171 /*! 172 * Currently being transferred or waited on. 173 * Not protected by the slot lock as it is only touched by the client thread. 174 */ 175 struct multi_layer_slot progress; 176 177 //! Scheduled frames for a future timepoint. 178 struct multi_layer_slot scheduled; 179 180 /*! 181 * Fully ready to be used. 182 * Not protected by the slot lock as it is only touched by the main render loop thread. 183 */ 184 struct multi_layer_slot delivered; 185 186 struct u_pacing_app *upa; 187 188 float current_refresh_rate_hz; 189}; 190 191/*! 192 * Small helper go from @ref xrt_compositor to @ref multi_compositor. 193 * 194 * @ingroup comp_multi 195 */ 196static inline struct multi_compositor * 197multi_compositor(struct xrt_compositor *xc) 198{ 199 return (struct multi_compositor *)xc; 200} 201 202/*! 203 * Create a multi client wrapper compositor. 204 * 205 * @ingroup comp_multi 206 */ 207xrt_result_t 208multi_compositor_create(struct multi_system_compositor *msc, 209 const struct xrt_session_info *xsi, 210 struct xrt_session_event_sink *xses, 211 struct xrt_compositor_native **out_xcn); 212 213/*! 214 * Push a event to be delivered to the session that corresponds 215 * to the given @ref multi_compositor. 216 * 217 * @ingroup comp_multi 218 * @private @memberof multi_compositor 219 */ 220XRT_CHECK_RESULT xrt_result_t 221multi_compositor_push_event(struct multi_compositor *mc, const union xrt_session_event *xse); 222 223/*! 224 * Deliver any scheduled frames at that is to be display at or after the given @p display_time_ns. Called by the render 225 * thread and copies data from multi_compositor::scheduled to multi_compositor::delivered while holding the slot_lock. 226 * 227 * @ingroup comp_multi 228 * @private @memberof multi_compositor 229 */ 230void 231multi_compositor_deliver_any_frames(struct multi_compositor *mc, int64_t display_time_ns); 232 233/*! 234 * Makes the current delivered frame as latched, called by the render thread. 235 * The list_and_timing_lock is held when this function is called. 236 * 237 * @ingroup comp_multi 238 * @private @memberof multi_compositor 239 */ 240void 241multi_compositor_latch_frame_locked(struct multi_compositor *mc, int64_t when_ns, int64_t system_frame_id); 242 243/*! 244 * Clears and retires the delivered frame, called by the render thread. 245 * The list_and_timing_lock is held when this function is called. 246 * 247 * @ingroup comp_multi 248 * @private @memberof multi_compositor 249 */ 250void 251multi_compositor_retire_delivered_locked(struct multi_compositor *mc, int64_t when_ns); 252 253 254/* 255 * 256 * Multi-client-capable system compositor 257 * 258 */ 259 260/*! 261 * State of the multi-client system compositor. Use to track the calling of native 262 * compositor methods @ref xrt_comp_begin_session and @ref xrt_comp_end_session. 263 * 264 * It is driven by the number of active app sessions. 265 * 266 * @ingroup comp_multi 267 */ 268enum multi_system_state 269{ 270 /*! 271 * Invalid state, never used. 272 */ 273 MULTI_SYSTEM_STATE_INVALID, 274 275 /*! 276 * One of the initial states, the multi-client system compositor will 277 * make sure that its @ref xrt_compositor_native submits one frame. 278 * 279 * The session hasn't been started yet. 280 */ 281 MULTI_SYSTEM_STATE_INIT_WARM_START, 282 283 /*! 284 * One of the initial state and post stopping state. 285 * 286 * The multi-client system compositor has called @ref xrt_comp_end_session 287 * on its @ref xrt_compositor_native. 288 */ 289 MULTI_SYSTEM_STATE_STOPPED, 290 291 /*! 292 * The main session is running. 293 * 294 * The multi-client system compositor has called @ref xrt_comp_begin_session 295 * on its @ref xrt_compositor_native. 296 */ 297 MULTI_SYSTEM_STATE_RUNNING, 298 299 /*! 300 * There are no active sessions and the multi-client system compositor is 301 * instructing the native compositor to draw one or more clear frames. 302 * 303 * The multi-client system compositor has not yet called @ref xrt_comp_begin_session 304 * on its @ref xrt_compositor_native. 305 */ 306 MULTI_SYSTEM_STATE_STOPPING, 307}; 308 309/*! 310 * The multi-client module (aka multi compositor) is system compositor that 311 * multiplexes access to a single @ref xrt_compositor_native, merging layers 312 * from one or more client apps/sessions. This object implements the 313 * @ref xrt_system_compositor, and gives each session a @ref multi_compositor, 314 * which implements @ref xrt_compositor_native. 315 * 316 * @ingroup comp_multi 317 * @implements xrt_system_compositor 318 */ 319struct multi_system_compositor 320{ 321 //! Base interface. 322 struct xrt_system_compositor base; 323 324 //! Extra functions to handle multi client. 325 struct xrt_multi_compositor_control xmcc; 326 327 /*! 328 * Real native compositor, which this multi client module submits the 329 * combined layers of active @ref multi_compositor objects. 330 */ 331 struct xrt_compositor_native *xcn; 332 333 /*! 334 * App pacer factory, when a new @ref multi_compositor is created a 335 * pacer is created from this factory. 336 */ 337 struct u_pacing_app_factory *upaf; 338 339 //! Render loop thread. 340 struct os_thread_helper oth; 341 342 struct 343 { 344 /*! 345 * The state of the multi-client system compositor. 346 * This is updated on the multi_system_compositor::oth 347 * thread, aka multi-client system compositor main thread. 348 * It is driven by the active_count field. 349 */ 350 enum multi_system_state state; 351 352 //! Number of active sessions, protected by oth. 353 uint64_t active_count; 354 } sessions; 355 356 /*! 357 * This mutex protects the list of client compositor 358 * and the rendering timings on it. 359 */ 360 struct os_mutex list_and_timing_lock; 361 362 struct 363 { 364 int64_t predicted_display_time_ns; 365 int64_t predicted_display_period_ns; 366 int64_t diff_ns; 367 } last_timings; 368 369 //! List of active clients. 370 struct multi_compositor *clients[MULTI_MAX_CLIENTS]; 371}; 372 373/*! 374 * Cast helper 375 * 376 * @ingroup comp_multi 377 * @private @memberof multi_system_compositor 378 */ 379static inline struct multi_system_compositor * 380multi_system_compositor(struct xrt_system_compositor *xsc) 381{ 382 return (struct multi_system_compositor *)xsc; 383} 384 385/*! 386 * The client compositor calls this function to update when its session is 387 * started or stopped. 388 * 389 * @ingroup comp_multi 390 * @private @memberof multi_system_compositor 391 */ 392void 393multi_system_compositor_update_session_status(struct multi_system_compositor *msc, bool active); 394 395 396#ifdef __cplusplus 397} 398#endif