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