• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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