1 /*
2 * Copyright © 2021 Collabora Ltd.
3 *
4 * Derived from tu_device.c which is:
5 * Copyright © 2016 Red Hat.
6 * Copyright © 2016 Bas Nieuwenhuizen
7 * Copyright © 2015 Intel Corporation
8 *
9 * SPDX-License-Identifier: MIT
10 */
11
12 #include "util/build_id.h"
13 #include "util/mesa-sha1.h"
14
15 #include "vk_alloc.h"
16 #include "vk_log.h"
17
18 #include "panvk_entrypoints.h"
19 #include "panvk_instance.h"
20 #include "panvk_physical_device.h"
21
22 #ifdef HAVE_VALGRIND
23 #include <memcheck.h>
24 #include <valgrind.h>
25 #define VG(x) x
26 #else
27 #define VG(x)
28 #endif
29
30 static const struct debug_control panvk_debug_options[] = {
31 {"startup", PANVK_DEBUG_STARTUP},
32 {"nir", PANVK_DEBUG_NIR},
33 {"trace", PANVK_DEBUG_TRACE},
34 {"sync", PANVK_DEBUG_SYNC},
35 {"afbc", PANVK_DEBUG_AFBC},
36 {"linear", PANVK_DEBUG_LINEAR},
37 {"dump", PANVK_DEBUG_DUMP},
38 {"no_known_warn", PANVK_DEBUG_NO_KNOWN_WARN},
39 {"cs", PANVK_DEBUG_CS},
40 {NULL, 0}};
41
42 VKAPI_ATTR VkResult VKAPI_CALL
panvk_EnumerateInstanceVersion(uint32_t * pApiVersion)43 panvk_EnumerateInstanceVersion(uint32_t *pApiVersion)
44 {
45 *pApiVersion = panvk_get_vk_version();
46 return VK_SUCCESS;
47 }
48
49 static const struct vk_instance_extension_table panvk_instance_extensions = {
50 .KHR_device_group_creation = true,
51 .KHR_get_physical_device_properties2 = true,
52 #ifdef PANVK_USE_WSI_PLATFORM
53 .KHR_surface = true,
54 #endif
55 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
56 .KHR_wayland_surface = true,
57 #endif
58 #ifdef VK_USE_PLATFORM_XCB_KHR
59 .KHR_xcb_surface = true,
60 #endif
61 #ifdef VK_USE_PLATFORM_XLIB_KHR
62 .KHR_xlib_surface = true,
63 #endif
64 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
65 .EXT_acquire_xlib_display = true,
66 #endif
67 .EXT_debug_report = true,
68 .EXT_debug_utils = true,
69 #ifndef VK_USE_PLATFORM_WIN32_KHR
70 .EXT_headless_surface = true,
71 #endif
72 };
73
74 static VkResult
panvk_physical_device_try_create(struct vk_instance * vk_instance,struct _drmDevice * drm_device,struct vk_physical_device ** out)75 panvk_physical_device_try_create(struct vk_instance *vk_instance,
76 struct _drmDevice *drm_device,
77 struct vk_physical_device **out)
78 {
79 struct panvk_instance *instance =
80 container_of(vk_instance, struct panvk_instance, vk);
81
82 if (!(drm_device->available_nodes & (1 << DRM_NODE_RENDER)) ||
83 drm_device->bustype != DRM_BUS_PLATFORM)
84 return VK_ERROR_INCOMPATIBLE_DRIVER;
85
86 struct panvk_physical_device *device =
87 vk_zalloc(&instance->vk.alloc, sizeof(*device), 8,
88 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
89 if (!device)
90 return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
91
92 VkResult result = panvk_physical_device_init(device, instance, drm_device);
93 if (result != VK_SUCCESS) {
94 vk_free(&instance->vk.alloc, device);
95 return result;
96 }
97
98 *out = &device->vk;
99 return VK_SUCCESS;
100 }
101
102 static void
panvk_destroy_physical_device(struct vk_physical_device * device)103 panvk_destroy_physical_device(struct vk_physical_device *device)
104 {
105 panvk_physical_device_finish((struct panvk_physical_device *)device);
106 vk_free(&device->instance->alloc, device);
107 }
108
109 static void *
panvk_kmod_zalloc(const struct pan_kmod_allocator * allocator,size_t size,bool transient)110 panvk_kmod_zalloc(const struct pan_kmod_allocator *allocator, size_t size,
111 bool transient)
112 {
113 const VkAllocationCallbacks *vkalloc = allocator->priv;
114
115 void *obj = vk_zalloc(vkalloc, size, 8,
116 transient ? VK_SYSTEM_ALLOCATION_SCOPE_COMMAND
117 : VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
118
119 /* We force errno to -ENOMEM on host allocation failures so we can properly
120 * report it back as VK_ERROR_OUT_OF_HOST_MEMORY. */
121 errno = obj ? 0 : -ENOMEM;
122
123 return obj;
124 }
125
126 static void
panvk_kmod_free(const struct pan_kmod_allocator * allocator,void * data)127 panvk_kmod_free(const struct pan_kmod_allocator *allocator, void *data)
128 {
129 const VkAllocationCallbacks *vkalloc = allocator->priv;
130
131 return vk_free(vkalloc, data);
132 }
133
134 VKAPI_ATTR VkResult VKAPI_CALL
panvk_CreateInstance(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * pInstance)135 panvk_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
136 const VkAllocationCallbacks *pAllocator,
137 VkInstance *pInstance)
138 {
139 struct panvk_instance *instance;
140 VkResult result;
141
142 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
143
144 const struct build_id_note *note =
145 build_id_find_nhdr_for_addr(panvk_CreateInstance);
146 if (!note) {
147 return vk_errorf(NULL, VK_ERROR_INITIALIZATION_FAILED,
148 "Failed to find build-id");
149 }
150
151 unsigned build_id_len = build_id_length(note);
152 if (build_id_len < SHA1_DIGEST_LENGTH) {
153 return vk_errorf(NULL, VK_ERROR_INITIALIZATION_FAILED,
154 "build-id too short. It needs to be a SHA");
155 }
156
157 pAllocator = pAllocator ?: vk_default_allocator();
158 instance = vk_zalloc(pAllocator, sizeof(*instance), 8,
159 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
160 if (!instance)
161 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
162
163 struct vk_instance_dispatch_table dispatch_table;
164
165 vk_instance_dispatch_table_from_entrypoints(
166 &dispatch_table, &panvk_instance_entrypoints, true);
167 vk_instance_dispatch_table_from_entrypoints(
168 &dispatch_table, &wsi_instance_entrypoints, false);
169 result = vk_instance_init(&instance->vk, &panvk_instance_extensions,
170 &dispatch_table, pCreateInfo, pAllocator);
171 if (result != VK_SUCCESS) {
172 vk_free(pAllocator, instance);
173 return vk_error(NULL, result);
174 }
175
176 instance->kmod.allocator = (struct pan_kmod_allocator){
177 .zalloc = panvk_kmod_zalloc,
178 .free = panvk_kmod_free,
179 .priv = &instance->vk.alloc,
180 };
181
182 instance->vk.physical_devices.try_create_for_drm =
183 panvk_physical_device_try_create;
184 instance->vk.physical_devices.destroy = panvk_destroy_physical_device;
185
186 instance->debug_flags =
187 parse_debug_string(getenv("PANVK_DEBUG"), panvk_debug_options);
188
189 if (instance->debug_flags & PANVK_DEBUG_STARTUP)
190 vk_logi(VK_LOG_NO_OBJS(instance), "Created an instance");
191
192 VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false));
193
194 STATIC_ASSERT(sizeof(instance->driver_build_sha) == SHA1_DIGEST_LENGTH);
195 memcpy(instance->driver_build_sha, build_id_data(note), SHA1_DIGEST_LENGTH);
196
197 *pInstance = panvk_instance_to_handle(instance);
198
199 return VK_SUCCESS;
200 }
201
202 VKAPI_ATTR void VKAPI_CALL
panvk_DestroyInstance(VkInstance _instance,const VkAllocationCallbacks * pAllocator)203 panvk_DestroyInstance(VkInstance _instance,
204 const VkAllocationCallbacks *pAllocator)
205 {
206 VK_FROM_HANDLE(panvk_instance, instance, _instance);
207
208 if (!instance)
209 return;
210
211 vk_instance_finish(&instance->vk);
212 vk_free(&instance->vk.alloc, instance);
213 }
214
215 VKAPI_ATTR VkResult VKAPI_CALL
panvk_EnumerateInstanceLayerProperties(uint32_t * pPropertyCount,VkLayerProperties * pProperties)216 panvk_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
217 VkLayerProperties *pProperties)
218 {
219 *pPropertyCount = 0;
220 return VK_SUCCESS;
221 }
222
223 VKAPI_ATTR VkResult VKAPI_CALL
panvk_EnumerateInstanceExtensionProperties(const char * pLayerName,uint32_t * pPropertyCount,VkExtensionProperties * pProperties)224 panvk_EnumerateInstanceExtensionProperties(const char *pLayerName,
225 uint32_t *pPropertyCount,
226 VkExtensionProperties *pProperties)
227 {
228 if (pLayerName)
229 return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
230
231 return vk_enumerate_instance_extension_properties(
232 &panvk_instance_extensions, pPropertyCount, pProperties);
233 }
234
235 PFN_vkVoidFunction
panvk_GetInstanceProcAddr(VkInstance _instance,const char * pName)236 panvk_GetInstanceProcAddr(VkInstance _instance, const char *pName)
237 {
238 VK_FROM_HANDLE(panvk_instance, instance, _instance);
239 return vk_instance_get_proc_addr(&instance->vk, &panvk_instance_entrypoints,
240 pName);
241 }
242
243 /* The loader wants us to expose a second GetInstanceProcAddr function
244 * to work around certain LD_PRELOAD issues seen in apps.
245 */
246 PUBLIC
247 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
vk_icdGetInstanceProcAddr(VkInstance instance,const char * pName)248 vk_icdGetInstanceProcAddr(VkInstance instance, const char *pName)
249 {
250 return panvk_GetInstanceProcAddr(instance, pName);
251 }
252