1 /*
2 * Copyright © 2019 Raspberry Pi Ltd
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <stdbool.h>
27 #include <string.h>
28 #include <sys/mman.h>
29 #include <sys/sysinfo.h>
30 #include <unistd.h>
31 #include <xf86drm.h>
32
33 #ifdef MAJOR_IN_MKDEV
34 #include <sys/mkdev.h>
35 #endif
36 #ifdef MAJOR_IN_SYSMACROS
37 #include <sys/sysmacros.h>
38 #endif
39
40 #include "v3dv_private.h"
41
42 #include "common/v3d_debug.h"
43
44 #include "compiler/v3d_compiler.h"
45
46 #include "drm-uapi/v3d_drm.h"
47 #include "format/u_format.h"
48 #include "vk_drm_syncobj.h"
49 #include "vk_util.h"
50 #include "git_sha1.h"
51
52 #include "util/build_id.h"
53 #include "util/debug.h"
54
55 #ifdef VK_USE_PLATFORM_XCB_KHR
56 #include <xcb/xcb.h>
57 #include <xcb/dri3.h>
58 #include <X11/Xlib-xcb.h>
59 #endif
60
61 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
62 #include <wayland-client.h>
63 #include "wayland-drm-client-protocol.h"
64 #endif
65
66 #ifndef ANDROID
67 # define V3DV_API_VERSION VK_MAKE_VERSION(1, 2, VK_HEADER_VERSION)
68 #else
69 /* Android CDD require additional extensions for API v1.1+ */
70 # define V3DV_API_VERSION VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION)
71 #endif
72
73 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_EnumerateInstanceVersion(uint32_t * pApiVersion)74 v3dv_EnumerateInstanceVersion(uint32_t *pApiVersion)
75 {
76 *pApiVersion = V3DV_API_VERSION;
77 return VK_SUCCESS;
78 }
79
80 #if defined(VK_USE_PLATFORM_WIN32_KHR) || \
81 defined(VK_USE_PLATFORM_WAYLAND_KHR) || \
82 defined(VK_USE_PLATFORM_XCB_KHR) || \
83 defined(VK_USE_PLATFORM_XLIB_KHR) || \
84 defined(VK_USE_PLATFORM_DISPLAY_KHR)
85 #define V3DV_USE_WSI_PLATFORM
86 #endif
87
88 static const struct vk_instance_extension_table instance_extensions = {
89 .KHR_device_group_creation = true,
90 #ifdef VK_USE_PLATFORM_DISPLAY_KHR
91 .KHR_display = true,
92 .KHR_get_display_properties2 = true,
93 #endif
94 .KHR_external_fence_capabilities = true,
95 .KHR_external_memory_capabilities = true,
96 .KHR_external_semaphore_capabilities = true,
97 .KHR_get_physical_device_properties2 = true,
98 #ifdef V3DV_USE_WSI_PLATFORM
99 .KHR_get_surface_capabilities2 = true,
100 .KHR_surface = true,
101 .KHR_surface_protected_capabilities = true,
102 #endif
103 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
104 .KHR_wayland_surface = true,
105 #endif
106 #ifdef VK_USE_PLATFORM_XCB_KHR
107 .KHR_xcb_surface = true,
108 #endif
109 #ifdef VK_USE_PLATFORM_XLIB_KHR
110 .KHR_xlib_surface = true,
111 #endif
112 .EXT_debug_report = true,
113 .EXT_debug_utils = true,
114 };
115
116 static void
get_device_extensions(const struct v3dv_physical_device * device,struct vk_device_extension_table * ext)117 get_device_extensions(const struct v3dv_physical_device *device,
118 struct vk_device_extension_table *ext)
119 {
120 *ext = (struct vk_device_extension_table) {
121 .KHR_8bit_storage = true,
122 .KHR_16bit_storage = true,
123 .KHR_bind_memory2 = true,
124 .KHR_buffer_device_address = true,
125 .KHR_copy_commands2 = true,
126 .KHR_create_renderpass2 = true,
127 .KHR_dedicated_allocation = true,
128 .KHR_device_group = true,
129 .KHR_driver_properties = true,
130 .KHR_descriptor_update_template = true,
131 .KHR_depth_stencil_resolve = true,
132 .KHR_external_fence = true,
133 .KHR_external_fence_fd = true,
134 .KHR_external_memory = true,
135 .KHR_external_memory_fd = true,
136 .KHR_external_semaphore = true,
137 .KHR_external_semaphore_fd = true,
138 .KHR_format_feature_flags2 = true,
139 .KHR_get_memory_requirements2 = true,
140 .KHR_image_format_list = true,
141 .KHR_imageless_framebuffer = true,
142 .KHR_performance_query = device->caps.perfmon,
143 .KHR_relaxed_block_layout = true,
144 .KHR_maintenance1 = true,
145 .KHR_maintenance2 = true,
146 .KHR_maintenance3 = true,
147 .KHR_multiview = true,
148 .KHR_pipeline_executable_properties = true,
149 .KHR_separate_depth_stencil_layouts = true,
150 .KHR_shader_float_controls = true,
151 .KHR_shader_non_semantic_info = true,
152 .KHR_sampler_mirror_clamp_to_edge = true,
153 .KHR_spirv_1_4 = true,
154 .KHR_storage_buffer_storage_class = true,
155 .KHR_timeline_semaphore = true,
156 .KHR_uniform_buffer_standard_layout = true,
157 #ifdef V3DV_USE_WSI_PLATFORM
158 .KHR_swapchain = true,
159 .KHR_swapchain_mutable_format = true,
160 .KHR_incremental_present = true,
161 #endif
162 .KHR_variable_pointers = true,
163 .KHR_vulkan_memory_model = true,
164 .EXT_4444_formats = true,
165 .EXT_color_write_enable = true,
166 .EXT_custom_border_color = true,
167 .EXT_inline_uniform_block = true,
168 .EXT_external_memory_dma_buf = true,
169 .EXT_host_query_reset = true,
170 .EXT_image_drm_format_modifier = true,
171 .EXT_index_type_uint8 = true,
172 .EXT_line_rasterization = true,
173 .EXT_physical_device_drm = true,
174 .EXT_pipeline_creation_cache_control = true,
175 .EXT_pipeline_creation_feedback = true,
176 .EXT_private_data = true,
177 .EXT_provoking_vertex = true,
178 .EXT_separate_stencil_usage = true,
179 .EXT_vertex_attribute_divisor = true,
180 #ifdef ANDROID
181 .ANDROID_native_buffer = true,
182 #endif
183 };
184 }
185
186 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_EnumerateInstanceExtensionProperties(const char * pLayerName,uint32_t * pPropertyCount,VkExtensionProperties * pProperties)187 v3dv_EnumerateInstanceExtensionProperties(const char *pLayerName,
188 uint32_t *pPropertyCount,
189 VkExtensionProperties *pProperties)
190 {
191 /* We don't support any layers */
192 if (pLayerName)
193 return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
194
195 return vk_enumerate_instance_extension_properties(
196 &instance_extensions, pPropertyCount, pProperties);
197 }
198
199 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_CreateInstance(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * pInstance)200 v3dv_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
201 const VkAllocationCallbacks *pAllocator,
202 VkInstance *pInstance)
203 {
204 struct v3dv_instance *instance;
205 VkResult result;
206
207 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
208
209 if (pAllocator == NULL)
210 pAllocator = vk_default_allocator();
211
212 instance = vk_alloc(pAllocator, sizeof(*instance), 8,
213 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
214 if (!instance)
215 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
216
217 struct vk_instance_dispatch_table dispatch_table;
218 vk_instance_dispatch_table_from_entrypoints(
219 &dispatch_table, &v3dv_instance_entrypoints, true);
220 vk_instance_dispatch_table_from_entrypoints(
221 &dispatch_table, &wsi_instance_entrypoints, false);
222
223 result = vk_instance_init(&instance->vk,
224 &instance_extensions,
225 &dispatch_table,
226 pCreateInfo, pAllocator);
227
228 if (result != VK_SUCCESS) {
229 vk_free(pAllocator, instance);
230 return vk_error(NULL, result);
231 }
232
233 v3d_process_debug_variable();
234
235 instance->physicalDeviceCount = -1;
236
237 /* We start with the default values for the pipeline_cache envvars */
238 instance->pipeline_cache_enabled = true;
239 instance->default_pipeline_cache_enabled = true;
240 const char *pipeline_cache_str = getenv("V3DV_ENABLE_PIPELINE_CACHE");
241 if (pipeline_cache_str != NULL) {
242 if (strncmp(pipeline_cache_str, "full", 4) == 0) {
243 /* nothing to do, just to filter correct values */
244 } else if (strncmp(pipeline_cache_str, "no-default-cache", 16) == 0) {
245 instance->default_pipeline_cache_enabled = false;
246 } else if (strncmp(pipeline_cache_str, "off", 3) == 0) {
247 instance->pipeline_cache_enabled = false;
248 instance->default_pipeline_cache_enabled = false;
249 } else {
250 fprintf(stderr, "Wrong value for envvar V3DV_ENABLE_PIPELINE_CACHE. "
251 "Allowed values are: full, no-default-cache, off\n");
252 }
253 }
254
255 if (instance->pipeline_cache_enabled == false) {
256 fprintf(stderr, "WARNING: v3dv pipeline cache is disabled. Performance "
257 "can be affected negatively\n");
258 } else {
259 if (instance->default_pipeline_cache_enabled == false) {
260 fprintf(stderr, "WARNING: default v3dv pipeline cache is disabled. "
261 "Performance can be affected negatively\n");
262 }
263 }
264
265 VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false));
266
267 *pInstance = v3dv_instance_to_handle(instance);
268
269 return VK_SUCCESS;
270 }
271
272 static void
v3dv_physical_device_free_disk_cache(struct v3dv_physical_device * device)273 v3dv_physical_device_free_disk_cache(struct v3dv_physical_device *device)
274 {
275 #ifdef ENABLE_SHADER_CACHE
276 if (device->disk_cache)
277 disk_cache_destroy(device->disk_cache);
278 #else
279 assert(device->disk_cache == NULL);
280 #endif
281 }
282
283 static void
physical_device_finish(struct v3dv_physical_device * device)284 physical_device_finish(struct v3dv_physical_device *device)
285 {
286 v3dv_wsi_finish(device);
287 v3dv_physical_device_free_disk_cache(device);
288 v3d_compiler_free(device->compiler);
289
290 util_sparse_array_finish(&device->bo_map);
291
292 close(device->render_fd);
293 if (device->display_fd >= 0)
294 close(device->display_fd);
295 if (device->master_fd >= 0)
296 close(device->master_fd);
297
298 free(device->name);
299
300 #if using_v3d_simulator
301 v3d_simulator_destroy(device->sim_file);
302 #endif
303
304 vk_physical_device_finish(&device->vk);
305 mtx_destroy(&device->mutex);
306 }
307
308 VKAPI_ATTR void VKAPI_CALL
v3dv_DestroyInstance(VkInstance _instance,const VkAllocationCallbacks * pAllocator)309 v3dv_DestroyInstance(VkInstance _instance,
310 const VkAllocationCallbacks *pAllocator)
311 {
312 V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
313
314 if (!instance)
315 return;
316
317 if (instance->physicalDeviceCount > 0) {
318 /* We support at most one physical device. */
319 assert(instance->physicalDeviceCount == 1);
320 physical_device_finish(&instance->physicalDevice);
321 }
322
323 VG(VALGRIND_DESTROY_MEMPOOL(instance));
324
325 vk_instance_finish(&instance->vk);
326 vk_free(&instance->vk.alloc, instance);
327 }
328
329 static uint64_t
compute_heap_size()330 compute_heap_size()
331 {
332 #if !using_v3d_simulator
333 /* Query the total ram from the system */
334 struct sysinfo info;
335 sysinfo(&info);
336
337 uint64_t total_ram = (uint64_t)info.totalram * (uint64_t)info.mem_unit;
338 #else
339 uint64_t total_ram = (uint64_t) v3d_simulator_get_mem_size();
340 #endif
341
342 /* We don't want to burn too much ram with the GPU. If the user has 4GiB
343 * or less, we use at most half. If they have more than 4GiB, we use 3/4.
344 */
345 uint64_t available_ram;
346 if (total_ram <= 4ull * 1024ull * 1024ull * 1024ull)
347 available_ram = total_ram / 2;
348 else
349 available_ram = total_ram * 3 / 4;
350
351 return available_ram;
352 }
353
354 #if !using_v3d_simulator
355 #ifdef VK_USE_PLATFORM_XCB_KHR
356 static int
create_display_fd_xcb(VkIcdSurfaceBase * surface)357 create_display_fd_xcb(VkIcdSurfaceBase *surface)
358 {
359 int fd = -1;
360
361 xcb_connection_t *conn;
362 xcb_dri3_open_reply_t *reply = NULL;
363 if (surface) {
364 if (surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
365 conn = XGetXCBConnection(((VkIcdSurfaceXlib *)surface)->dpy);
366 else
367 conn = ((VkIcdSurfaceXcb *)surface)->connection;
368 } else {
369 conn = xcb_connect(NULL, NULL);
370 }
371
372 if (xcb_connection_has_error(conn))
373 goto finish;
374
375 const xcb_setup_t *setup = xcb_get_setup(conn);
376 xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
377 xcb_screen_t *screen = iter.data;
378
379 xcb_dri3_open_cookie_t cookie;
380 cookie = xcb_dri3_open(conn, screen->root, None);
381 reply = xcb_dri3_open_reply(conn, cookie, NULL);
382 if (!reply)
383 goto finish;
384
385 if (reply->nfd != 1)
386 goto finish;
387
388 fd = xcb_dri3_open_reply_fds(conn, reply)[0];
389 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
390
391 finish:
392 if (!surface)
393 xcb_disconnect(conn);
394 if (reply)
395 free(reply);
396
397 return fd;
398 }
399 #endif
400
401 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
402 struct v3dv_wayland_info {
403 struct wl_drm *wl_drm;
404 int fd;
405 bool is_set;
406 bool authenticated;
407 };
408
409 static void
v3dv_drm_handle_device(void * data,struct wl_drm * drm,const char * device)410 v3dv_drm_handle_device(void *data, struct wl_drm *drm, const char *device)
411 {
412 struct v3dv_wayland_info *info = data;
413 info->fd = open(device, O_RDWR | O_CLOEXEC);
414 info->is_set = info->fd != -1;
415 if (!info->is_set) {
416 fprintf(stderr, "v3dv_drm_handle_device: could not open %s (%s)\n",
417 device, strerror(errno));
418 return;
419 }
420
421 drm_magic_t magic;
422 if (drmGetMagic(info->fd, &magic)) {
423 fprintf(stderr, "v3dv_drm_handle_device: drmGetMagic failed\n");
424 close(info->fd);
425 info->fd = -1;
426 info->is_set = false;
427 return;
428 }
429 wl_drm_authenticate(info->wl_drm, magic);
430 }
431
432 static void
v3dv_drm_handle_format(void * data,struct wl_drm * drm,uint32_t format)433 v3dv_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
434 {
435 }
436
437 static void
v3dv_drm_handle_authenticated(void * data,struct wl_drm * drm)438 v3dv_drm_handle_authenticated(void *data, struct wl_drm *drm)
439 {
440 struct v3dv_wayland_info *info = data;
441 info->authenticated = true;
442 }
443
444 static void
v3dv_drm_handle_capabilities(void * data,struct wl_drm * drm,uint32_t value)445 v3dv_drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
446 {
447 }
448
449 struct wl_drm_listener v3dv_drm_listener = {
450 .device = v3dv_drm_handle_device,
451 .format = v3dv_drm_handle_format,
452 .authenticated = v3dv_drm_handle_authenticated,
453 .capabilities = v3dv_drm_handle_capabilities
454 };
455
456 static void
v3dv_registry_global(void * data,struct wl_registry * registry,uint32_t name,const char * interface,uint32_t version)457 v3dv_registry_global(void *data,
458 struct wl_registry *registry,
459 uint32_t name,
460 const char *interface,
461 uint32_t version)
462 {
463 struct v3dv_wayland_info *info = data;
464 if (strcmp(interface, "wl_drm") == 0) {
465 info->wl_drm = wl_registry_bind(registry, name, &wl_drm_interface,
466 MIN2(version, 2));
467 wl_drm_add_listener(info->wl_drm, &v3dv_drm_listener, data);
468 };
469 }
470
471 static void
v3dv_registry_global_remove_cb(void * data,struct wl_registry * registry,uint32_t name)472 v3dv_registry_global_remove_cb(void *data,
473 struct wl_registry *registry,
474 uint32_t name)
475 {
476 }
477
478 static int
create_display_fd_wayland(VkIcdSurfaceBase * surface)479 create_display_fd_wayland(VkIcdSurfaceBase *surface)
480 {
481 struct wl_display *display;
482 struct wl_registry *registry = NULL;
483
484 struct v3dv_wayland_info info = {
485 .wl_drm = NULL,
486 .fd = -1,
487 .is_set = false,
488 .authenticated = false
489 };
490
491 if (surface)
492 display = ((VkIcdSurfaceWayland *) surface)->display;
493 else
494 display = wl_display_connect(NULL);
495
496 if (!display)
497 return -1;
498
499 registry = wl_display_get_registry(display);
500 if (!registry) {
501 if (!surface)
502 wl_display_disconnect(display);
503 return -1;
504 }
505
506 static const struct wl_registry_listener registry_listener = {
507 v3dv_registry_global,
508 v3dv_registry_global_remove_cb
509 };
510 wl_registry_add_listener(registry, ®istry_listener, &info);
511
512 wl_display_roundtrip(display); /* For the registry advertisement */
513 wl_display_roundtrip(display); /* For the DRM device event */
514 wl_display_roundtrip(display); /* For the authentication event */
515
516 wl_drm_destroy(info.wl_drm);
517 wl_registry_destroy(registry);
518
519 if (!surface)
520 wl_display_disconnect(display);
521
522 if (!info.is_set)
523 return -1;
524
525 if (!info.authenticated)
526 return -1;
527
528 return info.fd;
529 }
530 #endif
531
532 /* Acquire an authenticated display fd without a surface reference. This is the
533 * case where the application is making WSI allocations outside the Vulkan
534 * swapchain context (only Zink, for now). Since we lack information about the
535 * underlying surface we just try our best to figure out the correct display
536 * and platform to use. It should work in most cases.
537 */
538 static void
acquire_display_device_no_surface(struct v3dv_instance * instance,struct v3dv_physical_device * pdevice)539 acquire_display_device_no_surface(struct v3dv_instance *instance,
540 struct v3dv_physical_device *pdevice)
541 {
542 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
543 pdevice->display_fd = create_display_fd_wayland(NULL);
544 #endif
545
546 #ifdef VK_USE_PLATFORM_XCB_KHR
547 if (pdevice->display_fd == -1)
548 pdevice->display_fd = create_display_fd_xcb(NULL);
549 #endif
550
551 #ifdef VK_USE_PLATFORM_DISPLAY_KHR
552 if (pdevice->display_fd == - 1 && pdevice->master_fd >= 0)
553 pdevice->display_fd = dup(pdevice->master_fd);
554 #endif
555 }
556
557 /* Acquire an authenticated display fd from the surface. This is the regular
558 * case where the application is using swapchains to create WSI allocations.
559 * In this case we use the surface information to figure out the correct
560 * display and platform combination.
561 */
562 static void
acquire_display_device_surface(struct v3dv_instance * instance,struct v3dv_physical_device * pdevice,VkIcdSurfaceBase * surface)563 acquire_display_device_surface(struct v3dv_instance *instance,
564 struct v3dv_physical_device *pdevice,
565 VkIcdSurfaceBase *surface)
566 {
567 /* Mesa will set both of VK_USE_PLATFORM_{XCB,XLIB} when building with
568 * platform X11, so only check for XCB and rely on XCB to get an
569 * authenticated device also for Xlib.
570 */
571 #ifdef VK_USE_PLATFORM_XCB_KHR
572 if (surface->platform == VK_ICD_WSI_PLATFORM_XCB ||
573 surface->platform == VK_ICD_WSI_PLATFORM_XLIB) {
574 pdevice->display_fd = create_display_fd_xcb(surface);
575 }
576 #endif
577
578 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
579 if (surface->platform == VK_ICD_WSI_PLATFORM_WAYLAND)
580 pdevice->display_fd = create_display_fd_wayland(surface);
581 #endif
582
583 #ifdef VK_USE_PLATFORM_DISPLAY_KHR
584 if (surface->platform == VK_ICD_WSI_PLATFORM_DISPLAY &&
585 pdevice->master_fd >= 0) {
586 pdevice->display_fd = dup(pdevice->master_fd);
587 }
588 #endif
589 }
590 #endif /* !using_v3d_simulator */
591
592 /* Attempts to get an authenticated display fd from the display server that
593 * we can use to allocate BOs for presentable images.
594 */
595 VkResult
v3dv_physical_device_acquire_display(struct v3dv_instance * instance,struct v3dv_physical_device * pdevice,VkIcdSurfaceBase * surface)596 v3dv_physical_device_acquire_display(struct v3dv_instance *instance,
597 struct v3dv_physical_device *pdevice,
598 VkIcdSurfaceBase *surface)
599 {
600 VkResult result = VK_SUCCESS;
601 mtx_lock(&pdevice->mutex);
602
603 if (pdevice->display_fd != -1)
604 goto done;
605
606 /* When running on the simulator we do everything on a single render node so
607 * we don't need to get an authenticated display fd from the display server.
608 */
609 #if !using_v3d_simulator
610 if (surface)
611 acquire_display_device_surface(instance, pdevice, surface);
612 else
613 acquire_display_device_no_surface(instance, pdevice);
614
615 if (pdevice->display_fd == -1)
616 result = VK_ERROR_INITIALIZATION_FAILED;
617 #endif
618
619 done:
620 mtx_unlock(&pdevice->mutex);
621 return result;
622 }
623
624 static bool
v3d_has_feature(struct v3dv_physical_device * device,enum drm_v3d_param feature)625 v3d_has_feature(struct v3dv_physical_device *device, enum drm_v3d_param feature)
626 {
627 struct drm_v3d_get_param p = {
628 .param = feature,
629 };
630 if (v3dv_ioctl(device->render_fd, DRM_IOCTL_V3D_GET_PARAM, &p) != 0)
631 return false;
632 return p.value;
633 }
634
635 static bool
device_has_expected_features(struct v3dv_physical_device * device)636 device_has_expected_features(struct v3dv_physical_device *device)
637 {
638 return v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_TFU) &&
639 v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CSD) &&
640 v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH);
641 }
642
643
644 static VkResult
init_uuids(struct v3dv_physical_device * device)645 init_uuids(struct v3dv_physical_device *device)
646 {
647 const struct build_id_note *note =
648 build_id_find_nhdr_for_addr(init_uuids);
649 if (!note) {
650 return vk_errorf(device->vk.instance,
651 VK_ERROR_INITIALIZATION_FAILED,
652 "Failed to find build-id");
653 }
654
655 unsigned build_id_len = build_id_length(note);
656 if (build_id_len < 20) {
657 return vk_errorf(device->vk.instance,
658 VK_ERROR_INITIALIZATION_FAILED,
659 "build-id too short. It needs to be a SHA");
660 }
661
662 memcpy(device->driver_build_sha1, build_id_data(note), 20);
663
664 uint32_t vendor_id = v3dv_physical_device_vendor_id(device);
665 uint32_t device_id = v3dv_physical_device_device_id(device);
666
667 struct mesa_sha1 sha1_ctx;
668 uint8_t sha1[20];
669 STATIC_ASSERT(VK_UUID_SIZE <= sizeof(sha1));
670
671 /* The pipeline cache UUID is used for determining when a pipeline cache is
672 * invalid. It needs both a driver build and the PCI ID of the device.
673 */
674 _mesa_sha1_init(&sha1_ctx);
675 _mesa_sha1_update(&sha1_ctx, build_id_data(note), build_id_len);
676 _mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id));
677 _mesa_sha1_final(&sha1_ctx, sha1);
678 memcpy(device->pipeline_cache_uuid, sha1, VK_UUID_SIZE);
679
680 /* The driver UUID is used for determining sharability of images and memory
681 * between two Vulkan instances in separate processes. People who want to
682 * share memory need to also check the device UUID (below) so all this
683 * needs to be is the build-id.
684 */
685 memcpy(device->driver_uuid, build_id_data(note), VK_UUID_SIZE);
686
687 /* The device UUID uniquely identifies the given device within the machine.
688 * Since we never have more than one device, this doesn't need to be a real
689 * UUID.
690 */
691 _mesa_sha1_init(&sha1_ctx);
692 _mesa_sha1_update(&sha1_ctx, &vendor_id, sizeof(vendor_id));
693 _mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id));
694 _mesa_sha1_final(&sha1_ctx, sha1);
695 memcpy(device->device_uuid, sha1, VK_UUID_SIZE);
696
697 return VK_SUCCESS;
698 }
699
700 static void
v3dv_physical_device_init_disk_cache(struct v3dv_physical_device * device)701 v3dv_physical_device_init_disk_cache(struct v3dv_physical_device *device)
702 {
703 #ifdef ENABLE_SHADER_CACHE
704 char timestamp[41];
705 _mesa_sha1_format(timestamp, device->driver_build_sha1);
706
707 assert(device->name);
708 device->disk_cache = disk_cache_create(device->name, timestamp, 0);
709 #else
710 device->disk_cache = NULL;
711 #endif
712 }
713
714 static VkResult
physical_device_init(struct v3dv_physical_device * device,struct v3dv_instance * instance,drmDevicePtr drm_render_device,drmDevicePtr drm_primary_device)715 physical_device_init(struct v3dv_physical_device *device,
716 struct v3dv_instance *instance,
717 drmDevicePtr drm_render_device,
718 drmDevicePtr drm_primary_device)
719 {
720 VkResult result = VK_SUCCESS;
721 int32_t master_fd = -1;
722 int32_t render_fd = -1;
723
724 struct vk_physical_device_dispatch_table dispatch_table;
725 vk_physical_device_dispatch_table_from_entrypoints
726 (&dispatch_table, &v3dv_physical_device_entrypoints, true);
727 vk_physical_device_dispatch_table_from_entrypoints(
728 &dispatch_table, &wsi_physical_device_entrypoints, false);
729
730 result = vk_physical_device_init(&device->vk, &instance->vk, NULL,
731 &dispatch_table);
732
733 if (result != VK_SUCCESS)
734 goto fail;
735
736 assert(drm_render_device);
737 const char *path = drm_render_device->nodes[DRM_NODE_RENDER];
738 render_fd = open(path, O_RDWR | O_CLOEXEC);
739 if (render_fd < 0) {
740 fprintf(stderr, "Opening %s failed: %s\n", path, strerror(errno));
741 result = VK_ERROR_INCOMPATIBLE_DRIVER;
742 goto fail;
743 }
744
745 /* If we are running on VK_KHR_display we need to acquire the master
746 * display device now for the v3dv_wsi_init() call below. For anything else
747 * we postpone that until a swapchain is created.
748 */
749
750 const char *primary_path;
751 #if !using_v3d_simulator
752 if (drm_primary_device)
753 primary_path = drm_primary_device->nodes[DRM_NODE_PRIMARY];
754 else
755 primary_path = NULL;
756 #else
757 primary_path = drm_render_device->nodes[DRM_NODE_PRIMARY];
758 #endif
759
760 struct stat primary_stat = {0}, render_stat = {0};
761
762 device->has_primary = primary_path;
763 if (device->has_primary) {
764 if (stat(primary_path, &primary_stat) != 0) {
765 result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
766 "failed to stat DRM primary node %s",
767 primary_path);
768 goto fail;
769 }
770
771 device->primary_devid = primary_stat.st_rdev;
772 }
773
774 if (fstat(render_fd, &render_stat) != 0) {
775 result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
776 "failed to stat DRM render node %s",
777 path);
778 goto fail;
779 }
780 device->has_render = true;
781 device->render_devid = render_stat.st_rdev;
782
783 #if using_v3d_simulator
784 device->device_id = drm_render_device->deviceinfo.pci->device_id;
785 #endif
786
787 if (instance->vk.enabled_extensions.KHR_display) {
788 #if !using_v3d_simulator
789 /* Open the primary node on the vc4 display device */
790 assert(drm_primary_device);
791 master_fd = open(primary_path, O_RDWR | O_CLOEXEC);
792 #else
793 /* There is only one device with primary and render nodes.
794 * Open its primary node.
795 */
796 master_fd = open(primary_path, O_RDWR | O_CLOEXEC);
797 #endif
798 }
799
800 #if using_v3d_simulator
801 device->sim_file = v3d_simulator_init(render_fd);
802 #endif
803
804 device->render_fd = render_fd; /* The v3d render node */
805 device->display_fd = -1; /* Authenticated vc4 primary node */
806 device->master_fd = master_fd; /* Master vc4 primary node */
807
808 if (!v3d_get_device_info(device->render_fd, &device->devinfo, &v3dv_ioctl)) {
809 result = VK_ERROR_INCOMPATIBLE_DRIVER;
810 goto fail;
811 }
812
813 if (device->devinfo.ver < 42) {
814 result = VK_ERROR_INCOMPATIBLE_DRIVER;
815 goto fail;
816 }
817
818 if (!device_has_expected_features(device)) {
819 result = VK_ERROR_INCOMPATIBLE_DRIVER;
820 goto fail;
821 }
822
823 device->caps.multisync =
824 v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT);
825
826 device->caps.perfmon =
827 v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_PERFMON);
828
829 result = init_uuids(device);
830 if (result != VK_SUCCESS)
831 goto fail;
832
833 device->compiler = v3d_compiler_init(&device->devinfo,
834 MAX_INLINE_UNIFORM_BUFFERS);
835 device->next_program_id = 0;
836
837 ASSERTED int len =
838 asprintf(&device->name, "V3D %d.%d",
839 device->devinfo.ver / 10, device->devinfo.ver % 10);
840 assert(len != -1);
841
842 v3dv_physical_device_init_disk_cache(device);
843
844 /* Setup available memory heaps and types */
845 VkPhysicalDeviceMemoryProperties *mem = &device->memory;
846 mem->memoryHeapCount = 1;
847 mem->memoryHeaps[0].size = compute_heap_size();
848 mem->memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
849
850 /* This is the only combination required by the spec */
851 mem->memoryTypeCount = 1;
852 mem->memoryTypes[0].propertyFlags =
853 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
854 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
855 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
856 mem->memoryTypes[0].heapIndex = 0;
857
858 /* Initialize sparse array for refcounting imported BOs */
859 util_sparse_array_init(&device->bo_map, sizeof(struct v3dv_bo), 512);
860
861 device->options.merge_jobs = !(V3D_DEBUG & V3D_DEBUG_NO_MERGE_JOBS);
862
863 device->drm_syncobj_type = vk_drm_syncobj_get_type(device->render_fd);
864
865 /* We don't support timelines in the uAPI yet and we don't want it getting
866 * suddenly turned on by vk_drm_syncobj_get_type() without us adding v3dv
867 * code for it first.
868 */
869 device->drm_syncobj_type.features &= ~VK_SYNC_FEATURE_TIMELINE;
870
871 #ifndef ANDROID
872 /* Sync file export is incompatible with the current model of execution
873 * where some jobs may run on the CPU. There are CTS tests which do the
874 * following:
875 *
876 * 1. Create a command buffer with a vkCmdWaitEvents()
877 * 2. Submit the command buffer
878 * 3. vkGetSemaphoreFdKHR() to try to get a sync_file
879 * 4. vkSetEvent()
880 *
881 * This deadlocks because we have to wait for the syncobj to get a real
882 * fence in vkGetSemaphoreFdKHR() which only happens after all the work
883 * from the command buffer is complete which only happens after
884 * vkSetEvent(). No amount of CPU threading in userspace will ever fix
885 * this. Sadly, this is pretty explicitly allowed by the Vulkan spec:
886 *
887 * VUID-vkCmdWaitEvents-pEvents-01163
888 *
889 * "If pEvents includes one or more events that will be signaled by
890 * vkSetEvent after commandBuffer has been submitted to a queue, then
891 * vkCmdWaitEvents must not be called inside a render pass instance"
892 *
893 * Disable sync file support for now.
894 */
895 device->drm_syncobj_type.import_sync_file = NULL;
896 device->drm_syncobj_type.export_sync_file = NULL;
897 #endif
898
899 /* Multiwait is required for emulated timeline semaphores and is supported
900 * by the v3d kernel interface.
901 */
902 device->drm_syncobj_type.features |= VK_SYNC_FEATURE_GPU_MULTI_WAIT;
903
904 device->sync_timeline_type =
905 vk_sync_timeline_get_type(&device->drm_syncobj_type);
906
907 device->sync_types[0] = &device->drm_syncobj_type;
908 device->sync_types[1] = &device->sync_timeline_type.sync;
909 device->sync_types[2] = NULL;
910 device->vk.supported_sync_types = device->sync_types;
911
912 result = v3dv_wsi_init(device);
913 if (result != VK_SUCCESS) {
914 vk_error(instance, result);
915 goto fail;
916 }
917
918 get_device_extensions(device, &device->vk.supported_extensions);
919
920 mtx_init(&device->mutex, mtx_plain);
921
922 return VK_SUCCESS;
923
924 fail:
925 vk_physical_device_finish(&device->vk);
926
927 if (render_fd >= 0)
928 close(render_fd);
929 if (master_fd >= 0)
930 close(master_fd);
931
932 return result;
933 }
934
935 static VkResult
enumerate_devices(struct v3dv_instance * instance)936 enumerate_devices(struct v3dv_instance *instance)
937 {
938 /* TODO: Check for more devices? */
939 drmDevicePtr devices[8];
940 VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER;
941 int max_devices;
942
943 instance->physicalDeviceCount = 0;
944
945 max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
946 if (max_devices < 1)
947 return VK_ERROR_INCOMPATIBLE_DRIVER;
948
949 #if !using_v3d_simulator
950 int32_t v3d_idx = -1;
951 int32_t vc4_idx = -1;
952 #endif
953 for (unsigned i = 0; i < (unsigned)max_devices; i++) {
954 #if using_v3d_simulator
955 /* In the simulator, we look for an Intel/AMD render node */
956 const int required_nodes = (1 << DRM_NODE_RENDER) | (1 << DRM_NODE_PRIMARY);
957 if ((devices[i]->available_nodes & required_nodes) == required_nodes &&
958 devices[i]->bustype == DRM_BUS_PCI &&
959 (devices[i]->deviceinfo.pci->vendor_id == 0x8086 ||
960 devices[i]->deviceinfo.pci->vendor_id == 0x1002)) {
961 result = physical_device_init(&instance->physicalDevice, instance,
962 devices[i], NULL);
963 if (result != VK_ERROR_INCOMPATIBLE_DRIVER)
964 break;
965 }
966 #else
967 /* On actual hardware, we should have a render node (v3d)
968 * and a primary node (vc4). We will need to use the primary
969 * to allocate WSI buffers and share them with the render node
970 * via prime, but that is a privileged operation so we need the
971 * primary node to be authenticated, and for that we need the
972 * display server to provide the device fd (with DRI3), so we
973 * here we only check that the device is present but we don't
974 * try to open it.
975 */
976 if (devices[i]->bustype != DRM_BUS_PLATFORM)
977 continue;
978
979 if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER) {
980 char **compat = devices[i]->deviceinfo.platform->compatible;
981 while (*compat) {
982 if (strncmp(*compat, "brcm,2711-v3d", 13) == 0) {
983 v3d_idx = i;
984 break;
985 }
986 compat++;
987 }
988 } else if (devices[i]->available_nodes & 1 << DRM_NODE_PRIMARY) {
989 char **compat = devices[i]->deviceinfo.platform->compatible;
990 while (*compat) {
991 if (strncmp(*compat, "brcm,bcm2711-vc5", 16) == 0 ||
992 strncmp(*compat, "brcm,bcm2835-vc4", 16) == 0 ) {
993 vc4_idx = i;
994 break;
995 }
996 compat++;
997 }
998 }
999 #endif
1000 }
1001
1002 #if !using_v3d_simulator
1003 if (v3d_idx == -1 || vc4_idx == -1)
1004 result = VK_ERROR_INCOMPATIBLE_DRIVER;
1005 else
1006 result = physical_device_init(&instance->physicalDevice, instance,
1007 devices[v3d_idx], devices[vc4_idx]);
1008 #endif
1009
1010 drmFreeDevices(devices, max_devices);
1011
1012 if (result == VK_SUCCESS)
1013 instance->physicalDeviceCount = 1;
1014
1015 return result;
1016 }
1017
1018 static VkResult
instance_ensure_physical_device(struct v3dv_instance * instance)1019 instance_ensure_physical_device(struct v3dv_instance *instance)
1020 {
1021 if (instance->physicalDeviceCount < 0) {
1022 VkResult result = enumerate_devices(instance);
1023 if (result != VK_SUCCESS &&
1024 result != VK_ERROR_INCOMPATIBLE_DRIVER)
1025 return result;
1026 }
1027
1028 return VK_SUCCESS;
1029 }
1030
1031 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_EnumeratePhysicalDevices(VkInstance _instance,uint32_t * pPhysicalDeviceCount,VkPhysicalDevice * pPhysicalDevices)1032 v3dv_EnumeratePhysicalDevices(VkInstance _instance,
1033 uint32_t *pPhysicalDeviceCount,
1034 VkPhysicalDevice *pPhysicalDevices)
1035 {
1036 V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1037 VK_OUTARRAY_MAKE_TYPED(VkPhysicalDevice, out,
1038 pPhysicalDevices, pPhysicalDeviceCount);
1039
1040 VkResult result = instance_ensure_physical_device(instance);
1041 if (result != VK_SUCCESS)
1042 return result;
1043
1044 if (instance->physicalDeviceCount == 0)
1045 return VK_SUCCESS;
1046
1047 assert(instance->physicalDeviceCount == 1);
1048 vk_outarray_append_typed(VkPhysicalDevice, &out, i) {
1049 *i = v3dv_physical_device_to_handle(&instance->physicalDevice);
1050 }
1051
1052 return vk_outarray_status(&out);
1053 }
1054
1055 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_EnumeratePhysicalDeviceGroups(VkInstance _instance,uint32_t * pPhysicalDeviceGroupCount,VkPhysicalDeviceGroupProperties * pPhysicalDeviceGroupProperties)1056 v3dv_EnumeratePhysicalDeviceGroups(
1057 VkInstance _instance,
1058 uint32_t *pPhysicalDeviceGroupCount,
1059 VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties)
1060 {
1061 V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1062 VK_OUTARRAY_MAKE_TYPED(VkPhysicalDeviceGroupProperties, out,
1063 pPhysicalDeviceGroupProperties,
1064 pPhysicalDeviceGroupCount);
1065
1066 VkResult result = instance_ensure_physical_device(instance);
1067 if (result != VK_SUCCESS)
1068 return result;
1069
1070 assert(instance->physicalDeviceCount == 1);
1071
1072 vk_outarray_append_typed(VkPhysicalDeviceGroupProperties, &out, p) {
1073 p->physicalDeviceCount = 1;
1074 memset(p->physicalDevices, 0, sizeof(p->physicalDevices));
1075 p->physicalDevices[0] =
1076 v3dv_physical_device_to_handle(&instance->physicalDevice);
1077 p->subsetAllocation = false;
1078
1079 vk_foreach_struct(ext, p->pNext)
1080 v3dv_debug_ignored_stype(ext->sType);
1081 }
1082
1083 return vk_outarray_status(&out);
1084 }
1085
1086 VKAPI_ATTR void VKAPI_CALL
v3dv_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,VkPhysicalDeviceFeatures * pFeatures)1087 v3dv_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
1088 VkPhysicalDeviceFeatures *pFeatures)
1089 {
1090 memset(pFeatures, 0, sizeof(*pFeatures));
1091
1092 *pFeatures = (VkPhysicalDeviceFeatures) {
1093 .robustBufferAccess = true, /* This feature is mandatory */
1094 .fullDrawIndexUint32 = false, /* Only available since V3D 4.4.9.1 */
1095 .imageCubeArray = true,
1096 .independentBlend = true,
1097 .geometryShader = true,
1098 .tessellationShader = false,
1099 .sampleRateShading = true,
1100 .dualSrcBlend = false,
1101 .logicOp = true,
1102 .multiDrawIndirect = false,
1103 .drawIndirectFirstInstance = true,
1104 .depthClamp = false, /* Only available since V3D 4.5.1.1 */
1105 .depthBiasClamp = true,
1106 .fillModeNonSolid = true,
1107 .depthBounds = false, /* Only available since V3D 4.3.16.2 */
1108 .wideLines = true,
1109 .largePoints = true,
1110 .alphaToOne = true,
1111 .multiViewport = false,
1112 .samplerAnisotropy = true,
1113 .textureCompressionETC2 = true,
1114 .textureCompressionASTC_LDR = true,
1115 /* Note that textureCompressionBC requires that the driver support all
1116 * the BC formats. V3D 4.2 only support the BC1-3, so we can't claim
1117 * that we support it.
1118 */
1119 .textureCompressionBC = false,
1120 .occlusionQueryPrecise = true,
1121 .pipelineStatisticsQuery = false,
1122 .vertexPipelineStoresAndAtomics = true,
1123 .fragmentStoresAndAtomics = true,
1124 .shaderTessellationAndGeometryPointSize = true,
1125 .shaderImageGatherExtended = false,
1126 .shaderStorageImageExtendedFormats = true,
1127 .shaderStorageImageMultisample = false,
1128 .shaderStorageImageReadWithoutFormat = false,
1129 .shaderStorageImageWriteWithoutFormat = false,
1130 .shaderUniformBufferArrayDynamicIndexing = false,
1131 .shaderSampledImageArrayDynamicIndexing = false,
1132 .shaderStorageBufferArrayDynamicIndexing = false,
1133 .shaderStorageImageArrayDynamicIndexing = false,
1134 .shaderClipDistance = true,
1135 .shaderCullDistance = false,
1136 .shaderFloat64 = false,
1137 .shaderInt64 = false,
1138 .shaderInt16 = false,
1139 .shaderResourceResidency = false,
1140 .shaderResourceMinLod = false,
1141 .sparseBinding = false,
1142 .sparseResidencyBuffer = false,
1143 .sparseResidencyImage2D = false,
1144 .sparseResidencyImage3D = false,
1145 .sparseResidency2Samples = false,
1146 .sparseResidency4Samples = false,
1147 .sparseResidency8Samples = false,
1148 .sparseResidency16Samples = false,
1149 .sparseResidencyAliased = false,
1150 .variableMultisampleRate = false,
1151 .inheritedQueries = true,
1152 };
1153 }
1154
1155 VKAPI_ATTR void VKAPI_CALL
v3dv_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceFeatures2 * pFeatures)1156 v3dv_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
1157 VkPhysicalDeviceFeatures2 *pFeatures)
1158 {
1159 V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice);
1160 v3dv_GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features);
1161
1162 VkPhysicalDeviceVulkan13Features vk13 = {
1163 .inlineUniformBlock = true,
1164 /* Inline buffers work like push constants, so after their are bound
1165 * some of their contents may be copied into the uniform stream as soon
1166 * as the next draw/dispatch is recorded in the command buffer. This means
1167 * that if the client updates the buffer contents after binding it to
1168 * a command buffer, the next queue submit of that command buffer may
1169 * not use the latest update to the buffer contents, but the data that
1170 * was present in the buffer at the time it was bound to the command
1171 * buffer.
1172 */
1173 .descriptorBindingInlineUniformBlockUpdateAfterBind = false,
1174 .pipelineCreationCacheControl = true,
1175 .privateData = true,
1176 };
1177
1178 VkPhysicalDeviceVulkan12Features vk12 = {
1179 .hostQueryReset = true,
1180 .uniformAndStorageBuffer8BitAccess = true,
1181 .uniformBufferStandardLayout = true,
1182 /* V3D 4.2 wraps TMU vector accesses to 16-byte boundaries, so loads and
1183 * stores of vectors that cross these boundaries would not work correcly
1184 * with scalarBlockLayout and would need to be split into smaller vectors
1185 * (and/or scalars) that don't cross these boundaries. For load/stores
1186 * with dynamic offsets where we can't identify if the offset is
1187 * problematic, we would always have to scalarize. Overall, this would
1188 * not lead to best performance so let's just not support it.
1189 */
1190 .scalarBlockLayout = false,
1191 /* This tells applications 2 things:
1192 *
1193 * 1. If they can select just one aspect for barriers. For us barriers
1194 * decide if we need to split a job and we don't care if it is only
1195 * for one of the aspects of the image or both, so we don't really
1196 * benefit from seeing barriers that select just one aspect.
1197 *
1198 * 2. If they can program different layouts for each aspect. We
1199 * generally don't care about layouts, so again, we don't get any
1200 * benefits from this to limit the scope of image layout transitions.
1201 *
1202 * Still, Vulkan 1.2 requires this feature to be supported so we
1203 * advertise it even though we don't really take advantage of it.
1204 */
1205 .separateDepthStencilLayouts = true,
1206 .storageBuffer8BitAccess = true,
1207 .storagePushConstant8 = true,
1208 .imagelessFramebuffer = true,
1209 .timelineSemaphore = true,
1210
1211 .samplerMirrorClampToEdge = true,
1212
1213 /* These are mandatory by Vulkan 1.2, however, we don't support any of
1214 * the optional features affected by them (non 32-bit types for
1215 * shaderSubgroupExtendedTypes and additional subgroup ballot for
1216 * subgroupBroadcastDynamicId), so in practice setting them to true
1217 * doesn't have any implications for us until we implement any of these
1218 * optional features.
1219 */
1220 .shaderSubgroupExtendedTypes = true,
1221 .subgroupBroadcastDynamicId = true,
1222
1223 .vulkanMemoryModel = true,
1224 .vulkanMemoryModelDeviceScope = true,
1225 .vulkanMemoryModelAvailabilityVisibilityChains = true,
1226
1227 .bufferDeviceAddress = true,
1228 .bufferDeviceAddressCaptureReplay = false,
1229 .bufferDeviceAddressMultiDevice = false,
1230 };
1231
1232 VkPhysicalDeviceVulkan11Features vk11 = {
1233 .storageBuffer16BitAccess = true,
1234 .uniformAndStorageBuffer16BitAccess = true,
1235 .storagePushConstant16 = true,
1236 .storageInputOutput16 = false,
1237 .multiview = true,
1238 .multiviewGeometryShader = false,
1239 .multiviewTessellationShader = false,
1240 .variablePointersStorageBuffer = true,
1241 /* FIXME: this needs support for non-constant index on UBO/SSBO */
1242 .variablePointers = false,
1243 .protectedMemory = false,
1244 .samplerYcbcrConversion = false,
1245 .shaderDrawParameters = false,
1246 };
1247
1248 vk_foreach_struct(ext, pFeatures->pNext) {
1249 if (vk_get_physical_device_core_1_1_feature_ext(ext, &vk11))
1250 continue;
1251 if (vk_get_physical_device_core_1_2_feature_ext(ext, &vk12))
1252 continue;
1253 if (vk_get_physical_device_core_1_3_feature_ext(ext, &vk13))
1254 continue;
1255
1256 switch (ext->sType) {
1257 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: {
1258 VkPhysicalDevice4444FormatsFeaturesEXT *features =
1259 (VkPhysicalDevice4444FormatsFeaturesEXT *)ext;
1260 features->formatA4R4G4B4 = true;
1261 features->formatA4B4G4R4 = true;
1262 break;
1263 }
1264
1265 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: {
1266 VkPhysicalDeviceCustomBorderColorFeaturesEXT *features =
1267 (VkPhysicalDeviceCustomBorderColorFeaturesEXT *)ext;
1268 features->customBorderColors = true;
1269 features->customBorderColorWithoutFormat = false;
1270 break;
1271 }
1272
1273 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT: {
1274 VkPhysicalDeviceIndexTypeUint8FeaturesEXT *features =
1275 (VkPhysicalDeviceIndexTypeUint8FeaturesEXT *)ext;
1276 features->indexTypeUint8 = true;
1277 break;
1278 }
1279
1280 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT: {
1281 VkPhysicalDeviceLineRasterizationFeaturesEXT *features =
1282 (VkPhysicalDeviceLineRasterizationFeaturesEXT *)ext;
1283 features->rectangularLines = true;
1284 features->bresenhamLines = true;
1285 features->smoothLines = false;
1286 features->stippledRectangularLines = false;
1287 features->stippledBresenhamLines = false;
1288 features->stippledSmoothLines = false;
1289 break;
1290 }
1291
1292 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
1293 VkPhysicalDeviceColorWriteEnableFeaturesEXT *features = (void *) ext;
1294 features->colorWriteEnable = true;
1295 break;
1296 }
1297
1298 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR: {
1299 VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR *features =
1300 (VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR *) ext;
1301 features->pipelineExecutableInfo = true;
1302 break;
1303 }
1304
1305 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT: {
1306 VkPhysicalDeviceProvokingVertexFeaturesEXT *features = (void *) ext;
1307 features->provokingVertexLast = true;
1308 /* FIXME: update when supporting EXT_transform_feedback */
1309 features->transformFeedbackPreservesProvokingVertex = false;
1310 break;
1311 }
1312
1313 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: {
1314 VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *features =
1315 (void *) ext;
1316 features->vertexAttributeInstanceRateDivisor = true;
1317 features->vertexAttributeInstanceRateZeroDivisor = false;
1318 break;
1319 }
1320
1321 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR: {
1322 VkPhysicalDevicePerformanceQueryFeaturesKHR *features =
1323 (void *) ext;
1324
1325 features->performanceCounterQueryPools =
1326 physical_device->caps.perfmon;
1327 features->performanceCounterMultipleQueryPools = false;
1328 break;
1329 }
1330
1331 default:
1332 v3dv_debug_ignored_stype(ext->sType);
1333 break;
1334 }
1335 }
1336 }
1337
1338 VKAPI_ATTR void VKAPI_CALL
v3dv_GetDeviceGroupPeerMemoryFeatures(VkDevice device,uint32_t heapIndex,uint32_t localDeviceIndex,uint32_t remoteDeviceIndex,VkPeerMemoryFeatureFlags * pPeerMemoryFeatures)1339 v3dv_GetDeviceGroupPeerMemoryFeatures(VkDevice device,
1340 uint32_t heapIndex,
1341 uint32_t localDeviceIndex,
1342 uint32_t remoteDeviceIndex,
1343 VkPeerMemoryFeatureFlags *pPeerMemoryFeatures)
1344 {
1345 assert(localDeviceIndex == 0 && remoteDeviceIndex == 0);
1346 *pPeerMemoryFeatures = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT |
1347 VK_PEER_MEMORY_FEATURE_COPY_DST_BIT |
1348 VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT |
1349 VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT;
1350 }
1351
1352 uint32_t
v3dv_physical_device_vendor_id(struct v3dv_physical_device * dev)1353 v3dv_physical_device_vendor_id(struct v3dv_physical_device *dev)
1354 {
1355 return 0x14E4; /* Broadcom */
1356 }
1357
1358 uint32_t
v3dv_physical_device_device_id(struct v3dv_physical_device * dev)1359 v3dv_physical_device_device_id(struct v3dv_physical_device *dev)
1360 {
1361 #if using_v3d_simulator
1362 return dev->device_id;
1363 #else
1364 switch (dev->devinfo.ver) {
1365 case 42:
1366 return 0xBE485FD3; /* Broadcom deviceID for 2711 */
1367 default:
1368 unreachable("Unsupported V3D version");
1369 }
1370 #endif
1371 }
1372
1373 VKAPI_ATTR void VKAPI_CALL
v3dv_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,VkPhysicalDeviceProperties * pProperties)1374 v3dv_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
1375 VkPhysicalDeviceProperties *pProperties)
1376 {
1377 V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice);
1378
1379 STATIC_ASSERT(MAX_SAMPLED_IMAGES + MAX_STORAGE_IMAGES + MAX_INPUT_ATTACHMENTS
1380 <= V3D_MAX_TEXTURE_SAMPLERS);
1381 STATIC_ASSERT(MAX_UNIFORM_BUFFERS >= MAX_DYNAMIC_UNIFORM_BUFFERS);
1382 STATIC_ASSERT(MAX_STORAGE_BUFFERS >= MAX_DYNAMIC_STORAGE_BUFFERS);
1383
1384 const uint32_t page_size = 4096;
1385 const uint32_t mem_size = compute_heap_size();
1386
1387 const uint32_t max_varying_components = 16 * 4;
1388
1389 const float v3d_point_line_granularity = 2.0f / (1 << V3D_COORD_SHIFT);
1390 const uint32_t max_fb_size = V3D_MAX_IMAGE_DIMENSION;
1391
1392 const VkSampleCountFlags supported_sample_counts =
1393 VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
1394
1395 struct timespec clock_res;
1396 clock_getres(CLOCK_MONOTONIC, &clock_res);
1397 const float timestamp_period =
1398 clock_res.tv_sec * 1000000000.0f + clock_res.tv_nsec;
1399
1400 /* FIXME: this will probably require an in-depth review */
1401 VkPhysicalDeviceLimits limits = {
1402 .maxImageDimension1D = V3D_MAX_IMAGE_DIMENSION,
1403 .maxImageDimension2D = V3D_MAX_IMAGE_DIMENSION,
1404 .maxImageDimension3D = V3D_MAX_IMAGE_DIMENSION,
1405 .maxImageDimensionCube = V3D_MAX_IMAGE_DIMENSION,
1406 .maxImageArrayLayers = V3D_MAX_ARRAY_LAYERS,
1407 .maxTexelBufferElements = (1ul << 28),
1408 .maxUniformBufferRange = V3D_MAX_BUFFER_RANGE,
1409 .maxStorageBufferRange = V3D_MAX_BUFFER_RANGE,
1410 .maxPushConstantsSize = MAX_PUSH_CONSTANTS_SIZE,
1411 .maxMemoryAllocationCount = mem_size / page_size,
1412 .maxSamplerAllocationCount = 64 * 1024,
1413 .bufferImageGranularity = V3D_NON_COHERENT_ATOM_SIZE,
1414 .sparseAddressSpaceSize = 0,
1415 .maxBoundDescriptorSets = MAX_SETS,
1416 .maxPerStageDescriptorSamplers = V3D_MAX_TEXTURE_SAMPLERS,
1417 .maxPerStageDescriptorUniformBuffers = MAX_UNIFORM_BUFFERS,
1418 .maxPerStageDescriptorStorageBuffers = MAX_STORAGE_BUFFERS,
1419 .maxPerStageDescriptorSampledImages = MAX_SAMPLED_IMAGES,
1420 .maxPerStageDescriptorStorageImages = MAX_STORAGE_IMAGES,
1421 .maxPerStageDescriptorInputAttachments = MAX_INPUT_ATTACHMENTS,
1422 .maxPerStageResources = 128,
1423
1424 /* Some of these limits are multiplied by 6 because they need to
1425 * include all possible shader stages (even if not supported). See
1426 * 'Required Limits' table in the Vulkan spec.
1427 */
1428 .maxDescriptorSetSamplers = 6 * V3D_MAX_TEXTURE_SAMPLERS,
1429 .maxDescriptorSetUniformBuffers = 6 * MAX_UNIFORM_BUFFERS,
1430 .maxDescriptorSetUniformBuffersDynamic = MAX_DYNAMIC_UNIFORM_BUFFERS,
1431 .maxDescriptorSetStorageBuffers = 6 * MAX_STORAGE_BUFFERS,
1432 .maxDescriptorSetStorageBuffersDynamic = MAX_DYNAMIC_STORAGE_BUFFERS,
1433 .maxDescriptorSetSampledImages = 6 * MAX_SAMPLED_IMAGES,
1434 .maxDescriptorSetStorageImages = 6 * MAX_STORAGE_IMAGES,
1435 .maxDescriptorSetInputAttachments = MAX_INPUT_ATTACHMENTS,
1436
1437 /* Vertex limits */
1438 .maxVertexInputAttributes = MAX_VERTEX_ATTRIBS,
1439 .maxVertexInputBindings = MAX_VBS,
1440 .maxVertexInputAttributeOffset = 0xffffffff,
1441 .maxVertexInputBindingStride = 0xffffffff,
1442 .maxVertexOutputComponents = max_varying_components,
1443
1444 /* Tessellation limits */
1445 .maxTessellationGenerationLevel = 0,
1446 .maxTessellationPatchSize = 0,
1447 .maxTessellationControlPerVertexInputComponents = 0,
1448 .maxTessellationControlPerVertexOutputComponents = 0,
1449 .maxTessellationControlPerPatchOutputComponents = 0,
1450 .maxTessellationControlTotalOutputComponents = 0,
1451 .maxTessellationEvaluationInputComponents = 0,
1452 .maxTessellationEvaluationOutputComponents = 0,
1453
1454 /* Geometry limits */
1455 .maxGeometryShaderInvocations = 32,
1456 .maxGeometryInputComponents = 64,
1457 .maxGeometryOutputComponents = 64,
1458 .maxGeometryOutputVertices = 256,
1459 .maxGeometryTotalOutputComponents = 1024,
1460
1461 /* Fragment limits */
1462 .maxFragmentInputComponents = max_varying_components,
1463 .maxFragmentOutputAttachments = 4,
1464 .maxFragmentDualSrcAttachments = 0,
1465 .maxFragmentCombinedOutputResources = MAX_RENDER_TARGETS +
1466 MAX_STORAGE_BUFFERS +
1467 MAX_STORAGE_IMAGES,
1468
1469 /* Compute limits */
1470 .maxComputeSharedMemorySize = 16384,
1471 .maxComputeWorkGroupCount = { 65535, 65535, 65535 },
1472 .maxComputeWorkGroupInvocations = 256,
1473 .maxComputeWorkGroupSize = { 256, 256, 256 },
1474
1475 .subPixelPrecisionBits = V3D_COORD_SHIFT,
1476 .subTexelPrecisionBits = 8,
1477 .mipmapPrecisionBits = 8,
1478 .maxDrawIndexedIndexValue = 0x00ffffff,
1479 .maxDrawIndirectCount = 0x7fffffff,
1480 .maxSamplerLodBias = 14.0f,
1481 .maxSamplerAnisotropy = 16.0f,
1482 .maxViewports = MAX_VIEWPORTS,
1483 .maxViewportDimensions = { max_fb_size, max_fb_size },
1484 .viewportBoundsRange = { -2.0 * max_fb_size,
1485 2.0 * max_fb_size - 1 },
1486 .viewportSubPixelBits = 0,
1487 .minMemoryMapAlignment = page_size,
1488 .minTexelBufferOffsetAlignment = V3D_UIFBLOCK_SIZE,
1489 .minUniformBufferOffsetAlignment = 32,
1490 .minStorageBufferOffsetAlignment = 32,
1491 .minTexelOffset = -8,
1492 .maxTexelOffset = 7,
1493 .minTexelGatherOffset = -8,
1494 .maxTexelGatherOffset = 7,
1495 .minInterpolationOffset = -0.5,
1496 .maxInterpolationOffset = 0.5,
1497 .subPixelInterpolationOffsetBits = V3D_COORD_SHIFT,
1498 .maxFramebufferWidth = max_fb_size,
1499 .maxFramebufferHeight = max_fb_size,
1500 .maxFramebufferLayers = 256,
1501 .framebufferColorSampleCounts = supported_sample_counts,
1502 .framebufferDepthSampleCounts = supported_sample_counts,
1503 .framebufferStencilSampleCounts = supported_sample_counts,
1504 .framebufferNoAttachmentsSampleCounts = supported_sample_counts,
1505 .maxColorAttachments = MAX_RENDER_TARGETS,
1506 .sampledImageColorSampleCounts = supported_sample_counts,
1507 .sampledImageIntegerSampleCounts = supported_sample_counts,
1508 .sampledImageDepthSampleCounts = supported_sample_counts,
1509 .sampledImageStencilSampleCounts = supported_sample_counts,
1510 .storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT,
1511 .maxSampleMaskWords = 1,
1512 .timestampComputeAndGraphics = true,
1513 .timestampPeriod = timestamp_period,
1514 .maxClipDistances = 8,
1515 .maxCullDistances = 0,
1516 .maxCombinedClipAndCullDistances = 8,
1517 .discreteQueuePriorities = 2,
1518 .pointSizeRange = { v3d_point_line_granularity,
1519 V3D_MAX_POINT_SIZE },
1520 .lineWidthRange = { 1.0f, V3D_MAX_LINE_WIDTH },
1521 .pointSizeGranularity = v3d_point_line_granularity,
1522 .lineWidthGranularity = v3d_point_line_granularity,
1523 .strictLines = true,
1524 .standardSampleLocations = false,
1525 .optimalBufferCopyOffsetAlignment = 32,
1526 .optimalBufferCopyRowPitchAlignment = 32,
1527 .nonCoherentAtomSize = V3D_NON_COHERENT_ATOM_SIZE,
1528 };
1529
1530 *pProperties = (VkPhysicalDeviceProperties) {
1531 .apiVersion = V3DV_API_VERSION,
1532 .driverVersion = vk_get_driver_version(),
1533 .vendorID = v3dv_physical_device_vendor_id(pdevice),
1534 .deviceID = v3dv_physical_device_device_id(pdevice),
1535 .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
1536 .limits = limits,
1537 .sparseProperties = { 0 },
1538 };
1539
1540 snprintf(pProperties->deviceName, sizeof(pProperties->deviceName),
1541 "%s", pdevice->name);
1542 memcpy(pProperties->pipelineCacheUUID,
1543 pdevice->pipeline_cache_uuid, VK_UUID_SIZE);
1544 }
1545
1546 VKAPI_ATTR void VKAPI_CALL
v3dv_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceProperties2 * pProperties)1547 v3dv_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
1548 VkPhysicalDeviceProperties2 *pProperties)
1549 {
1550 V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice);
1551
1552 v3dv_GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties);
1553
1554 /* We don't really have special restrictions for the maximum
1555 * descriptors per set, other than maybe not exceeding the limits
1556 * of addressable memory in a single allocation on either the host
1557 * or the GPU. This will be a much larger limit than any of the
1558 * per-stage limits already available in Vulkan though, so in practice,
1559 * it is not expected to limit anything beyond what is already
1560 * constrained through per-stage limits.
1561 */
1562 const uint32_t max_host_descriptors =
1563 (UINT32_MAX - sizeof(struct v3dv_descriptor_set)) /
1564 sizeof(struct v3dv_descriptor);
1565 const uint32_t max_gpu_descriptors =
1566 (UINT32_MAX / v3dv_X(pdevice, max_descriptor_bo_size)());
1567
1568 VkPhysicalDeviceVulkan13Properties vk13 = {
1569 .maxInlineUniformBlockSize = 4096,
1570 .maxPerStageDescriptorInlineUniformBlocks = MAX_INLINE_UNIFORM_BUFFERS,
1571 .maxDescriptorSetInlineUniformBlocks = MAX_INLINE_UNIFORM_BUFFERS,
1572 .maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks =
1573 MAX_INLINE_UNIFORM_BUFFERS,
1574 .maxDescriptorSetUpdateAfterBindInlineUniformBlocks =
1575 MAX_INLINE_UNIFORM_BUFFERS,
1576 };
1577
1578 VkPhysicalDeviceVulkan12Properties vk12 = {
1579 .driverID = VK_DRIVER_ID_MESA_V3DV,
1580 .conformanceVersion = {
1581 .major = 1,
1582 .minor = 2,
1583 .subminor = 7,
1584 .patch = 1,
1585 },
1586 .supportedDepthResolveModes = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT,
1587 .supportedStencilResolveModes = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT,
1588 /* FIXME: if we want to support independentResolveNone then we would
1589 * need to honor attachment load operations on resolve attachments,
1590 * which we currently ignore because the resolve makes them irrelevant,
1591 * as it unconditionally writes all pixels in the render area. However,
1592 * with independentResolveNone, it is possible to have one aspect of a
1593 * D/S resolve attachment stay unresolved, in which case the attachment
1594 * load operation is relevant.
1595 *
1596 * NOTE: implementing attachment load for resolve attachments isn't
1597 * immediately trivial because these attachments are not part of the
1598 * framebuffer and therefore we can't use the same mechanism we use
1599 * for framebuffer attachments. Instead, we should probably have to
1600 * emit a meta operation for that right at the start of the render
1601 * pass (or subpass).
1602 */
1603 .independentResolveNone = false,
1604 .independentResolve = false,
1605 .maxTimelineSemaphoreValueDifference = UINT64_MAX,
1606
1607 .denormBehaviorIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
1608 .roundingModeIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
1609 .shaderSignedZeroInfNanPreserveFloat16 = true,
1610 .shaderSignedZeroInfNanPreserveFloat32 = true,
1611 .shaderSignedZeroInfNanPreserveFloat64 = false,
1612 .shaderDenormPreserveFloat16 = true,
1613 .shaderDenormPreserveFloat32 = true,
1614 .shaderDenormPreserveFloat64 = false,
1615 .shaderDenormFlushToZeroFloat16 = false,
1616 .shaderDenormFlushToZeroFloat32 = false,
1617 .shaderDenormFlushToZeroFloat64 = false,
1618 .shaderRoundingModeRTEFloat16 = true,
1619 .shaderRoundingModeRTEFloat32 = true,
1620 .shaderRoundingModeRTEFloat64 = false,
1621 .shaderRoundingModeRTZFloat16 = false,
1622 .shaderRoundingModeRTZFloat32 = false,
1623 .shaderRoundingModeRTZFloat64 = false,
1624
1625 /* V3D doesn't support min/max filtering */
1626 .filterMinmaxSingleComponentFormats = false,
1627 .filterMinmaxImageComponentMapping = false,
1628
1629 .framebufferIntegerColorSampleCounts =
1630 VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT,
1631 };
1632 memset(vk12.driverName, 0, VK_MAX_DRIVER_NAME_SIZE);
1633 snprintf(vk12.driverName, VK_MAX_DRIVER_NAME_SIZE, "V3DV Mesa");
1634 memset(vk12.driverInfo, 0, VK_MAX_DRIVER_INFO_SIZE);
1635 snprintf(vk12.driverInfo, VK_MAX_DRIVER_INFO_SIZE,
1636 "Mesa " PACKAGE_VERSION MESA_GIT_SHA1);
1637
1638 VkPhysicalDeviceVulkan11Properties vk11 = {
1639 .deviceLUIDValid = false,
1640 .subgroupSize = V3D_CHANNELS,
1641 .subgroupSupportedStages = VK_SHADER_STAGE_COMPUTE_BIT,
1642 .subgroupSupportedOperations = VK_SUBGROUP_FEATURE_BASIC_BIT,
1643 .subgroupQuadOperationsInAllStages = false,
1644 .pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES,
1645 .maxMultiviewViewCount = MAX_MULTIVIEW_VIEW_COUNT,
1646 .maxMultiviewInstanceIndex = UINT32_MAX - 1,
1647 .protectedNoFault = false,
1648 .maxPerSetDescriptors = MIN2(max_host_descriptors, max_gpu_descriptors),
1649 /* Minimum required by the spec */
1650 .maxMemoryAllocationSize = MAX_MEMORY_ALLOCATION_SIZE,
1651 };
1652 memcpy(vk11.deviceUUID, pdevice->device_uuid, VK_UUID_SIZE);
1653 memcpy(vk11.driverUUID, pdevice->driver_uuid, VK_UUID_SIZE);
1654
1655
1656 vk_foreach_struct(ext, pProperties->pNext) {
1657 if (vk_get_physical_device_core_1_1_property_ext(ext, &vk11))
1658 continue;
1659 if (vk_get_physical_device_core_1_2_property_ext(ext, &vk12))
1660 continue;
1661 if (vk_get_physical_device_core_1_3_property_ext(ext, &vk13))
1662 continue;
1663
1664 switch (ext->sType) {
1665 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT: {
1666 VkPhysicalDeviceCustomBorderColorPropertiesEXT *props =
1667 (VkPhysicalDeviceCustomBorderColorPropertiesEXT *)ext;
1668 props->maxCustomBorderColorSamplers = V3D_MAX_TEXTURE_SAMPLERS;
1669 break;
1670 }
1671 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT: {
1672 VkPhysicalDeviceProvokingVertexPropertiesEXT *props =
1673 (VkPhysicalDeviceProvokingVertexPropertiesEXT *)ext;
1674 props->provokingVertexModePerPipeline = true;
1675 /* FIXME: update when supporting EXT_transform_feedback */
1676 props->transformFeedbackPreservesTriangleFanProvokingVertex = false;
1677 break;
1678 }
1679 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
1680 VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *props =
1681 (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)ext;
1682 props->maxVertexAttribDivisor = 0xffff;
1683 break;
1684 }
1685 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR : {
1686 VkPhysicalDevicePerformanceQueryPropertiesKHR *props =
1687 (VkPhysicalDevicePerformanceQueryPropertiesKHR *)ext;
1688
1689 props->allowCommandBufferQueryCopies = true;
1690 break;
1691 }
1692 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT: {
1693 VkPhysicalDeviceDrmPropertiesEXT *props =
1694 (VkPhysicalDeviceDrmPropertiesEXT *)ext;
1695 props->hasPrimary = pdevice->has_primary;
1696 if (props->hasPrimary) {
1697 props->primaryMajor = (int64_t) major(pdevice->primary_devid);
1698 props->primaryMinor = (int64_t) minor(pdevice->primary_devid);
1699 }
1700 props->hasRender = pdevice->has_render;
1701 if (props->hasRender) {
1702 props->renderMajor = (int64_t) major(pdevice->render_devid);
1703 props->renderMinor = (int64_t) minor(pdevice->render_devid);
1704 }
1705 break;
1706 }
1707 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT: {
1708 VkPhysicalDeviceLineRasterizationPropertiesEXT *props =
1709 (VkPhysicalDeviceLineRasterizationPropertiesEXT *)ext;
1710 props->lineSubPixelPrecisionBits = V3D_COORD_SHIFT;
1711 break;
1712 }
1713 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT:
1714 /* Do nothing, not even logging. This is a non-PCI device, so we will
1715 * never provide this extension.
1716 */
1717 break;
1718 default:
1719 v3dv_debug_ignored_stype(ext->sType);
1720 break;
1721 }
1722 }
1723 }
1724
1725 /* We support exactly one queue family. */
1726 static const VkQueueFamilyProperties
1727 v3dv_queue_family_properties = {
1728 .queueFlags = VK_QUEUE_GRAPHICS_BIT |
1729 VK_QUEUE_COMPUTE_BIT |
1730 VK_QUEUE_TRANSFER_BIT,
1731 .queueCount = 1,
1732 .timestampValidBits = 64,
1733 .minImageTransferGranularity = { 1, 1, 1 },
1734 };
1735
1736 VKAPI_ATTR void VKAPI_CALL
v3dv_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,uint32_t * pQueueFamilyPropertyCount,VkQueueFamilyProperties2 * pQueueFamilyProperties)1737 v3dv_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
1738 uint32_t *pQueueFamilyPropertyCount,
1739 VkQueueFamilyProperties2 *pQueueFamilyProperties)
1740 {
1741 VK_OUTARRAY_MAKE_TYPED(VkQueueFamilyProperties2, out,
1742 pQueueFamilyProperties, pQueueFamilyPropertyCount);
1743
1744 vk_outarray_append_typed(VkQueueFamilyProperties2, &out, p) {
1745 p->queueFamilyProperties = v3dv_queue_family_properties;
1746
1747 vk_foreach_struct(s, p->pNext) {
1748 v3dv_debug_ignored_stype(s->sType);
1749 }
1750 }
1751 }
1752
1753 VKAPI_ATTR void VKAPI_CALL
v3dv_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,VkPhysicalDeviceMemoryProperties * pMemoryProperties)1754 v3dv_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
1755 VkPhysicalDeviceMemoryProperties *pMemoryProperties)
1756 {
1757 V3DV_FROM_HANDLE(v3dv_physical_device, device, physicalDevice);
1758 *pMemoryProperties = device->memory;
1759 }
1760
1761 VKAPI_ATTR void VKAPI_CALL
v3dv_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceMemoryProperties2 * pMemoryProperties)1762 v3dv_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,
1763 VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
1764 {
1765 v3dv_GetPhysicalDeviceMemoryProperties(physicalDevice,
1766 &pMemoryProperties->memoryProperties);
1767
1768 vk_foreach_struct(ext, pMemoryProperties->pNext) {
1769 switch (ext->sType) {
1770 default:
1771 v3dv_debug_ignored_stype(ext->sType);
1772 break;
1773 }
1774 }
1775 }
1776
1777 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
v3dv_GetInstanceProcAddr(VkInstance _instance,const char * pName)1778 v3dv_GetInstanceProcAddr(VkInstance _instance,
1779 const char *pName)
1780 {
1781 V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1782 return vk_instance_get_proc_addr(&instance->vk,
1783 &v3dv_instance_entrypoints,
1784 pName);
1785 }
1786
1787 /* With version 1+ of the loader interface the ICD should expose
1788 * vk_icdGetInstanceProcAddr to work around certain LD_PRELOAD issues seen in apps.
1789 */
1790 PUBLIC
1791 VKAPI_ATTR PFN_vkVoidFunction
1792 VKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance,
1793 const char *pName);
1794
1795 PUBLIC
1796 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
vk_icdGetInstanceProcAddr(VkInstance instance,const char * pName)1797 vk_icdGetInstanceProcAddr(VkInstance instance,
1798 const char* pName)
1799 {
1800 return v3dv_GetInstanceProcAddr(instance, pName);
1801 }
1802
1803 /* With version 4+ of the loader interface the ICD should expose
1804 * vk_icdGetPhysicalDeviceProcAddr()
1805 */
1806 PUBLIC
1807 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
1808 vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,
1809 const char* pName);
1810
1811 PFN_vkVoidFunction
vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,const char * pName)1812 vk_icdGetPhysicalDeviceProcAddr(VkInstance _instance,
1813 const char* pName)
1814 {
1815 V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
1816
1817 return vk_instance_get_physical_device_proc_addr(&instance->vk, pName);
1818 }
1819
1820 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_EnumerateInstanceLayerProperties(uint32_t * pPropertyCount,VkLayerProperties * pProperties)1821 v3dv_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
1822 VkLayerProperties *pProperties)
1823 {
1824 if (pProperties == NULL) {
1825 *pPropertyCount = 0;
1826 return VK_SUCCESS;
1827 }
1828
1829 return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
1830 }
1831
1832 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,uint32_t * pPropertyCount,VkLayerProperties * pProperties)1833 v3dv_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,
1834 uint32_t *pPropertyCount,
1835 VkLayerProperties *pProperties)
1836 {
1837 V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice);
1838
1839 if (pProperties == NULL) {
1840 *pPropertyCount = 0;
1841 return VK_SUCCESS;
1842 }
1843
1844 return vk_error(physical_device, VK_ERROR_LAYER_NOT_PRESENT);
1845 }
1846
1847 static void
destroy_queue_syncs(struct v3dv_queue * queue)1848 destroy_queue_syncs(struct v3dv_queue *queue)
1849 {
1850 for (int i = 0; i < V3DV_QUEUE_COUNT; i++) {
1851 if (queue->last_job_syncs.syncs[i]) {
1852 drmSyncobjDestroy(queue->device->pdevice->render_fd,
1853 queue->last_job_syncs.syncs[i]);
1854 }
1855 }
1856 }
1857
1858 static VkResult
queue_init(struct v3dv_device * device,struct v3dv_queue * queue,const VkDeviceQueueCreateInfo * create_info,uint32_t index_in_family)1859 queue_init(struct v3dv_device *device, struct v3dv_queue *queue,
1860 const VkDeviceQueueCreateInfo *create_info,
1861 uint32_t index_in_family)
1862 {
1863 VkResult result = vk_queue_init(&queue->vk, &device->vk, create_info,
1864 index_in_family);
1865 if (result != VK_SUCCESS)
1866 return result;
1867
1868 result = vk_queue_enable_submit_thread(&queue->vk);
1869 if (result != VK_SUCCESS)
1870 goto fail_submit_thread;
1871
1872 queue->device = device;
1873 queue->vk.driver_submit = v3dv_queue_driver_submit;
1874
1875 for (int i = 0; i < V3DV_QUEUE_COUNT; i++) {
1876 queue->last_job_syncs.first[i] = true;
1877 int ret = drmSyncobjCreate(device->pdevice->render_fd,
1878 DRM_SYNCOBJ_CREATE_SIGNALED,
1879 &queue->last_job_syncs.syncs[i]);
1880 if (ret) {
1881 result = vk_errorf(device, VK_ERROR_INITIALIZATION_FAILED,
1882 "syncobj create failed: %m");
1883 goto fail_last_job_syncs;
1884 }
1885 }
1886
1887 queue->noop_job = NULL;
1888 return VK_SUCCESS;
1889
1890 fail_last_job_syncs:
1891 destroy_queue_syncs(queue);
1892 fail_submit_thread:
1893 vk_queue_finish(&queue->vk);
1894 return result;
1895 }
1896
1897 static void
queue_finish(struct v3dv_queue * queue)1898 queue_finish(struct v3dv_queue *queue)
1899 {
1900 if (queue->noop_job)
1901 v3dv_job_destroy(queue->noop_job);
1902 destroy_queue_syncs(queue);
1903 vk_queue_finish(&queue->vk);
1904 }
1905
1906 static void
init_device_meta(struct v3dv_device * device)1907 init_device_meta(struct v3dv_device *device)
1908 {
1909 mtx_init(&device->meta.mtx, mtx_plain);
1910 v3dv_meta_clear_init(device);
1911 v3dv_meta_blit_init(device);
1912 v3dv_meta_texel_buffer_copy_init(device);
1913 }
1914
1915 static void
destroy_device_meta(struct v3dv_device * device)1916 destroy_device_meta(struct v3dv_device *device)
1917 {
1918 mtx_destroy(&device->meta.mtx);
1919 v3dv_meta_clear_finish(device);
1920 v3dv_meta_blit_finish(device);
1921 v3dv_meta_texel_buffer_copy_finish(device);
1922 }
1923
1924 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_CreateDevice(VkPhysicalDevice physicalDevice,const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDevice * pDevice)1925 v3dv_CreateDevice(VkPhysicalDevice physicalDevice,
1926 const VkDeviceCreateInfo *pCreateInfo,
1927 const VkAllocationCallbacks *pAllocator,
1928 VkDevice *pDevice)
1929 {
1930 V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice);
1931 struct v3dv_instance *instance = (struct v3dv_instance*) physical_device->vk.instance;
1932 VkResult result;
1933 struct v3dv_device *device;
1934
1935 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);
1936
1937 /* Check requested queues (we only expose one queue ) */
1938 assert(pCreateInfo->queueCreateInfoCount == 1);
1939 for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
1940 assert(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex == 0);
1941 assert(pCreateInfo->pQueueCreateInfos[i].queueCount == 1);
1942 if (pCreateInfo->pQueueCreateInfos[i].flags != 0)
1943 return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);
1944 }
1945
1946 device = vk_zalloc2(&physical_device->vk.instance->alloc, pAllocator,
1947 sizeof(*device), 8,
1948 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1949 if (!device)
1950 return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1951
1952 struct vk_device_dispatch_table dispatch_table;
1953 vk_device_dispatch_table_from_entrypoints(&dispatch_table,
1954 &v3dv_device_entrypoints, true);
1955 vk_device_dispatch_table_from_entrypoints(&dispatch_table,
1956 &wsi_device_entrypoints, false);
1957 result = vk_device_init(&device->vk, &physical_device->vk,
1958 &dispatch_table, pCreateInfo, pAllocator);
1959 if (result != VK_SUCCESS) {
1960 vk_free(&device->vk.alloc, device);
1961 return vk_error(NULL, result);
1962 }
1963
1964 device->instance = instance;
1965 device->pdevice = physical_device;
1966
1967 mtx_init(&device->query_mutex, mtx_plain);
1968 cnd_init(&device->query_ended);
1969
1970 vk_device_set_drm_fd(&device->vk, physical_device->render_fd);
1971 vk_device_enable_threaded_submit(&device->vk);
1972
1973 result = queue_init(device, &device->queue,
1974 pCreateInfo->pQueueCreateInfos, 0);
1975 if (result != VK_SUCCESS)
1976 goto fail;
1977
1978 device->devinfo = physical_device->devinfo;
1979
1980 /* Vulkan 1.1 and VK_KHR_get_physical_device_properties2 added
1981 * VkPhysicalDeviceFeatures2 which can be used in the pNext chain of
1982 * vkDeviceCreateInfo, in which case it should be used instead of
1983 * pEnabledFeatures.
1984 */
1985 const VkPhysicalDeviceFeatures2 *features2 =
1986 vk_find_struct_const(pCreateInfo->pNext, PHYSICAL_DEVICE_FEATURES_2);
1987 if (features2) {
1988 memcpy(&device->features, &features2->features,
1989 sizeof(device->features));
1990 } else if (pCreateInfo->pEnabledFeatures) {
1991 memcpy(&device->features, pCreateInfo->pEnabledFeatures,
1992 sizeof(device->features));
1993 }
1994
1995 if (device->features.robustBufferAccess)
1996 perf_debug("Device created with Robust Buffer Access enabled.\n");
1997
1998 #ifdef DEBUG
1999 v3dv_X(device, device_check_prepacked_sizes)();
2000 #endif
2001 init_device_meta(device);
2002 v3dv_bo_cache_init(device);
2003 v3dv_pipeline_cache_init(&device->default_pipeline_cache, device, 0,
2004 device->instance->default_pipeline_cache_enabled);
2005 device->default_attribute_float =
2006 v3dv_pipeline_create_default_attribute_values(device, NULL);
2007
2008 device->device_address_mem_ctx = ralloc_context(NULL);
2009 util_dynarray_init(&device->device_address_bo_list,
2010 device->device_address_mem_ctx);
2011
2012 *pDevice = v3dv_device_to_handle(device);
2013
2014 return VK_SUCCESS;
2015
2016 fail:
2017 cnd_destroy(&device->query_ended);
2018 mtx_destroy(&device->query_mutex);
2019 queue_finish(&device->queue);
2020 destroy_device_meta(device);
2021 v3dv_pipeline_cache_finish(&device->default_pipeline_cache);
2022 vk_device_finish(&device->vk);
2023 vk_free(&device->vk.alloc, device);
2024
2025 return result;
2026 }
2027
2028 VKAPI_ATTR void VKAPI_CALL
v3dv_DestroyDevice(VkDevice _device,const VkAllocationCallbacks * pAllocator)2029 v3dv_DestroyDevice(VkDevice _device,
2030 const VkAllocationCallbacks *pAllocator)
2031 {
2032 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2033
2034 device->vk.dispatch_table.DeviceWaitIdle(_device);
2035 queue_finish(&device->queue);
2036 destroy_device_meta(device);
2037 v3dv_pipeline_cache_finish(&device->default_pipeline_cache);
2038
2039 if (device->default_attribute_float) {
2040 v3dv_bo_free(device, device->default_attribute_float);
2041 device->default_attribute_float = NULL;
2042 }
2043
2044 ralloc_free(device->device_address_mem_ctx);
2045
2046 /* Bo cache should be removed the last, as any other object could be
2047 * freeing their private bos
2048 */
2049 v3dv_bo_cache_destroy(device);
2050
2051 cnd_destroy(&device->query_ended);
2052 mtx_destroy(&device->query_mutex);
2053
2054 vk_device_finish(&device->vk);
2055 vk_free2(&device->vk.alloc, pAllocator, device);
2056 }
2057
2058 static VkResult
device_alloc(struct v3dv_device * device,struct v3dv_device_memory * mem,VkDeviceSize size)2059 device_alloc(struct v3dv_device *device,
2060 struct v3dv_device_memory *mem,
2061 VkDeviceSize size)
2062 {
2063 /* Our kernel interface is 32-bit */
2064 assert(size <= UINT32_MAX);
2065
2066 mem->bo = v3dv_bo_alloc(device, size, "device_alloc", false);
2067 if (!mem->bo)
2068 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
2069
2070 return VK_SUCCESS;
2071 }
2072
2073 static void
device_free_wsi_dumb(int32_t display_fd,int32_t dumb_handle)2074 device_free_wsi_dumb(int32_t display_fd, int32_t dumb_handle)
2075 {
2076 assert(display_fd != -1);
2077 if (dumb_handle < 0)
2078 return;
2079
2080 struct drm_mode_destroy_dumb destroy_dumb = {
2081 .handle = dumb_handle,
2082 };
2083 if (v3dv_ioctl(display_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb)) {
2084 fprintf(stderr, "destroy dumb object %d: %s\n", dumb_handle, strerror(errno));
2085 }
2086 }
2087
2088 static void
device_free(struct v3dv_device * device,struct v3dv_device_memory * mem)2089 device_free(struct v3dv_device *device, struct v3dv_device_memory *mem)
2090 {
2091 /* If this memory allocation was for WSI, then we need to use the
2092 * display device to free the allocated dumb BO.
2093 */
2094 if (mem->is_for_wsi) {
2095 device_free_wsi_dumb(device->instance->physicalDevice.display_fd,
2096 mem->bo->dumb_handle);
2097 }
2098
2099 v3dv_bo_free(device, mem->bo);
2100 }
2101
2102 static void
device_unmap(struct v3dv_device * device,struct v3dv_device_memory * mem)2103 device_unmap(struct v3dv_device *device, struct v3dv_device_memory *mem)
2104 {
2105 assert(mem && mem->bo->map && mem->bo->map_size > 0);
2106 v3dv_bo_unmap(device, mem->bo);
2107 }
2108
2109 static VkResult
device_map(struct v3dv_device * device,struct v3dv_device_memory * mem)2110 device_map(struct v3dv_device *device, struct v3dv_device_memory *mem)
2111 {
2112 assert(mem && mem->bo);
2113
2114 /* From the spec:
2115 *
2116 * "After a successful call to vkMapMemory the memory object memory is
2117 * considered to be currently host mapped. It is an application error to
2118 * call vkMapMemory on a memory object that is already host mapped."
2119 *
2120 * We are not concerned with this ourselves (validation layers should
2121 * catch these errors and warn users), however, the driver may internally
2122 * map things (for example for debug CLIF dumps or some CPU-side operations)
2123 * so by the time the user calls here the buffer might already been mapped
2124 * internally by the driver.
2125 */
2126 if (mem->bo->map) {
2127 assert(mem->bo->map_size == mem->bo->size);
2128 return VK_SUCCESS;
2129 }
2130
2131 bool ok = v3dv_bo_map(device, mem->bo, mem->bo->size);
2132 if (!ok)
2133 return VK_ERROR_MEMORY_MAP_FAILED;
2134
2135 return VK_SUCCESS;
2136 }
2137
2138 static VkResult
device_import_bo(struct v3dv_device * device,const VkAllocationCallbacks * pAllocator,int fd,uint64_t size,struct v3dv_bo ** bo)2139 device_import_bo(struct v3dv_device *device,
2140 const VkAllocationCallbacks *pAllocator,
2141 int fd, uint64_t size,
2142 struct v3dv_bo **bo)
2143 {
2144 *bo = NULL;
2145
2146 off_t real_size = lseek(fd, 0, SEEK_END);
2147 lseek(fd, 0, SEEK_SET);
2148 if (real_size < 0 || (uint64_t) real_size < size)
2149 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
2150
2151 int render_fd = device->pdevice->render_fd;
2152 assert(render_fd >= 0);
2153
2154 int ret;
2155 uint32_t handle;
2156 ret = drmPrimeFDToHandle(render_fd, fd, &handle);
2157 if (ret)
2158 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
2159
2160 struct drm_v3d_get_bo_offset get_offset = {
2161 .handle = handle,
2162 };
2163 ret = v3dv_ioctl(render_fd, DRM_IOCTL_V3D_GET_BO_OFFSET, &get_offset);
2164 if (ret)
2165 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
2166 assert(get_offset.offset != 0);
2167
2168 *bo = v3dv_device_lookup_bo(device->pdevice, handle);
2169 assert(*bo);
2170
2171 if ((*bo)->refcnt == 0)
2172 v3dv_bo_init(*bo, handle, size, get_offset.offset, "import", false);
2173 else
2174 p_atomic_inc(&(*bo)->refcnt);
2175
2176 return VK_SUCCESS;
2177 }
2178
2179 static VkResult
device_alloc_for_wsi(struct v3dv_device * device,const VkAllocationCallbacks * pAllocator,struct v3dv_device_memory * mem,VkDeviceSize size)2180 device_alloc_for_wsi(struct v3dv_device *device,
2181 const VkAllocationCallbacks *pAllocator,
2182 struct v3dv_device_memory *mem,
2183 VkDeviceSize size)
2184 {
2185 /* In the simulator we can get away with a regular allocation since both
2186 * allocation and rendering happen in the same DRM render node. On actual
2187 * hardware we need to allocate our winsys BOs on the vc4 display device
2188 * and import them into v3d.
2189 */
2190 #if using_v3d_simulator
2191 return device_alloc(device, mem, size);
2192 #else
2193 /* If we are allocating for WSI we should have a swapchain and thus,
2194 * we should've initialized the display device. However, Zink doesn't
2195 * use swapchains, so in that case we can get here without acquiring the
2196 * display device and we need to do it now.
2197 */
2198 VkResult result;
2199 struct v3dv_instance *instance = device->instance;
2200 struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;
2201 if (unlikely(pdevice->display_fd < 0)) {
2202 result = v3dv_physical_device_acquire_display(instance, pdevice, NULL);
2203 if (result != VK_SUCCESS)
2204 return result;
2205 }
2206 assert(pdevice->display_fd != -1);
2207
2208 mem->is_for_wsi = true;
2209
2210 int display_fd = pdevice->display_fd;
2211 struct drm_mode_create_dumb create_dumb = {
2212 .width = 1024, /* one page */
2213 .height = align(size, 4096) / 4096,
2214 .bpp = util_format_get_blocksizebits(PIPE_FORMAT_RGBA8888_UNORM),
2215 };
2216
2217 int err;
2218 err = v3dv_ioctl(display_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
2219 if (err < 0)
2220 goto fail_create;
2221
2222 int fd;
2223 err =
2224 drmPrimeHandleToFD(display_fd, create_dumb.handle, O_CLOEXEC, &fd);
2225 if (err < 0)
2226 goto fail_export;
2227
2228 result = device_import_bo(device, pAllocator, fd, size, &mem->bo);
2229 close(fd);
2230 if (result != VK_SUCCESS)
2231 goto fail_import;
2232
2233 mem->bo->dumb_handle = create_dumb.handle;
2234 return VK_SUCCESS;
2235
2236 fail_import:
2237 fail_export:
2238 device_free_wsi_dumb(display_fd, create_dumb.handle);
2239
2240 fail_create:
2241 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
2242 #endif
2243 }
2244
2245 static void
device_add_device_address_bo(struct v3dv_device * device,struct v3dv_bo * bo)2246 device_add_device_address_bo(struct v3dv_device *device,
2247 struct v3dv_bo *bo)
2248 {
2249 util_dynarray_append(&device->device_address_bo_list,
2250 struct v3dv_bo *,
2251 bo);
2252 }
2253
2254 static void
device_remove_device_address_bo(struct v3dv_device * device,struct v3dv_bo * bo)2255 device_remove_device_address_bo(struct v3dv_device *device,
2256 struct v3dv_bo *bo)
2257 {
2258 util_dynarray_delete_unordered(&device->device_address_bo_list,
2259 struct v3dv_bo *,
2260 bo);
2261 }
2262
2263 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_AllocateMemory(VkDevice _device,const VkMemoryAllocateInfo * pAllocateInfo,const VkAllocationCallbacks * pAllocator,VkDeviceMemory * pMem)2264 v3dv_AllocateMemory(VkDevice _device,
2265 const VkMemoryAllocateInfo *pAllocateInfo,
2266 const VkAllocationCallbacks *pAllocator,
2267 VkDeviceMemory *pMem)
2268 {
2269 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2270 struct v3dv_device_memory *mem;
2271 struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;
2272
2273 assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO);
2274
2275 /* The Vulkan 1.0.33 spec says "allocationSize must be greater than 0". */
2276 assert(pAllocateInfo->allocationSize > 0);
2277
2278 mem = vk_object_zalloc(&device->vk, pAllocator, sizeof(*mem),
2279 VK_OBJECT_TYPE_DEVICE_MEMORY);
2280 if (mem == NULL)
2281 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
2282
2283 assert(pAllocateInfo->memoryTypeIndex < pdevice->memory.memoryTypeCount);
2284 mem->type = &pdevice->memory.memoryTypes[pAllocateInfo->memoryTypeIndex];
2285 mem->is_for_wsi = false;
2286
2287 const struct wsi_memory_allocate_info *wsi_info = NULL;
2288 const VkImportMemoryFdInfoKHR *fd_info = NULL;
2289 const VkMemoryAllocateFlagsInfo *flags_info = NULL;
2290 vk_foreach_struct_const(ext, pAllocateInfo->pNext) {
2291 switch ((unsigned)ext->sType) {
2292 case VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA:
2293 wsi_info = (void *)ext;
2294 break;
2295 case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:
2296 fd_info = (void *)ext;
2297 break;
2298 case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO:
2299 flags_info = (void *)ext;
2300 break;
2301 case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO:
2302 /* We don't have particular optimizations associated with memory
2303 * allocations that won't be suballocated to multiple resources.
2304 */
2305 break;
2306 case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
2307 /* The mask of handle types specified here must be supported
2308 * according to VkExternalImageFormatProperties, so it must be
2309 * fd or dmabuf, which don't have special requirements for us.
2310 */
2311 break;
2312 default:
2313 v3dv_debug_ignored_stype(ext->sType);
2314 break;
2315 }
2316 }
2317
2318 VkResult result = VK_SUCCESS;
2319
2320 /* We always allocate device memory in multiples of a page, so round up
2321 * requested size to that.
2322 */
2323 VkDeviceSize alloc_size = ALIGN(pAllocateInfo->allocationSize, 4096);
2324
2325 if (unlikely(alloc_size > MAX_MEMORY_ALLOCATION_SIZE)) {
2326 result = VK_ERROR_OUT_OF_DEVICE_MEMORY;
2327 } else {
2328 if (wsi_info) {
2329 result = device_alloc_for_wsi(device, pAllocator, mem, alloc_size);
2330 } else if (fd_info && fd_info->handleType) {
2331 assert(fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
2332 fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
2333 result = device_import_bo(device, pAllocator,
2334 fd_info->fd, alloc_size, &mem->bo);
2335 if (result == VK_SUCCESS)
2336 close(fd_info->fd);
2337 } else {
2338 result = device_alloc(device, mem, alloc_size);
2339 }
2340 }
2341
2342 if (result != VK_SUCCESS) {
2343 vk_object_free(&device->vk, pAllocator, mem);
2344 return vk_error(device, result);
2345 }
2346
2347 /* If this memory can be used via VK_KHR_buffer_device_address then we
2348 * will need to manually add the BO to any job submit that makes use of
2349 * VK_KHR_buffer_device_address, since such jobs may produde buffer
2350 * load/store operations that may access any buffer memory allocated with
2351 * this flag and we don't have any means to tell which buffers will be
2352 * accessed through this mechanism since they don't even have to be bound
2353 * through descriptor state.
2354 */
2355 if (flags_info &&
2356 (flags_info->flags & VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR)) {
2357 mem->is_for_device_address = true;
2358 device_add_device_address_bo(device, mem->bo);
2359 }
2360
2361 *pMem = v3dv_device_memory_to_handle(mem);
2362 return result;
2363 }
2364
2365 VKAPI_ATTR void VKAPI_CALL
v3dv_FreeMemory(VkDevice _device,VkDeviceMemory _mem,const VkAllocationCallbacks * pAllocator)2366 v3dv_FreeMemory(VkDevice _device,
2367 VkDeviceMemory _mem,
2368 const VkAllocationCallbacks *pAllocator)
2369 {
2370 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2371 V3DV_FROM_HANDLE(v3dv_device_memory, mem, _mem);
2372
2373 if (mem == NULL)
2374 return;
2375
2376 if (mem->bo->map)
2377 v3dv_UnmapMemory(_device, _mem);
2378
2379 if (mem->is_for_device_address)
2380 device_remove_device_address_bo(device, mem->bo);
2381
2382 device_free(device, mem);
2383
2384 vk_object_free(&device->vk, pAllocator, mem);
2385 }
2386
2387 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_MapMemory(VkDevice _device,VkDeviceMemory _memory,VkDeviceSize offset,VkDeviceSize size,VkMemoryMapFlags flags,void ** ppData)2388 v3dv_MapMemory(VkDevice _device,
2389 VkDeviceMemory _memory,
2390 VkDeviceSize offset,
2391 VkDeviceSize size,
2392 VkMemoryMapFlags flags,
2393 void **ppData)
2394 {
2395 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2396 V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
2397
2398 if (mem == NULL) {
2399 *ppData = NULL;
2400 return VK_SUCCESS;
2401 }
2402
2403 assert(offset < mem->bo->size);
2404
2405 /* Since the driver can map BOs internally as well and the mapped range
2406 * required by the user or the driver might not be the same, we always map
2407 * the entire BO and then add the requested offset to the start address
2408 * of the mapped region.
2409 */
2410 VkResult result = device_map(device, mem);
2411 if (result != VK_SUCCESS)
2412 return vk_error(device, result);
2413
2414 *ppData = ((uint8_t *) mem->bo->map) + offset;
2415 return VK_SUCCESS;
2416 }
2417
2418 VKAPI_ATTR void VKAPI_CALL
v3dv_UnmapMemory(VkDevice _device,VkDeviceMemory _memory)2419 v3dv_UnmapMemory(VkDevice _device,
2420 VkDeviceMemory _memory)
2421 {
2422 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2423 V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
2424
2425 if (mem == NULL)
2426 return;
2427
2428 device_unmap(device, mem);
2429 }
2430
2431 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_FlushMappedMemoryRanges(VkDevice _device,uint32_t memoryRangeCount,const VkMappedMemoryRange * pMemoryRanges)2432 v3dv_FlushMappedMemoryRanges(VkDevice _device,
2433 uint32_t memoryRangeCount,
2434 const VkMappedMemoryRange *pMemoryRanges)
2435 {
2436 return VK_SUCCESS;
2437 }
2438
2439 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_InvalidateMappedMemoryRanges(VkDevice _device,uint32_t memoryRangeCount,const VkMappedMemoryRange * pMemoryRanges)2440 v3dv_InvalidateMappedMemoryRanges(VkDevice _device,
2441 uint32_t memoryRangeCount,
2442 const VkMappedMemoryRange *pMemoryRanges)
2443 {
2444 return VK_SUCCESS;
2445 }
2446
2447 VKAPI_ATTR void VKAPI_CALL
v3dv_GetImageMemoryRequirements2(VkDevice device,const VkImageMemoryRequirementsInfo2 * pInfo,VkMemoryRequirements2 * pMemoryRequirements)2448 v3dv_GetImageMemoryRequirements2(VkDevice device,
2449 const VkImageMemoryRequirementsInfo2 *pInfo,
2450 VkMemoryRequirements2 *pMemoryRequirements)
2451 {
2452 V3DV_FROM_HANDLE(v3dv_image, image, pInfo->image);
2453
2454 pMemoryRequirements->memoryRequirements = (VkMemoryRequirements) {
2455 .memoryTypeBits = 0x1,
2456 .alignment = image->alignment,
2457 .size = image->size
2458 };
2459
2460 vk_foreach_struct(ext, pMemoryRequirements->pNext) {
2461 switch (ext->sType) {
2462 case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
2463 VkMemoryDedicatedRequirements *req =
2464 (VkMemoryDedicatedRequirements *) ext;
2465 req->requiresDedicatedAllocation = image->vk.external_handle_types != 0;
2466 req->prefersDedicatedAllocation = image->vk.external_handle_types != 0;
2467 break;
2468 }
2469 default:
2470 v3dv_debug_ignored_stype(ext->sType);
2471 break;
2472 }
2473 }
2474 }
2475
2476 static void
bind_image_memory(const VkBindImageMemoryInfo * info)2477 bind_image_memory(const VkBindImageMemoryInfo *info)
2478 {
2479 V3DV_FROM_HANDLE(v3dv_image, image, info->image);
2480 V3DV_FROM_HANDLE(v3dv_device_memory, mem, info->memory);
2481
2482 /* Valid usage:
2483 *
2484 * "memoryOffset must be an integer multiple of the alignment member of
2485 * the VkMemoryRequirements structure returned from a call to
2486 * vkGetImageMemoryRequirements with image"
2487 */
2488 assert(info->memoryOffset % image->alignment == 0);
2489 assert(info->memoryOffset < mem->bo->size);
2490
2491 image->mem = mem;
2492 image->mem_offset = info->memoryOffset;
2493 }
2494
2495 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_BindImageMemory2(VkDevice _device,uint32_t bindInfoCount,const VkBindImageMemoryInfo * pBindInfos)2496 v3dv_BindImageMemory2(VkDevice _device,
2497 uint32_t bindInfoCount,
2498 const VkBindImageMemoryInfo *pBindInfos)
2499 {
2500 for (uint32_t i = 0; i < bindInfoCount; i++) {
2501 const VkBindImageMemorySwapchainInfoKHR *swapchain_info =
2502 vk_find_struct_const(pBindInfos->pNext,
2503 BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR);
2504 if (swapchain_info && swapchain_info->swapchain) {
2505 struct v3dv_image *swapchain_image =
2506 v3dv_wsi_get_image_from_swapchain(swapchain_info->swapchain,
2507 swapchain_info->imageIndex);
2508 VkBindImageMemoryInfo swapchain_bind = {
2509 .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
2510 .image = pBindInfos[i].image,
2511 .memory = v3dv_device_memory_to_handle(swapchain_image->mem),
2512 .memoryOffset = swapchain_image->mem_offset,
2513 };
2514 bind_image_memory(&swapchain_bind);
2515 } else {
2516 bind_image_memory(&pBindInfos[i]);
2517 }
2518 }
2519
2520 return VK_SUCCESS;
2521 }
2522
2523 VKAPI_ATTR void VKAPI_CALL
v3dv_GetBufferMemoryRequirements2(VkDevice device,const VkBufferMemoryRequirementsInfo2 * pInfo,VkMemoryRequirements2 * pMemoryRequirements)2524 v3dv_GetBufferMemoryRequirements2(VkDevice device,
2525 const VkBufferMemoryRequirementsInfo2 *pInfo,
2526 VkMemoryRequirements2 *pMemoryRequirements)
2527 {
2528 V3DV_FROM_HANDLE(v3dv_buffer, buffer, pInfo->buffer);
2529
2530 pMemoryRequirements->memoryRequirements = (VkMemoryRequirements) {
2531 .memoryTypeBits = 0x1,
2532 .alignment = buffer->alignment,
2533 .size = align64(buffer->size, buffer->alignment),
2534 };
2535
2536 vk_foreach_struct(ext, pMemoryRequirements->pNext) {
2537 switch (ext->sType) {
2538 case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
2539 VkMemoryDedicatedRequirements *req =
2540 (VkMemoryDedicatedRequirements *) ext;
2541 req->requiresDedicatedAllocation = false;
2542 req->prefersDedicatedAllocation = false;
2543 break;
2544 }
2545 default:
2546 v3dv_debug_ignored_stype(ext->sType);
2547 break;
2548 }
2549 }
2550 }
2551
2552 static void
bind_buffer_memory(const VkBindBufferMemoryInfo * info)2553 bind_buffer_memory(const VkBindBufferMemoryInfo *info)
2554 {
2555 V3DV_FROM_HANDLE(v3dv_buffer, buffer, info->buffer);
2556 V3DV_FROM_HANDLE(v3dv_device_memory, mem, info->memory);
2557
2558 /* Valid usage:
2559 *
2560 * "memoryOffset must be an integer multiple of the alignment member of
2561 * the VkMemoryRequirements structure returned from a call to
2562 * vkGetBufferMemoryRequirements with buffer"
2563 */
2564 assert(info->memoryOffset % buffer->alignment == 0);
2565 assert(info->memoryOffset < mem->bo->size);
2566
2567 buffer->mem = mem;
2568 buffer->mem_offset = info->memoryOffset;
2569 }
2570
2571
2572 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_BindBufferMemory2(VkDevice device,uint32_t bindInfoCount,const VkBindBufferMemoryInfo * pBindInfos)2573 v3dv_BindBufferMemory2(VkDevice device,
2574 uint32_t bindInfoCount,
2575 const VkBindBufferMemoryInfo *pBindInfos)
2576 {
2577 for (uint32_t i = 0; i < bindInfoCount; i++)
2578 bind_buffer_memory(&pBindInfos[i]);
2579
2580 return VK_SUCCESS;
2581 }
2582
2583 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_CreateBuffer(VkDevice _device,const VkBufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBuffer * pBuffer)2584 v3dv_CreateBuffer(VkDevice _device,
2585 const VkBufferCreateInfo *pCreateInfo,
2586 const VkAllocationCallbacks *pAllocator,
2587 VkBuffer *pBuffer)
2588 {
2589 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2590 struct v3dv_buffer *buffer;
2591
2592 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO);
2593 assert(pCreateInfo->usage != 0);
2594
2595 /* We don't support any flags for now */
2596 assert(pCreateInfo->flags == 0);
2597
2598 buffer = vk_object_zalloc(&device->vk, pAllocator, sizeof(*buffer),
2599 VK_OBJECT_TYPE_BUFFER);
2600 if (buffer == NULL)
2601 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2602
2603 buffer->size = pCreateInfo->size;
2604 buffer->usage = pCreateInfo->usage;
2605 buffer->alignment = V3D_NON_COHERENT_ATOM_SIZE;
2606
2607 /* Limit allocations to 32-bit */
2608 const VkDeviceSize aligned_size = align64(buffer->size, buffer->alignment);
2609 if (aligned_size > UINT32_MAX || aligned_size < buffer->size) {
2610 vk_free(&device->vk.alloc, buffer);
2611 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
2612 }
2613
2614 *pBuffer = v3dv_buffer_to_handle(buffer);
2615
2616 return VK_SUCCESS;
2617 }
2618
2619 VKAPI_ATTR void VKAPI_CALL
v3dv_DestroyBuffer(VkDevice _device,VkBuffer _buffer,const VkAllocationCallbacks * pAllocator)2620 v3dv_DestroyBuffer(VkDevice _device,
2621 VkBuffer _buffer,
2622 const VkAllocationCallbacks *pAllocator)
2623 {
2624 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2625 V3DV_FROM_HANDLE(v3dv_buffer, buffer, _buffer);
2626
2627 if (!buffer)
2628 return;
2629
2630 vk_object_free(&device->vk, pAllocator, buffer);
2631 }
2632
2633 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_CreateFramebuffer(VkDevice _device,const VkFramebufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkFramebuffer * pFramebuffer)2634 v3dv_CreateFramebuffer(VkDevice _device,
2635 const VkFramebufferCreateInfo *pCreateInfo,
2636 const VkAllocationCallbacks *pAllocator,
2637 VkFramebuffer *pFramebuffer)
2638 {
2639 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2640 struct v3dv_framebuffer *framebuffer;
2641
2642 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO);
2643
2644 size_t size = sizeof(*framebuffer) +
2645 sizeof(struct v3dv_image_view *) * pCreateInfo->attachmentCount;
2646 framebuffer = vk_object_zalloc(&device->vk, pAllocator, size,
2647 VK_OBJECT_TYPE_FRAMEBUFFER);
2648 if (framebuffer == NULL)
2649 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2650
2651 framebuffer->width = pCreateInfo->width;
2652 framebuffer->height = pCreateInfo->height;
2653 framebuffer->layers = pCreateInfo->layers;
2654 framebuffer->has_edge_padding = true;
2655
2656 const VkFramebufferAttachmentsCreateInfo *imageless =
2657 vk_find_struct_const(pCreateInfo->pNext,
2658 FRAMEBUFFER_ATTACHMENTS_CREATE_INFO);
2659
2660 framebuffer->attachment_count = pCreateInfo->attachmentCount;
2661 framebuffer->color_attachment_count = 0;
2662 for (uint32_t i = 0; i < framebuffer->attachment_count; i++) {
2663 if (!imageless) {
2664 framebuffer->attachments[i] =
2665 v3dv_image_view_from_handle(pCreateInfo->pAttachments[i]);
2666 if (framebuffer->attachments[i]->vk.aspects & VK_IMAGE_ASPECT_COLOR_BIT)
2667 framebuffer->color_attachment_count++;
2668 } else {
2669 assert(i < imageless->attachmentImageInfoCount);
2670 if (imageless->pAttachmentImageInfos[i].usage &
2671 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
2672 framebuffer->color_attachment_count++;
2673 }
2674 }
2675 }
2676
2677 *pFramebuffer = v3dv_framebuffer_to_handle(framebuffer);
2678
2679 return VK_SUCCESS;
2680 }
2681
2682 VKAPI_ATTR void VKAPI_CALL
v3dv_DestroyFramebuffer(VkDevice _device,VkFramebuffer _fb,const VkAllocationCallbacks * pAllocator)2683 v3dv_DestroyFramebuffer(VkDevice _device,
2684 VkFramebuffer _fb,
2685 const VkAllocationCallbacks *pAllocator)
2686 {
2687 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2688 V3DV_FROM_HANDLE(v3dv_framebuffer, fb, _fb);
2689
2690 if (!fb)
2691 return;
2692
2693 vk_object_free(&device->vk, pAllocator, fb);
2694 }
2695
2696 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_GetMemoryFdPropertiesKHR(VkDevice _device,VkExternalMemoryHandleTypeFlagBits handleType,int fd,VkMemoryFdPropertiesKHR * pMemoryFdProperties)2697 v3dv_GetMemoryFdPropertiesKHR(VkDevice _device,
2698 VkExternalMemoryHandleTypeFlagBits handleType,
2699 int fd,
2700 VkMemoryFdPropertiesKHR *pMemoryFdProperties)
2701 {
2702 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2703 struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;
2704
2705 switch (handleType) {
2706 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT:
2707 pMemoryFdProperties->memoryTypeBits =
2708 (1 << pdevice->memory.memoryTypeCount) - 1;
2709 return VK_SUCCESS;
2710 default:
2711 return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
2712 }
2713 }
2714
2715 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_GetMemoryFdKHR(VkDevice _device,const VkMemoryGetFdInfoKHR * pGetFdInfo,int * pFd)2716 v3dv_GetMemoryFdKHR(VkDevice _device,
2717 const VkMemoryGetFdInfoKHR *pGetFdInfo,
2718 int *pFd)
2719 {
2720 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2721 V3DV_FROM_HANDLE(v3dv_device_memory, mem, pGetFdInfo->memory);
2722
2723 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR);
2724 assert(pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
2725 pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
2726
2727 int fd, ret;
2728 ret = drmPrimeHandleToFD(device->pdevice->render_fd,
2729 mem->bo->handle,
2730 DRM_CLOEXEC, &fd);
2731 if (ret)
2732 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2733
2734 *pFd = fd;
2735
2736 return VK_SUCCESS;
2737 }
2738
2739 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_CreateEvent(VkDevice _device,const VkEventCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkEvent * pEvent)2740 v3dv_CreateEvent(VkDevice _device,
2741 const VkEventCreateInfo *pCreateInfo,
2742 const VkAllocationCallbacks *pAllocator,
2743 VkEvent *pEvent)
2744 {
2745 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2746 struct v3dv_event *event =
2747 vk_object_zalloc(&device->vk, pAllocator, sizeof(*event),
2748 VK_OBJECT_TYPE_EVENT);
2749 if (!event)
2750 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2751
2752 /* Events are created in the unsignaled state */
2753 event->state = false;
2754 *pEvent = v3dv_event_to_handle(event);
2755
2756 return VK_SUCCESS;
2757 }
2758
2759 VKAPI_ATTR void VKAPI_CALL
v3dv_DestroyEvent(VkDevice _device,VkEvent _event,const VkAllocationCallbacks * pAllocator)2760 v3dv_DestroyEvent(VkDevice _device,
2761 VkEvent _event,
2762 const VkAllocationCallbacks *pAllocator)
2763 {
2764 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2765 V3DV_FROM_HANDLE(v3dv_event, event, _event);
2766
2767 if (!event)
2768 return;
2769
2770 vk_object_free(&device->vk, pAllocator, event);
2771 }
2772
2773 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_GetEventStatus(VkDevice _device,VkEvent _event)2774 v3dv_GetEventStatus(VkDevice _device, VkEvent _event)
2775 {
2776 V3DV_FROM_HANDLE(v3dv_event, event, _event);
2777 return p_atomic_read(&event->state) ? VK_EVENT_SET : VK_EVENT_RESET;
2778 }
2779
2780 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_SetEvent(VkDevice _device,VkEvent _event)2781 v3dv_SetEvent(VkDevice _device, VkEvent _event)
2782 {
2783 V3DV_FROM_HANDLE(v3dv_event, event, _event);
2784 p_atomic_set(&event->state, 1);
2785 return VK_SUCCESS;
2786 }
2787
2788 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_ResetEvent(VkDevice _device,VkEvent _event)2789 v3dv_ResetEvent(VkDevice _device, VkEvent _event)
2790 {
2791 V3DV_FROM_HANDLE(v3dv_event, event, _event);
2792 p_atomic_set(&event->state, 0);
2793 return VK_SUCCESS;
2794 }
2795
2796 VKAPI_ATTR VkResult VKAPI_CALL
v3dv_CreateSampler(VkDevice _device,const VkSamplerCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSampler * pSampler)2797 v3dv_CreateSampler(VkDevice _device,
2798 const VkSamplerCreateInfo *pCreateInfo,
2799 const VkAllocationCallbacks *pAllocator,
2800 VkSampler *pSampler)
2801 {
2802 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2803 struct v3dv_sampler *sampler;
2804
2805 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
2806
2807 sampler = vk_object_zalloc(&device->vk, pAllocator, sizeof(*sampler),
2808 VK_OBJECT_TYPE_SAMPLER);
2809 if (!sampler)
2810 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2811
2812 sampler->compare_enable = pCreateInfo->compareEnable;
2813 sampler->unnormalized_coordinates = pCreateInfo->unnormalizedCoordinates;
2814
2815 const VkSamplerCustomBorderColorCreateInfoEXT *bc_info =
2816 vk_find_struct_const(pCreateInfo->pNext,
2817 SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT);
2818
2819 v3dv_X(device, pack_sampler_state)(sampler, pCreateInfo, bc_info);
2820
2821 *pSampler = v3dv_sampler_to_handle(sampler);
2822
2823 return VK_SUCCESS;
2824 }
2825
2826 VKAPI_ATTR void VKAPI_CALL
v3dv_DestroySampler(VkDevice _device,VkSampler _sampler,const VkAllocationCallbacks * pAllocator)2827 v3dv_DestroySampler(VkDevice _device,
2828 VkSampler _sampler,
2829 const VkAllocationCallbacks *pAllocator)
2830 {
2831 V3DV_FROM_HANDLE(v3dv_device, device, _device);
2832 V3DV_FROM_HANDLE(v3dv_sampler, sampler, _sampler);
2833
2834 if (!sampler)
2835 return;
2836
2837 vk_object_free(&device->vk, pAllocator, sampler);
2838 }
2839
2840 VKAPI_ATTR void VKAPI_CALL
v3dv_GetDeviceMemoryCommitment(VkDevice device,VkDeviceMemory memory,VkDeviceSize * pCommittedMemoryInBytes)2841 v3dv_GetDeviceMemoryCommitment(VkDevice device,
2842 VkDeviceMemory memory,
2843 VkDeviceSize *pCommittedMemoryInBytes)
2844 {
2845 *pCommittedMemoryInBytes = 0;
2846 }
2847
2848 VKAPI_ATTR void VKAPI_CALL
v3dv_GetImageSparseMemoryRequirements(VkDevice device,VkImage image,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements * pSparseMemoryRequirements)2849 v3dv_GetImageSparseMemoryRequirements(
2850 VkDevice device,
2851 VkImage image,
2852 uint32_t *pSparseMemoryRequirementCount,
2853 VkSparseImageMemoryRequirements *pSparseMemoryRequirements)
2854 {
2855 *pSparseMemoryRequirementCount = 0;
2856 }
2857
2858 VKAPI_ATTR void VKAPI_CALL
v3dv_GetImageSparseMemoryRequirements2(VkDevice device,const VkImageSparseMemoryRequirementsInfo2 * pInfo,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements)2859 v3dv_GetImageSparseMemoryRequirements2(
2860 VkDevice device,
2861 const VkImageSparseMemoryRequirementsInfo2 *pInfo,
2862 uint32_t *pSparseMemoryRequirementCount,
2863 VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
2864 {
2865 *pSparseMemoryRequirementCount = 0;
2866 }
2867
2868 /* vk_icd.h does not declare this function, so we declare it here to
2869 * suppress Wmissing-prototypes.
2870 */
2871 PUBLIC VKAPI_ATTR VkResult VKAPI_CALL
2872 vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion);
2873
2874 PUBLIC VKAPI_ATTR VkResult VKAPI_CALL
vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t * pSupportedVersion)2875 vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion)
2876 {
2877 /* For the full details on loader interface versioning, see
2878 * <https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md>.
2879 * What follows is a condensed summary, to help you navigate the large and
2880 * confusing official doc.
2881 *
2882 * - Loader interface v0 is incompatible with later versions. We don't
2883 * support it.
2884 *
2885 * - In loader interface v1:
2886 * - The first ICD entrypoint called by the loader is
2887 * vk_icdGetInstanceProcAddr(). The ICD must statically expose this
2888 * entrypoint.
2889 * - The ICD must statically expose no other Vulkan symbol unless it is
2890 * linked with -Bsymbolic.
2891 * - Each dispatchable Vulkan handle created by the ICD must be
2892 * a pointer to a struct whose first member is VK_LOADER_DATA. The
2893 * ICD must initialize VK_LOADER_DATA.loadMagic to ICD_LOADER_MAGIC.
2894 * - The loader implements vkCreate{PLATFORM}SurfaceKHR() and
2895 * vkDestroySurfaceKHR(). The ICD must be capable of working with
2896 * such loader-managed surfaces.
2897 *
2898 * - Loader interface v2 differs from v1 in:
2899 * - The first ICD entrypoint called by the loader is
2900 * vk_icdNegotiateLoaderICDInterfaceVersion(). The ICD must
2901 * statically expose this entrypoint.
2902 *
2903 * - Loader interface v3 differs from v2 in:
2904 * - The ICD must implement vkCreate{PLATFORM}SurfaceKHR(),
2905 * vkDestroySurfaceKHR(), and other API which uses VKSurfaceKHR,
2906 * because the loader no longer does so.
2907 *
2908 * - Loader interface v4 differs from v3 in:
2909 * - The ICD must implement vk_icdGetPhysicalDeviceProcAddr().
2910 *
2911 * - Loader interface v5 differs from v4 in:
2912 * - The ICD must support Vulkan API version 1.1 and must not return
2913 * VK_ERROR_INCOMPATIBLE_DRIVER from vkCreateInstance() unless a
2914 * Vulkan Loader with interface v4 or smaller is being used and the
2915 * application provides an API version that is greater than 1.0.
2916 */
2917 *pSupportedVersion = MIN2(*pSupportedVersion, 5u);
2918 return VK_SUCCESS;
2919 }
2920
2921 VkDeviceAddress
v3dv_GetBufferDeviceAddress(VkDevice device,const VkBufferDeviceAddressInfoKHR * pInfo)2922 v3dv_GetBufferDeviceAddress(VkDevice device,
2923 const VkBufferDeviceAddressInfoKHR *pInfo)
2924 {
2925 V3DV_FROM_HANDLE(v3dv_buffer, buffer, pInfo->buffer);
2926 return buffer->mem_offset + buffer->mem->bo->offset;
2927 }
2928
2929 uint64_t
v3dv_GetBufferOpaqueCaptureAddress(VkDevice device,const VkBufferDeviceAddressInfoKHR * pInfo)2930 v3dv_GetBufferOpaqueCaptureAddress(VkDevice device,
2931 const VkBufferDeviceAddressInfoKHR *pInfo)
2932 {
2933 /* Not implemented */
2934 return 0;
2935 }
2936
2937 uint64_t
v3dv_GetDeviceMemoryOpaqueCaptureAddress(VkDevice device,const VkDeviceMemoryOpaqueCaptureAddressInfoKHR * pInfo)2938 v3dv_GetDeviceMemoryOpaqueCaptureAddress(
2939 VkDevice device,
2940 const VkDeviceMemoryOpaqueCaptureAddressInfoKHR *pInfo)
2941 {
2942 /* Not implemented */
2943 return 0;
2944 }
2945