1 /*
2 * Copyright 2024 Valve Corporation
3 * Copyright 2024 Alyssa Rosenzweig
4 * Copyright 2022-2023 Collabora Ltd. and Red Hat Inc.
5 * SPDX-License-Identifier: MIT
6 */
7 #include "hk_instance.h"
8
9 #include "hk_entrypoints.h"
10 #include "hk_physical_device.h"
11
12 #include "vulkan/wsi/wsi_common.h"
13
14 #include "util/build_id.h"
15 #include "util/driconf.h"
16 #include "util/mesa-sha1.h"
17
18 VKAPI_ATTR VkResult VKAPI_CALL
hk_EnumerateInstanceVersion(uint32_t * pApiVersion)19 hk_EnumerateInstanceVersion(uint32_t *pApiVersion)
20 {
21 uint32_t version_override = vk_get_version_override();
22 *pApiVersion = version_override ? version_override
23 : VK_MAKE_VERSION(1, 4, VK_HEADER_VERSION);
24
25 return VK_SUCCESS;
26 }
27
28 static const struct vk_instance_extension_table instance_extensions = {
29 #ifdef HK_USE_WSI_PLATFORM
30 .KHR_get_surface_capabilities2 = true,
31 .KHR_surface = true,
32 .KHR_surface_protected_capabilities = true,
33 .EXT_surface_maintenance1 = true,
34 .EXT_swapchain_colorspace = true,
35 #endif
36 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
37 .KHR_wayland_surface = true,
38 #endif
39 #ifdef VK_USE_PLATFORM_XCB_KHR
40 .KHR_xcb_surface = true,
41 #endif
42 #ifdef VK_USE_PLATFORM_XLIB_KHR
43 .KHR_xlib_surface = true,
44 #endif
45 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
46 .EXT_acquire_xlib_display = true,
47 #endif
48 #ifdef VK_USE_PLATFORM_DISPLAY_KHR
49 .KHR_display = true,
50 .KHR_get_display_properties2 = true,
51 .EXT_direct_mode_display = true,
52 .EXT_display_surface_counter = true,
53 .EXT_acquire_drm_display = true,
54 #endif
55 #ifndef VK_USE_PLATFORM_WIN32_KHR
56 .EXT_headless_surface = true,
57 #endif
58 .KHR_device_group_creation = true,
59 .KHR_external_fence_capabilities = true,
60 .KHR_external_memory_capabilities = true,
61 .KHR_external_semaphore_capabilities = true,
62 .KHR_get_physical_device_properties2 = true,
63 .EXT_debug_report = true,
64 .EXT_debug_utils = true,
65 };
66
67 VKAPI_ATTR VkResult VKAPI_CALL
hk_EnumerateInstanceExtensionProperties(const char * pLayerName,uint32_t * pPropertyCount,VkExtensionProperties * pProperties)68 hk_EnumerateInstanceExtensionProperties(const char *pLayerName,
69 uint32_t *pPropertyCount,
70 VkExtensionProperties *pProperties)
71 {
72 if (pLayerName)
73 return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
74
75 return vk_enumerate_instance_extension_properties(
76 &instance_extensions, pPropertyCount, pProperties);
77 }
78
79 /* clang-format off */
80 static const driOptionDescription hk_dri_options[] = {
81 DRI_CONF_SECTION_PERFORMANCE
82 DRI_CONF_ADAPTIVE_SYNC(true)
83 DRI_CONF_VK_X11_OVERRIDE_MIN_IMAGE_COUNT(0)
84 DRI_CONF_VK_X11_STRICT_IMAGE_COUNT(false)
85 DRI_CONF_VK_X11_ENSURE_MIN_IMAGE_COUNT(false)
86 DRI_CONF_VK_KHR_PRESENT_WAIT(false)
87 DRI_CONF_VK_XWAYLAND_WAIT_READY(false)
88 DRI_CONF_SECTION_END
89
90 DRI_CONF_SECTION_DEBUG
91 DRI_CONF_FORCE_VK_VENDOR()
92 DRI_CONF_VK_WSI_FORCE_SWAPCHAIN_TO_CURRENT_EXTENT(false)
93 DRI_CONF_VK_X11_IGNORE_SUBOPTIMAL(false)
94 DRI_CONF_SECTION_END
95
96 DRI_CONF_SECTION_MISCELLANEOUS
97 DRI_CONF_HK_DISABLE_RGBA4_BORDER_COLOR_WORKAROUND(false)
98 DRI_CONF_HK_DISABLE_BORDER_EMULATION(false)
99 DRI_CONF_SECTION_END
100 };
101 /* clang-format on */
102
103 static void
hk_init_dri_options(struct hk_instance * instance)104 hk_init_dri_options(struct hk_instance *instance)
105 {
106 driParseOptionInfo(&instance->available_dri_options, hk_dri_options,
107 ARRAY_SIZE(hk_dri_options));
108 driParseConfigFiles(
109 &instance->dri_options, &instance->available_dri_options, 0, "hk", NULL,
110 NULL, instance->vk.app_info.app_name, instance->vk.app_info.app_version,
111 instance->vk.app_info.engine_name, instance->vk.app_info.engine_version);
112
113 instance->force_vk_vendor =
114 driQueryOptioni(&instance->dri_options, "force_vk_vendor");
115
116 instance->workaround_rgba4 = !driQueryOptionb(
117 &instance->dri_options, "hk_disable_rgba4_border_color_workaround");
118
119 instance->no_border =
120 driQueryOptionb(&instance->dri_options, "hk_disable_border_emulation");
121 }
122
123 VKAPI_ATTR VkResult VKAPI_CALL
hk_CreateInstance(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * pInstance)124 hk_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
125 const VkAllocationCallbacks *pAllocator,
126 VkInstance *pInstance)
127 {
128 struct hk_instance *instance;
129 VkResult result;
130
131 if (pAllocator == NULL)
132 pAllocator = vk_default_allocator();
133
134 instance = vk_alloc(pAllocator, sizeof(*instance), 8,
135 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
136 if (!instance)
137 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
138
139 struct vk_instance_dispatch_table dispatch_table;
140 vk_instance_dispatch_table_from_entrypoints(&dispatch_table,
141 &hk_instance_entrypoints, true);
142 vk_instance_dispatch_table_from_entrypoints(
143 &dispatch_table, &wsi_instance_entrypoints, false);
144
145 result = vk_instance_init(&instance->vk, &instance_extensions,
146 &dispatch_table, pCreateInfo, pAllocator);
147 if (result != VK_SUCCESS)
148 goto fail_alloc;
149
150 hk_init_dri_options(instance);
151
152 instance->vk.physical_devices.try_create_for_drm =
153 hk_create_drm_physical_device;
154 instance->vk.physical_devices.destroy = hk_physical_device_destroy;
155
156 const struct build_id_note *note =
157 build_id_find_nhdr_for_addr(hk_CreateInstance);
158 if (!note) {
159 result = vk_errorf(NULL, VK_ERROR_INITIALIZATION_FAILED,
160 "Failed to find build-id");
161 goto fail_init;
162 }
163
164 unsigned build_id_len = build_id_length(note);
165 if (build_id_len < SHA1_DIGEST_LENGTH) {
166 result = vk_errorf(NULL, VK_ERROR_INITIALIZATION_FAILED,
167 "build-id too short. It needs to be a SHA");
168 goto fail_init;
169 }
170
171 static_assert(sizeof(instance->driver_build_sha) == SHA1_DIGEST_LENGTH);
172 memcpy(instance->driver_build_sha, build_id_data(note), SHA1_DIGEST_LENGTH);
173
174 *pInstance = hk_instance_to_handle(instance);
175 return VK_SUCCESS;
176
177 fail_init:
178 vk_instance_finish(&instance->vk);
179 fail_alloc:
180 vk_free(pAllocator, instance);
181
182 return result;
183 }
184
185 VKAPI_ATTR void VKAPI_CALL
hk_DestroyInstance(VkInstance _instance,const VkAllocationCallbacks * pAllocator)186 hk_DestroyInstance(VkInstance _instance,
187 const VkAllocationCallbacks *pAllocator)
188 {
189 VK_FROM_HANDLE(hk_instance, instance, _instance);
190
191 if (!instance)
192 return;
193
194 driDestroyOptionCache(&instance->dri_options);
195 driDestroyOptionInfo(&instance->available_dri_options);
196
197 vk_instance_finish(&instance->vk);
198 vk_free(&instance->vk.alloc, instance);
199 }
200
201 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
hk_GetInstanceProcAddr(VkInstance _instance,const char * pName)202 hk_GetInstanceProcAddr(VkInstance _instance, const char *pName)
203 {
204 VK_FROM_HANDLE(hk_instance, instance, _instance);
205 return vk_instance_get_proc_addr(&instance->vk, &hk_instance_entrypoints,
206 pName);
207 }
208
209 PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
vk_icdGetInstanceProcAddr(VkInstance instance,const char * pName)210 vk_icdGetInstanceProcAddr(VkInstance instance, const char *pName)
211 {
212 return hk_GetInstanceProcAddr(instance, pName);
213 }
214