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, 3, 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 static const driOptionDescription hk_dri_options[] = {
80 DRI_CONF_SECTION_PERFORMANCE DRI_CONF_ADAPTIVE_SYNC(true)
81 DRI_CONF_VK_X11_OVERRIDE_MIN_IMAGE_COUNT(0)
82 DRI_CONF_VK_X11_STRICT_IMAGE_COUNT(false)
83 DRI_CONF_VK_X11_ENSURE_MIN_IMAGE_COUNT(false)
84 DRI_CONF_VK_KHR_PRESENT_WAIT(false)
85 DRI_CONF_VK_XWAYLAND_WAIT_READY(false) DRI_CONF_SECTION_END
86
87 DRI_CONF_SECTION_DEBUG DRI_CONF_FORCE_VK_VENDOR()
88 DRI_CONF_VK_WSI_FORCE_SWAPCHAIN_TO_CURRENT_EXTENT(false)
89 DRI_CONF_VK_X11_IGNORE_SUBOPTIMAL(false)
90 DRI_CONF_SECTION_END};
91
92 static void
hk_init_dri_options(struct hk_instance * instance)93 hk_init_dri_options(struct hk_instance *instance)
94 {
95 driParseOptionInfo(&instance->available_dri_options, hk_dri_options,
96 ARRAY_SIZE(hk_dri_options));
97 driParseConfigFiles(
98 &instance->dri_options, &instance->available_dri_options, 0, "hk", NULL,
99 NULL, instance->vk.app_info.app_name, instance->vk.app_info.app_version,
100 instance->vk.app_info.engine_name, instance->vk.app_info.engine_version);
101
102 instance->force_vk_vendor =
103 driQueryOptioni(&instance->dri_options, "force_vk_vendor");
104 }
105
106 VKAPI_ATTR VkResult VKAPI_CALL
hk_CreateInstance(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * pInstance)107 hk_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
108 const VkAllocationCallbacks *pAllocator,
109 VkInstance *pInstance)
110 {
111 struct hk_instance *instance;
112 VkResult result;
113
114 if (pAllocator == NULL)
115 pAllocator = vk_default_allocator();
116
117 instance = vk_alloc(pAllocator, sizeof(*instance), 8,
118 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
119 if (!instance)
120 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
121
122 struct vk_instance_dispatch_table dispatch_table;
123 vk_instance_dispatch_table_from_entrypoints(&dispatch_table,
124 &hk_instance_entrypoints, true);
125 vk_instance_dispatch_table_from_entrypoints(
126 &dispatch_table, &wsi_instance_entrypoints, false);
127
128 result = vk_instance_init(&instance->vk, &instance_extensions,
129 &dispatch_table, pCreateInfo, pAllocator);
130 if (result != VK_SUCCESS)
131 goto fail_alloc;
132
133 hk_init_dri_options(instance);
134
135 instance->vk.physical_devices.try_create_for_drm =
136 hk_create_drm_physical_device;
137 instance->vk.physical_devices.destroy = hk_physical_device_destroy;
138
139 const struct build_id_note *note =
140 build_id_find_nhdr_for_addr(hk_CreateInstance);
141 if (!note) {
142 result = vk_errorf(NULL, VK_ERROR_INITIALIZATION_FAILED,
143 "Failed to find build-id");
144 goto fail_init;
145 }
146
147 unsigned build_id_len = build_id_length(note);
148 if (build_id_len < SHA1_DIGEST_LENGTH) {
149 result = vk_errorf(NULL, VK_ERROR_INITIALIZATION_FAILED,
150 "build-id too short. It needs to be a SHA");
151 goto fail_init;
152 }
153
154 static_assert(sizeof(instance->driver_build_sha) == SHA1_DIGEST_LENGTH);
155 memcpy(instance->driver_build_sha, build_id_data(note), SHA1_DIGEST_LENGTH);
156
157 *pInstance = hk_instance_to_handle(instance);
158 return VK_SUCCESS;
159
160 fail_init:
161 vk_instance_finish(&instance->vk);
162 fail_alloc:
163 vk_free(pAllocator, instance);
164
165 return result;
166 }
167
168 VKAPI_ATTR void VKAPI_CALL
hk_DestroyInstance(VkInstance _instance,const VkAllocationCallbacks * pAllocator)169 hk_DestroyInstance(VkInstance _instance,
170 const VkAllocationCallbacks *pAllocator)
171 {
172 VK_FROM_HANDLE(hk_instance, instance, _instance);
173
174 if (!instance)
175 return;
176
177 driDestroyOptionCache(&instance->dri_options);
178 driDestroyOptionInfo(&instance->available_dri_options);
179
180 vk_instance_finish(&instance->vk);
181 vk_free(&instance->vk.alloc, instance);
182 }
183
184 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
hk_GetInstanceProcAddr(VkInstance _instance,const char * pName)185 hk_GetInstanceProcAddr(VkInstance _instance, const char *pName)
186 {
187 VK_FROM_HANDLE(hk_instance, instance, _instance);
188 return vk_instance_get_proc_addr(&instance->vk, &hk_instance_entrypoints,
189 pName);
190 }
191
192 PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
vk_icdGetInstanceProcAddr(VkInstance instance,const char * pName)193 vk_icdGetInstanceProcAddr(VkInstance instance, const char *pName)
194 {
195 return hk_GetInstanceProcAddr(instance, pName);
196 }
197