The open source OpenXR runtime
1// Copyright 2019-2024, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Helper implementation for native compositors.
6 * @author Jakob Bornecrantz <jakob@collabora.com>
7 * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
8 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
9 * @ingroup comp_util
10 */
11
12#include "util/comp_layer_accum.h"
13#include "util/comp_sync.h"
14#include "util/u_wait.h"
15#include "util/u_trace_marker.h"
16
17#include "util/comp_base.h"
18#include "util/comp_semaphore.h"
19#include "xrt/xrt_compositor.h"
20
21
22/*
23 *
24 * Helper function.
25 *
26 */
27
28
29/*
30 *
31 * xrt_compositor functions.
32 *
33 */
34
35//! Delegates to code in `comp_swapchain`
36static xrt_result_t
37base_get_swapchain_create_properties(struct xrt_compositor *xc,
38 const struct xrt_swapchain_create_info *info,
39 struct xrt_swapchain_create_properties *xsccp)
40{
41 return comp_swapchain_get_create_properties(info, xsccp);
42}
43
44//! Delegates to code in `comp_swapchain`
45static xrt_result_t
46base_create_swapchain(struct xrt_compositor *xc,
47 const struct xrt_swapchain_create_info *info,
48 struct xrt_swapchain **out_xsc)
49{
50 struct comp_base *cb = comp_base(xc);
51
52 /*
53 * In case the default get properties function have been overridden
54 * make sure to correctly dispatch the call to get the properties.
55 */
56 struct xrt_swapchain_create_properties xsccp = {0};
57 xrt_comp_get_swapchain_create_properties(xc, info, &xsccp);
58
59 return comp_swapchain_create(&cb->vk, &cb->cscs, info, &xsccp, out_xsc);
60}
61
62//! Delegates to code in `comp_swapchain`
63static xrt_result_t
64base_import_swapchain(struct xrt_compositor *xc,
65 const struct xrt_swapchain_create_info *info,
66 struct xrt_image_native *native_images,
67 uint32_t image_count,
68 struct xrt_swapchain **out_xsc)
69{
70 struct comp_base *cb = comp_base(xc);
71
72 return comp_swapchain_import(&cb->vk, &cb->cscs, info, native_images, image_count, out_xsc);
73}
74
75//! Delegates to code in `comp_sync`
76static xrt_result_t
77base_import_fence(struct xrt_compositor *xc, xrt_graphics_sync_handle_t handle, struct xrt_compositor_fence **out_xcf)
78{
79 struct comp_base *cb = comp_base(xc);
80
81 return comp_fence_import(&cb->vk, handle, out_xcf);
82}
83
84//! Delegates to code in `comp_semaphore`
85static xrt_result_t
86base_create_semaphore(struct xrt_compositor *xc,
87 xrt_graphics_sync_handle_t *out_handle,
88 struct xrt_compositor_semaphore **out_xcsem)
89{
90 struct comp_base *cb = comp_base(xc);
91
92 return comp_semaphore_create(&cb->vk, out_handle, out_xcsem);
93}
94
95static xrt_result_t
96base_layer_begin(struct xrt_compositor *xc, const struct xrt_layer_frame_data *data)
97{
98 struct comp_base *cb = comp_base(xc);
99 return comp_layer_accum_begin(&cb->layer_accum, data);
100}
101
102static xrt_result_t
103base_layer_projection(struct xrt_compositor *xc,
104 struct xrt_device *xdev,
105 struct xrt_swapchain *xsc[XRT_MAX_VIEWS],
106 const struct xrt_layer_data *data)
107{
108 struct comp_base *cb = comp_base(xc);
109 return comp_layer_accum_projection(&cb->layer_accum, xsc, data);
110}
111
112static xrt_result_t
113base_layer_projection_depth(struct xrt_compositor *xc,
114 struct xrt_device *xdev,
115 struct xrt_swapchain *xsc[XRT_MAX_VIEWS],
116 struct xrt_swapchain *d_xsc[XRT_MAX_VIEWS],
117 const struct xrt_layer_data *data)
118{
119 struct comp_base *cb = comp_base(xc);
120 return comp_layer_accum_projection_depth(&cb->layer_accum, xsc, d_xsc, data);
121}
122
123static xrt_result_t
124base_layer_quad(struct xrt_compositor *xc,
125 struct xrt_device *xdev,
126 struct xrt_swapchain *xsc,
127 const struct xrt_layer_data *data)
128{
129 struct comp_base *cb = comp_base(xc);
130 return comp_layer_accum_quad(&cb->layer_accum, xsc, data);
131}
132
133static xrt_result_t
134base_layer_cube(struct xrt_compositor *xc,
135 struct xrt_device *xdev,
136 struct xrt_swapchain *xsc,
137 const struct xrt_layer_data *data)
138{
139 struct comp_base *cb = comp_base(xc);
140 return comp_layer_accum_cube(&cb->layer_accum, xsc, data);
141}
142
143static xrt_result_t
144base_layer_cylinder(struct xrt_compositor *xc,
145 struct xrt_device *xdev,
146 struct xrt_swapchain *xsc,
147 const struct xrt_layer_data *data)
148{
149 struct comp_base *cb = comp_base(xc);
150 return comp_layer_accum_cylinder(&cb->layer_accum, xsc, data);
151}
152
153static xrt_result_t
154base_layer_equirect1(struct xrt_compositor *xc,
155 struct xrt_device *xdev,
156 struct xrt_swapchain *xsc,
157 const struct xrt_layer_data *data)
158{
159 struct comp_base *cb = comp_base(xc);
160 return comp_layer_accum_equirect1(&cb->layer_accum, xsc, data);
161}
162
163static xrt_result_t
164base_layer_equirect2(struct xrt_compositor *xc,
165 struct xrt_device *xdev,
166 struct xrt_swapchain *xsc,
167 const struct xrt_layer_data *data)
168{
169 struct comp_base *cb = comp_base(xc);
170 return comp_layer_accum_equirect2(&cb->layer_accum, xsc, data);
171}
172
173static xrt_result_t
174base_wait_frame(struct xrt_compositor *xc,
175 int64_t *out_frame_id,
176 int64_t *out_predicted_display_time_ns,
177 int64_t *out_predicted_display_period_ns)
178{
179 COMP_TRACE_MARKER();
180
181 struct comp_base *cb = comp_base(xc);
182
183 int64_t frame_id = -1;
184 int64_t wake_up_time_ns = 0;
185 int64_t predicted_gpu_time_ns = 0;
186
187 xrt_comp_predict_frame( //
188 xc, //
189 &frame_id, //
190 &wake_up_time_ns, //
191 &predicted_gpu_time_ns, //
192 out_predicted_display_time_ns, //
193 out_predicted_display_period_ns); //
194
195 // Wait until the given wake up time.
196 u_wait_until(&cb->sleeper, wake_up_time_ns);
197
198 int64_t now_ns = os_monotonic_get_ns();
199
200 // Signal that we woke up.
201 xrt_comp_mark_frame(xc, frame_id, XRT_COMPOSITOR_FRAME_POINT_WOKE, now_ns);
202
203 *out_frame_id = frame_id;
204
205 return XRT_SUCCESS;
206}
207
208
209/*
210 *
211 * 'Exported' functions.
212 *
213 */
214
215void
216comp_base_init(struct comp_base *cb)
217{
218 struct xrt_compositor *iface = &cb->base.base;
219 iface->get_swapchain_create_properties = base_get_swapchain_create_properties;
220 iface->create_swapchain = base_create_swapchain;
221 iface->import_swapchain = base_import_swapchain;
222 iface->create_semaphore = base_create_semaphore;
223 iface->import_fence = base_import_fence;
224 iface->layer_begin = base_layer_begin;
225 iface->layer_projection = base_layer_projection;
226 iface->layer_projection_depth = base_layer_projection_depth;
227 iface->layer_quad = base_layer_quad;
228 iface->layer_cube = base_layer_cube;
229 iface->layer_cylinder = base_layer_cylinder;
230 iface->layer_equirect1 = base_layer_equirect1;
231 iface->layer_equirect2 = base_layer_equirect2;
232 iface->wait_frame = base_wait_frame;
233
234 u_threading_stack_init(&cb->cscs.destroy_swapchains);
235
236 os_precise_sleeper_init(&cb->sleeper);
237}
238
239void
240comp_base_fini(struct comp_base *cb)
241{
242 os_precise_sleeper_deinit(&cb->sleeper);
243
244 u_threading_stack_fini(&cb->cscs.destroy_swapchains);
245}