The open source OpenXR runtime
1// Copyright 2020-2022, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief A mock native compositor to use when testing client compositors.
6 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
7 * @author Jakob Bornecrantz <jakob@collabora.com>
8 */
9
10#include "mock_compositor.h"
11
12#include "util/u_misc.h"
13#include "util/u_handles.h"
14
15static void
16mock_compositor_swapchain_destroy(struct xrt_swapchain *xsc)
17{
18 struct mock_compositor_swapchain *mcsc = mock_compositor_swapchain(xsc);
19 struct mock_compositor *mc = mcsc->mc;
20
21 if (mc->swapchain_hooks.destroy) {
22 mc->swapchain_hooks.destroy(mc, mcsc);
23 }
24 for (uint32_t i = 0; i < mcsc->base.base.image_count; ++i) {
25 u_graphics_buffer_unref(&(mcsc->handles[i]));
26 }
27 free(xsc);
28}
29
30static xrt_result_t
31mock_compositor_swapchain_wait_image(struct xrt_swapchain *xsc, int64_t timeout_ns, uint32_t index)
32{
33 struct mock_compositor_swapchain *mcsc = mock_compositor_swapchain(xsc);
34 struct mock_compositor *mc = mcsc->mc;
35
36 if (mc->swapchain_hooks.wait_image) {
37 return mc->swapchain_hooks.wait_image(mc, mcsc, timeout_ns, index);
38 }
39 mcsc->waited[index] = true;
40 return XRT_SUCCESS;
41}
42
43static xrt_result_t
44mock_compositor_swapchain_acquire_image(struct xrt_swapchain *xsc, uint32_t *out_index)
45{
46 struct mock_compositor_swapchain *mcsc = mock_compositor_swapchain(xsc);
47 struct mock_compositor *mc = mcsc->mc;
48
49 if (mc->swapchain_hooks.acquire_image) {
50 return mc->swapchain_hooks.acquire_image(mc, mcsc, out_index);
51 }
52 uint32_t index = mcsc->next_to_acquire;
53 mcsc->next_to_acquire = (mcsc->next_to_acquire + 1) % mcsc->base.base.image_count;
54 mcsc->acquired[index] = true;
55
56 return XRT_SUCCESS;
57}
58
59static xrt_result_t
60mock_compositor_swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index)
61{
62 struct mock_compositor_swapchain *mcsc = mock_compositor_swapchain(xsc);
63 struct mock_compositor *mc = mcsc->mc;
64
65 if (mc->swapchain_hooks.acquire_image) {
66 return mc->swapchain_hooks.release_image(mc, mcsc, index);
67 }
68 mcsc->acquired[index] = false;
69 mcsc->waited[index] = false;
70
71 return XRT_SUCCESS;
72}
73
74
75static xrt_result_t
76mock_compositor_swapchain_create(struct xrt_compositor *xc,
77 const struct xrt_swapchain_create_info *info,
78 struct xrt_swapchain **out_xsc)
79{
80 struct mock_compositor *mc = mock_compositor(xc);
81 // Mini implementation of get_swapchain_create_properties to avoid an actual call causing confusing traces in
82 // the mock
83 uint32_t image_count = (0 != (info->create & XRT_SWAPCHAIN_CREATE_STATIC_IMAGE)) ? 1 : 3;
84 constexpr bool use_dedicated_allocation = false;
85
86
87 struct mock_compositor_swapchain *mcsc = U_TYPED_CALLOC(struct mock_compositor_swapchain);
88 mcsc->base.base.image_count = image_count;
89 mcsc->base.base.wait_image = mock_compositor_swapchain_wait_image;
90 mcsc->base.base.acquire_image = mock_compositor_swapchain_acquire_image;
91 mcsc->base.base.release_image = mock_compositor_swapchain_release_image;
92 mcsc->base.base.destroy = mock_compositor_swapchain_destroy;
93 mcsc->base.base.reference.count = 1;
94 mcsc->mc = mc;
95 mcsc->id = mc->next_id;
96 mcsc->info = *info;
97 mc->next_id++;
98
99 *out_xsc = &mcsc->base.base;
100 if (mc->compositor_hooks.create_swapchain) {
101 return mc->compositor_hooks.create_swapchain(mc, mcsc, info, out_xsc);
102 }
103
104 for (uint32_t i = 0; i < image_count; i++) {
105 mcsc->base.images[i].handle = XRT_GRAPHICS_BUFFER_HANDLE_INVALID;
106 mcsc->base.images[i].use_dedicated_allocation = use_dedicated_allocation;
107 }
108
109
110 return XRT_SUCCESS;
111}
112
113static xrt_result_t
114mock_compositor_swapchain_import(struct xrt_compositor *xc,
115 const struct xrt_swapchain_create_info *info,
116 struct xrt_image_native *native_images,
117 uint32_t image_count,
118 struct xrt_swapchain **out_xsc)
119{
120 struct mock_compositor *mc = mock_compositor(xc);
121 struct mock_compositor_swapchain *mcsc = U_TYPED_CALLOC(struct mock_compositor_swapchain);
122 mcsc->base.base.image_count = image_count;
123 mcsc->base.base.wait_image = mock_compositor_swapchain_wait_image;
124 mcsc->base.base.acquire_image = mock_compositor_swapchain_acquire_image;
125 mcsc->base.base.release_image = mock_compositor_swapchain_release_image;
126 mcsc->base.base.destroy = mock_compositor_swapchain_destroy;
127 mcsc->base.base.reference.count = 1;
128 mcsc->imported = true;
129 mcsc->mc = mc;
130 mcsc->id = mc->next_id;
131 mcsc->info = *info;
132 mc->next_id++;
133
134 *out_xsc = &mcsc->base.base;
135 if (mc->compositor_hooks.import_swapchain) {
136 return mc->compositor_hooks.import_swapchain(mc, mcsc, info, native_images, image_count, out_xsc);
137 }
138
139 for (uint32_t i = 0; i < image_count; i++) {
140 mcsc->handles[i] = native_images[i].handle;
141 mcsc->base.images[i] = native_images[i];
142 }
143
144 return XRT_SUCCESS;
145}
146
147static xrt_result_t
148mock_compositor_get_swapchain_create_properties(struct xrt_compositor *xc,
149 const struct xrt_swapchain_create_info *info,
150 struct xrt_swapchain_create_properties *xsccp)
151{
152 struct mock_compositor *mc = mock_compositor(xc);
153
154 if (mc->compositor_hooks.get_swapchain_create_properties) {
155 return mc->compositor_hooks.get_swapchain_create_properties(mc, info, xsccp);
156 }
157 // default "normal" impl
158 if (0 != (info->create & XRT_SWAPCHAIN_CREATE_STATIC_IMAGE)) {
159 xsccp->image_count = 1;
160 } else {
161 xsccp->image_count = 3;
162 }
163 return XRT_SUCCESS;
164}
165
166static void
167mock_compositor_destroy(struct xrt_compositor *xc)
168{
169 struct mock_compositor *mc = mock_compositor(xc);
170
171 if (mc->compositor_hooks.destroy) {
172 return mc->compositor_hooks.destroy(mc);
173 }
174 free(mc);
175}
176
177struct xrt_compositor_native *
178mock_create_native_compositor()
179{
180 struct mock_compositor *mc = U_TYPED_CALLOC(struct mock_compositor);
181 mc->base.base.get_swapchain_create_properties = mock_compositor_get_swapchain_create_properties;
182 mc->base.base.create_swapchain = mock_compositor_swapchain_create;
183 mc->base.base.import_swapchain = mock_compositor_swapchain_import;
184 // mc->base.base.create_semaphore = mock_compositor_semaphore_create;
185 // mc->base.base.begin_session = mock_compositor_begin_session;
186 // mc->base.base.end_session = mock_compositor_end_session;
187 // mc->base.base.wait_frame = mock_compositor_wait_frame;
188 // mc->base.base.begin_frame = mock_compositor_begin_frame;
189 // mc->base.base.discard_frame = mock_compositor_discard_frame;
190 // mc->base.base.layer_begin = mock_compositor_layer_begin;
191 // mc->base.base.layer_projection = mock_compositor_layer_projection;
192 // mc->base.base.layer_projection_depth = mock_compositor_layer_projection_depth;
193 // mc->base.base.layer_quad = mock_compositor_layer_quad;
194 // mc->base.base.layer_cube = mock_compositor_layer_cube;
195 // mc->base.base.layer_cylinder = mock_compositor_layer_cylinder;
196 // mc->base.base.layer_equirect1 = mock_compositor_layer_equirect1;
197 // mc->base.base.layer_equirect2 = mock_compositor_layer_equirect2;
198 // mc->base.base.layer_commit = mock_compositor_layer_commit;
199 // mc->base.base.layer_commit_with_semaphore = mock_compositor_layer_commit_with_semaphore;
200 // mc->base.base.poll_events = mock_compositor_poll_events;
201 mc->base.base.destroy = mock_compositor_destroy;
202
203 return &mc->base;
204}