The open source OpenXR runtime
1// Copyright 2022-2024, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Basic Vulkan compositor tests.
6 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
7 * @author Korcan Hussein <korcan.hussein@collabora.com>
8 */
9
10
11#include "mock/mock_compositor.h"
12#include "client/comp_vk_client.h"
13#include "xrt/xrt_results.h"
14#include <vulkan/vulkan_core.h>
15
16#undef Always
17#undef None
18#undef Success
19
20#include "catch_amalgamated.hpp"
21#include "util/comp_vulkan.h"
22#include "util/u_logging.h"
23#include "util/u_string_list.h"
24#include "vk/vk_helpers.h"
25#include "xrt/xrt_compositor.h"
26#include <xrt/xrt_deleters.hpp>
27
28#include <memory>
29#include <iostream>
30
31using unique_native_compositor =
32 std::unique_ptr<xrt_compositor_native,
33 xrt::deleters::ptr_ptr_deleter<xrt_compositor_native, &xrt_comp_native_destroy>>;
34
35// clang-format off
36#define COMP_INSTANCE_EXTENSIONS_COMMON \
37 VK_EXT_DEBUG_REPORT_EXTENSION_NAME, \
38 VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, \
39 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, \
40 VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, \
41 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, \
42 VK_KHR_SURFACE_EXTENSION_NAME
43// clang-format on
44
45static const char *instance_extensions_common[] = {
46 COMP_INSTANCE_EXTENSIONS_COMMON,
47};
48static const char *required_device_extensions[] = {
49 VK_KHR_SWAPCHAIN_EXTENSION_NAME, //
50 VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, //
51 VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME, //
52 VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, //
53 VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, //
54 VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, //
55
56// Platform version of "external_memory"
57#if defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD)
58 VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
59
60#elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER)
61 VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
62 VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
63 VK_KHR_MAINTENANCE_1_EXTENSION_NAME,
64 VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
65 VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
66
67#elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_WIN32_HANDLE)
68 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
69
70#else
71#error "Need port!"
72#endif
73
74// Platform version of "external_fence" and "external_semaphore"
75#if defined(XRT_GRAPHICS_SYNC_HANDLE_IS_FD) // Optional
76
77#elif defined(XRT_GRAPHICS_SYNC_HANDLE_IS_WIN32_HANDLE)
78 VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME,
79 VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME,
80
81#else
82#error "Need port!"
83#endif
84};
85
86
87using unique_string_list =
88 std::unique_ptr<u_string_list, xrt::deleters::ptr_ptr_deleter<u_string_list, &u_string_list_destroy>>;
89
90static void
91xrt_comp_vk_destroy(struct xrt_compositor_vk **ptr_xcvk)
92{
93 if (!ptr_xcvk) {
94 return;
95 }
96 xrt_compositor *xc = &(*ptr_xcvk)->base;
97 xrt_comp_destroy(&xc);
98}
99
100using unique_compositor_vk =
101 std::unique_ptr<struct xrt_compositor_vk,
102 xrt::deleters::ptr_ptr_deleter<struct xrt_compositor_vk, &xrt_comp_vk_destroy>>;
103
104TEST_CASE("client_compositor", "[.][needgpu]")
105{
106 xrt_compositor_native *xcn = mock_create_native_compositor();
107 struct mock_compositor *mc = mock_compositor(&(xcn->base));
108
109 // every backend needs at least the common extensions
110 unique_string_list required_instance_ext_list{
111 u_string_list_create_from_array(instance_extensions_common, ARRAY_SIZE(instance_extensions_common))};
112
113 unique_string_list optional_instance_ext_list{u_string_list_create()};
114
115 unique_string_list required_device_extension_list{
116 u_string_list_create_from_array(required_device_extensions, ARRAY_SIZE(required_device_extensions))};
117
118 unique_string_list optional_device_extension_list{u_string_list_create()};
119
120 comp_vulkan_arguments args{VK_MAKE_VERSION(1, 0, 0),
121 vkGetInstanceProcAddr,
122 required_instance_ext_list.get(),
123 optional_instance_ext_list.get(),
124 required_device_extension_list.get(),
125 optional_device_extension_list.get(),
126 U_LOGGING_TRACE,
127 false /* only_compute_queue */,
128 true /*timeline_semaphore*/,
129 -1,
130 -1};
131 vk_bundle vk_bundle_storage{};
132 vk_bundle *vk = &vk_bundle_storage;
133 comp_vulkan_results results{};
134 REQUIRE(comp_vulkan_init_bundle(vk, &args, &results));
135 struct xrt_compositor_vk *xcvk = xrt_gfx_vk_provider_create( //
136 xcn, //
137 vk->instance, //
138 vkGetInstanceProcAddr, //
139 vk->physical_device, //
140 vk->device,
141#if defined(XRT_GRAPHICS_SYNC_HANDLE_IS_FD) //
142 vk->external.fence_sync_fd, //
143 vk->external.binary_semaphore_sync_fd, //
144 vk->external.timeline_semaphore_sync_fd, //
145#elif defined(XRT_GRAPHICS_SYNC_HANDLE_IS_WIN32_HANDLE)
146 vk->external.fence_win32_handle, //
147 vk->external.binary_semaphore_win32_handle, //
148 vk->external.timeline_semaphore_win32_handle, //
149#else
150#error "Need port for fence sync handles checkers"
151#endif
152 vk->has_KHR_image_format_list, // image_format_list_enabled
153 false, // debug_utils_enabled
154 false, // renderdoc_enabled
155 vk->main_queue->family_index, //
156 vk->main_queue->index);
157 struct xrt_compositor *xc = &xcvk->base;
158
159 SECTION("CreateSwapchain calls native create")
160 {
161 bool nativeCreateCalled = false;
162 mc->userdata = &nativeCreateCalled;
163 mc->compositor_hooks.create_swapchain =
164 [](struct mock_compositor *mc, struct mock_compositor_swapchain *mcsc,
165 const struct xrt_swapchain_create_info *info, struct xrt_swapchain **out_xsc) {
166 *static_cast<bool *>(mc->userdata) = true;
167 return XRT_SUCCESS;
168 };
169 xrt_swapchain_create_info xsci{};
170 xsci.format = VK_FORMAT_B8G8R8A8_SRGB;
171 xsci.bits = (xrt_swapchain_usage_bits)(XRT_SWAPCHAIN_USAGE_COLOR | XRT_SWAPCHAIN_USAGE_SAMPLED);
172 xsci.sample_count = 1;
173 xsci.width = 800;
174 xsci.height = 600;
175 xsci.face_count = 1;
176 xsci.array_size = 1;
177 xsci.mip_count = 1;
178
179 struct xrt_swapchain *xsc = nullptr;
180 // This will fail because the mock compositor doesn't actually create images for Vulkan to import, but
181 // it will get far enough to trigger our hook and update the flag.
182 xrt_comp_create_swapchain(xc, &xsci, &xsc);
183 CHECK(nativeCreateCalled);
184 xrt_swapchain_reference(&xsc, nullptr);
185 }
186
187 xrt_comp_destroy(&xc);
188
189 vk_deinit_mutex(vk);
190
191 xrt_comp_native_destroy(&xcn);
192}