17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2019 Raspberry Pi
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
217ec681f3Smrg * IN THE SOFTWARE.
227ec681f3Smrg */
237ec681f3Smrg
247ec681f3Smrg#include <assert.h>
257ec681f3Smrg#include <fcntl.h>
267ec681f3Smrg#include <stdbool.h>
277ec681f3Smrg#include <string.h>
287ec681f3Smrg#include <sys/mman.h>
297ec681f3Smrg#include <sys/sysinfo.h>
307ec681f3Smrg#include <unistd.h>
317ec681f3Smrg#include <xf86drm.h>
327ec681f3Smrg
337ec681f3Smrg#ifdef MAJOR_IN_MKDEV
347ec681f3Smrg#include <sys/mkdev.h>
357ec681f3Smrg#endif
367ec681f3Smrg#ifdef MAJOR_IN_SYSMACROS
377ec681f3Smrg#include <sys/sysmacros.h>
387ec681f3Smrg#endif
397ec681f3Smrg
407ec681f3Smrg#include "v3dv_private.h"
417ec681f3Smrg
427ec681f3Smrg#include "common/v3d_debug.h"
437ec681f3Smrg
447ec681f3Smrg#include "compiler/v3d_compiler.h"
457ec681f3Smrg
467ec681f3Smrg#include "drm-uapi/v3d_drm.h"
477ec681f3Smrg#include "format/u_format.h"
487ec681f3Smrg#include "vk_util.h"
497ec681f3Smrg
507ec681f3Smrg#include "util/build_id.h"
517ec681f3Smrg#include "util/debug.h"
527ec681f3Smrg#include "util/u_cpu_detect.h"
537ec681f3Smrg
547ec681f3Smrg#ifdef VK_USE_PLATFORM_XCB_KHR
557ec681f3Smrg#include <xcb/xcb.h>
567ec681f3Smrg#include <xcb/dri3.h>
577ec681f3Smrg#include <X11/Xlib-xcb.h>
587ec681f3Smrg#endif
597ec681f3Smrg
607ec681f3Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR
617ec681f3Smrg#include <wayland-client.h>
627ec681f3Smrg#include "wayland-drm-client-protocol.h"
637ec681f3Smrg#endif
647ec681f3Smrg
657ec681f3Smrg#ifdef USE_V3D_SIMULATOR
667ec681f3Smrg#include "drm-uapi/i915_drm.h"
677ec681f3Smrg#endif
687ec681f3Smrg
697ec681f3Smrg#define V3DV_API_VERSION VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION)
707ec681f3Smrg
717ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
727ec681f3Smrgv3dv_EnumerateInstanceVersion(uint32_t *pApiVersion)
737ec681f3Smrg{
747ec681f3Smrg    *pApiVersion = V3DV_API_VERSION;
757ec681f3Smrg    return VK_SUCCESS;
767ec681f3Smrg}
777ec681f3Smrg
787ec681f3Smrg#if defined(VK_USE_PLATFORM_WIN32_KHR) ||   \
797ec681f3Smrg    defined(VK_USE_PLATFORM_WAYLAND_KHR) || \
807ec681f3Smrg    defined(VK_USE_PLATFORM_XCB_KHR) ||     \
817ec681f3Smrg    defined(VK_USE_PLATFORM_XLIB_KHR) ||    \
827ec681f3Smrg    defined(VK_USE_PLATFORM_DISPLAY_KHR)
837ec681f3Smrg#define V3DV_USE_WSI_PLATFORM
847ec681f3Smrg#endif
857ec681f3Smrg
867ec681f3Smrgstatic const struct vk_instance_extension_table instance_extensions = {
877ec681f3Smrg   .KHR_device_group_creation           = true,
887ec681f3Smrg#ifdef VK_USE_PLATFORM_DISPLAY_KHR
897ec681f3Smrg   .KHR_display                         = true,
907ec681f3Smrg   .KHR_get_display_properties2         = true,
917ec681f3Smrg#endif
927ec681f3Smrg   .KHR_external_fence_capabilities     = true,
937ec681f3Smrg   .KHR_external_memory_capabilities    = true,
947ec681f3Smrg   .KHR_external_semaphore_capabilities = true,
957ec681f3Smrg   .KHR_get_physical_device_properties2 = true,
967ec681f3Smrg#ifdef V3DV_USE_WSI_PLATFORM
977ec681f3Smrg   .KHR_get_surface_capabilities2       = true,
987ec681f3Smrg   .KHR_surface                         = true,
997ec681f3Smrg   .KHR_surface_protected_capabilities  = true,
1007ec681f3Smrg#endif
1017ec681f3Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR
1027ec681f3Smrg   .KHR_wayland_surface                 = true,
1037ec681f3Smrg#endif
1047ec681f3Smrg#ifdef VK_USE_PLATFORM_XCB_KHR
1057ec681f3Smrg   .KHR_xcb_surface                     = true,
1067ec681f3Smrg#endif
1077ec681f3Smrg#ifdef VK_USE_PLATFORM_XLIB_KHR
1087ec681f3Smrg   .KHR_xlib_surface                    = true,
1097ec681f3Smrg#endif
1107ec681f3Smrg   .EXT_debug_report                    = true,
1117ec681f3Smrg};
1127ec681f3Smrg
1137ec681f3Smrgstatic void
1147ec681f3Smrgget_device_extensions(const struct v3dv_physical_device *device,
1157ec681f3Smrg                      struct vk_device_extension_table *ext)
1167ec681f3Smrg{
1177ec681f3Smrg   *ext = (struct vk_device_extension_table) {
1187ec681f3Smrg      .KHR_bind_memory2                    = true,
1197ec681f3Smrg      .KHR_copy_commands2                  = true,
1207ec681f3Smrg      .KHR_dedicated_allocation            = true,
1217ec681f3Smrg      .KHR_device_group                    = true,
1227ec681f3Smrg      .KHR_descriptor_update_template      = true,
1237ec681f3Smrg      .KHR_external_fence                  = true,
1247ec681f3Smrg      .KHR_external_fence_fd               = true,
1257ec681f3Smrg      .KHR_external_memory                 = true,
1267ec681f3Smrg      .KHR_external_memory_fd              = true,
1277ec681f3Smrg      .KHR_external_semaphore              = true,
1287ec681f3Smrg      .KHR_external_semaphore_fd           = true,
1297ec681f3Smrg      .KHR_get_memory_requirements2        = true,
1307ec681f3Smrg      .KHR_image_format_list               = true,
1317ec681f3Smrg      .KHR_relaxed_block_layout            = true,
1327ec681f3Smrg      .KHR_maintenance1                    = true,
1337ec681f3Smrg      .KHR_maintenance2                    = true,
1347ec681f3Smrg      .KHR_maintenance3                    = true,
1357ec681f3Smrg      .KHR_multiview                       = true,
1367ec681f3Smrg      .KHR_shader_non_semantic_info        = true,
1377ec681f3Smrg      .KHR_sampler_mirror_clamp_to_edge    = true,
1387ec681f3Smrg      .KHR_storage_buffer_storage_class    = true,
1397ec681f3Smrg      .KHR_uniform_buffer_standard_layout  = true,
1407ec681f3Smrg#ifdef V3DV_USE_WSI_PLATFORM
1417ec681f3Smrg      .KHR_swapchain                       = true,
1427ec681f3Smrg      .KHR_incremental_present             = true,
1437ec681f3Smrg#endif
1447ec681f3Smrg      .KHR_variable_pointers               = true,
1457ec681f3Smrg      .EXT_color_write_enable              = true,
1467ec681f3Smrg      .EXT_custom_border_color             = true,
1477ec681f3Smrg      .EXT_external_memory_dma_buf         = true,
1487ec681f3Smrg      .EXT_index_type_uint8                = true,
1497ec681f3Smrg      .EXT_physical_device_drm             = true,
1507ec681f3Smrg      .EXT_pipeline_creation_cache_control = true,
1517ec681f3Smrg      .EXT_pipeline_creation_feedback      = true,
1527ec681f3Smrg      .EXT_private_data                    = true,
1537ec681f3Smrg      .EXT_provoking_vertex                = true,
1547ec681f3Smrg      .EXT_vertex_attribute_divisor        = true,
1557ec681f3Smrg   };
1567ec681f3Smrg}
1577ec681f3Smrg
1587ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
1597ec681f3Smrgv3dv_EnumerateInstanceExtensionProperties(const char *pLayerName,
1607ec681f3Smrg                                          uint32_t *pPropertyCount,
1617ec681f3Smrg                                          VkExtensionProperties *pProperties)
1627ec681f3Smrg{
1637ec681f3Smrg   /* We don't support any layers  */
1647ec681f3Smrg   if (pLayerName)
1657ec681f3Smrg      return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
1667ec681f3Smrg
1677ec681f3Smrg   return vk_enumerate_instance_extension_properties(
1687ec681f3Smrg      &instance_extensions, pPropertyCount, pProperties);
1697ec681f3Smrg}
1707ec681f3Smrg
1717ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
1727ec681f3Smrgv3dv_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
1737ec681f3Smrg                    const VkAllocationCallbacks *pAllocator,
1747ec681f3Smrg                    VkInstance *pInstance)
1757ec681f3Smrg{
1767ec681f3Smrg   struct v3dv_instance *instance;
1777ec681f3Smrg   VkResult result;
1787ec681f3Smrg
1797ec681f3Smrg   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
1807ec681f3Smrg
1817ec681f3Smrg   if (pAllocator == NULL)
1827ec681f3Smrg      pAllocator = vk_default_allocator();
1837ec681f3Smrg
1847ec681f3Smrg   instance = vk_alloc(pAllocator, sizeof(*instance), 8,
1857ec681f3Smrg                       VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1867ec681f3Smrg   if (!instance)
1877ec681f3Smrg      return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
1887ec681f3Smrg
1897ec681f3Smrg   struct vk_instance_dispatch_table dispatch_table;
1907ec681f3Smrg   vk_instance_dispatch_table_from_entrypoints(
1917ec681f3Smrg      &dispatch_table, &v3dv_instance_entrypoints, true);
1927ec681f3Smrg   vk_instance_dispatch_table_from_entrypoints(
1937ec681f3Smrg      &dispatch_table, &wsi_instance_entrypoints, false);
1947ec681f3Smrg
1957ec681f3Smrg   result = vk_instance_init(&instance->vk,
1967ec681f3Smrg                             &instance_extensions,
1977ec681f3Smrg                             &dispatch_table,
1987ec681f3Smrg                             pCreateInfo, pAllocator);
1997ec681f3Smrg
2007ec681f3Smrg   if (result != VK_SUCCESS) {
2017ec681f3Smrg      vk_free(pAllocator, instance);
2027ec681f3Smrg      return vk_error(NULL, result);
2037ec681f3Smrg   }
2047ec681f3Smrg
2057ec681f3Smrg   v3d_process_debug_variable();
2067ec681f3Smrg
2077ec681f3Smrg   instance->physicalDeviceCount = -1;
2087ec681f3Smrg
2097ec681f3Smrg   /* We start with the default values for the pipeline_cache envvars */
2107ec681f3Smrg   instance->pipeline_cache_enabled = true;
2117ec681f3Smrg   instance->default_pipeline_cache_enabled = true;
2127ec681f3Smrg   const char *pipeline_cache_str = getenv("V3DV_ENABLE_PIPELINE_CACHE");
2137ec681f3Smrg   if (pipeline_cache_str != NULL) {
2147ec681f3Smrg      if (strncmp(pipeline_cache_str, "full", 4) == 0) {
2157ec681f3Smrg         /* nothing to do, just to filter correct values */
2167ec681f3Smrg      } else if (strncmp(pipeline_cache_str, "no-default-cache", 16) == 0) {
2177ec681f3Smrg         instance->default_pipeline_cache_enabled = false;
2187ec681f3Smrg      } else if (strncmp(pipeline_cache_str, "off", 3) == 0) {
2197ec681f3Smrg         instance->pipeline_cache_enabled = false;
2207ec681f3Smrg         instance->default_pipeline_cache_enabled = false;
2217ec681f3Smrg      } else {
2227ec681f3Smrg         fprintf(stderr, "Wrong value for envvar V3DV_ENABLE_PIPELINE_CACHE. "
2237ec681f3Smrg                 "Allowed values are: full, no-default-cache, off\n");
2247ec681f3Smrg      }
2257ec681f3Smrg   }
2267ec681f3Smrg
2277ec681f3Smrg   if (instance->pipeline_cache_enabled == false) {
2287ec681f3Smrg      fprintf(stderr, "WARNING: v3dv pipeline cache is disabled. Performance "
2297ec681f3Smrg              "can be affected negatively\n");
2307ec681f3Smrg   } else {
2317ec681f3Smrg      if (instance->default_pipeline_cache_enabled == false) {
2327ec681f3Smrg        fprintf(stderr, "WARNING: default v3dv pipeline cache is disabled. "
2337ec681f3Smrg                "Performance can be affected negatively\n");
2347ec681f3Smrg      }
2357ec681f3Smrg   }
2367ec681f3Smrg
2377ec681f3Smrg   util_cpu_detect();
2387ec681f3Smrg
2397ec681f3Smrg   VG(VALGRIND_CREATE_MEMPOOL(instance, 0, false));
2407ec681f3Smrg
2417ec681f3Smrg   *pInstance = v3dv_instance_to_handle(instance);
2427ec681f3Smrg
2437ec681f3Smrg   return VK_SUCCESS;
2447ec681f3Smrg}
2457ec681f3Smrg
2467ec681f3Smrgstatic void
2477ec681f3Smrgv3dv_physical_device_free_disk_cache(struct v3dv_physical_device *device)
2487ec681f3Smrg{
2497ec681f3Smrg#ifdef ENABLE_SHADER_CACHE
2507ec681f3Smrg   if (device->disk_cache)
2517ec681f3Smrg      disk_cache_destroy(device->disk_cache);
2527ec681f3Smrg#else
2537ec681f3Smrg   assert(device->disk_cache == NULL);
2547ec681f3Smrg#endif
2557ec681f3Smrg}
2567ec681f3Smrg
2577ec681f3Smrgstatic void
2587ec681f3Smrgphysical_device_finish(struct v3dv_physical_device *device)
2597ec681f3Smrg{
2607ec681f3Smrg   v3dv_wsi_finish(device);
2617ec681f3Smrg   v3dv_physical_device_free_disk_cache(device);
2627ec681f3Smrg   v3d_compiler_free(device->compiler);
2637ec681f3Smrg
2647ec681f3Smrg   close(device->render_fd);
2657ec681f3Smrg   if (device->display_fd >= 0)
2667ec681f3Smrg      close(device->display_fd);
2677ec681f3Smrg   if (device->master_fd >= 0)
2687ec681f3Smrg      close(device->master_fd);
2697ec681f3Smrg
2707ec681f3Smrg   free(device->name);
2717ec681f3Smrg
2727ec681f3Smrg#if using_v3d_simulator
2737ec681f3Smrg   v3d_simulator_destroy(device->sim_file);
2747ec681f3Smrg#endif
2757ec681f3Smrg
2767ec681f3Smrg   vk_physical_device_finish(&device->vk);
2777ec681f3Smrg   mtx_destroy(&device->mutex);
2787ec681f3Smrg}
2797ec681f3Smrg
2807ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
2817ec681f3Smrgv3dv_DestroyInstance(VkInstance _instance,
2827ec681f3Smrg                     const VkAllocationCallbacks *pAllocator)
2837ec681f3Smrg{
2847ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
2857ec681f3Smrg
2867ec681f3Smrg   if (!instance)
2877ec681f3Smrg      return;
2887ec681f3Smrg
2897ec681f3Smrg   if (instance->physicalDeviceCount > 0) {
2907ec681f3Smrg      /* We support at most one physical device. */
2917ec681f3Smrg      assert(instance->physicalDeviceCount == 1);
2927ec681f3Smrg      physical_device_finish(&instance->physicalDevice);
2937ec681f3Smrg   }
2947ec681f3Smrg
2957ec681f3Smrg   VG(VALGRIND_DESTROY_MEMPOOL(instance));
2967ec681f3Smrg
2977ec681f3Smrg   vk_instance_finish(&instance->vk);
2987ec681f3Smrg   vk_free(&instance->vk.alloc, instance);
2997ec681f3Smrg}
3007ec681f3Smrg
3017ec681f3Smrgstatic uint64_t
3027ec681f3Smrgcompute_heap_size()
3037ec681f3Smrg{
3047ec681f3Smrg#if !using_v3d_simulator
3057ec681f3Smrg   /* Query the total ram from the system */
3067ec681f3Smrg   struct sysinfo info;
3077ec681f3Smrg   sysinfo(&info);
3087ec681f3Smrg
3097ec681f3Smrg   uint64_t total_ram = (uint64_t)info.totalram * (uint64_t)info.mem_unit;
3107ec681f3Smrg#else
3117ec681f3Smrg   uint64_t total_ram = (uint64_t) v3d_simulator_get_mem_size();
3127ec681f3Smrg#endif
3137ec681f3Smrg
3147ec681f3Smrg   /* We don't want to burn too much ram with the GPU.  If the user has 4GiB
3157ec681f3Smrg    * or less, we use at most half.  If they have more than 4GiB, we use 3/4.
3167ec681f3Smrg    */
3177ec681f3Smrg   uint64_t available_ram;
3187ec681f3Smrg   if (total_ram <= 4ull * 1024ull * 1024ull * 1024ull)
3197ec681f3Smrg      available_ram = total_ram / 2;
3207ec681f3Smrg   else
3217ec681f3Smrg      available_ram = total_ram * 3 / 4;
3227ec681f3Smrg
3237ec681f3Smrg   return available_ram;
3247ec681f3Smrg}
3257ec681f3Smrg
3267ec681f3Smrg#if !using_v3d_simulator
3277ec681f3Smrg#ifdef VK_USE_PLATFORM_XCB_KHR
3287ec681f3Smrgstatic int
3297ec681f3Smrgcreate_display_fd_xcb(VkIcdSurfaceBase *surface)
3307ec681f3Smrg{
3317ec681f3Smrg   int fd = -1;
3327ec681f3Smrg
3337ec681f3Smrg   xcb_connection_t *conn;
3347ec681f3Smrg   xcb_dri3_open_reply_t *reply = NULL;
3357ec681f3Smrg   if (surface) {
3367ec681f3Smrg      if (surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
3377ec681f3Smrg         conn = XGetXCBConnection(((VkIcdSurfaceXlib *)surface)->dpy);
3387ec681f3Smrg      else
3397ec681f3Smrg         conn = ((VkIcdSurfaceXcb *)surface)->connection;
3407ec681f3Smrg   } else {
3417ec681f3Smrg      conn = xcb_connect(NULL, NULL);
3427ec681f3Smrg   }
3437ec681f3Smrg
3447ec681f3Smrg   if (xcb_connection_has_error(conn))
3457ec681f3Smrg      goto finish;
3467ec681f3Smrg
3477ec681f3Smrg   const xcb_setup_t *setup = xcb_get_setup(conn);
3487ec681f3Smrg   xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
3497ec681f3Smrg   xcb_screen_t *screen = iter.data;
3507ec681f3Smrg
3517ec681f3Smrg   xcb_dri3_open_cookie_t cookie;
3527ec681f3Smrg   cookie = xcb_dri3_open(conn, screen->root, None);
3537ec681f3Smrg   reply = xcb_dri3_open_reply(conn, cookie, NULL);
3547ec681f3Smrg   if (!reply)
3557ec681f3Smrg      goto finish;
3567ec681f3Smrg
3577ec681f3Smrg   if (reply->nfd != 1)
3587ec681f3Smrg      goto finish;
3597ec681f3Smrg
3607ec681f3Smrg   fd = xcb_dri3_open_reply_fds(conn, reply)[0];
3617ec681f3Smrg   fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
3627ec681f3Smrg
3637ec681f3Smrgfinish:
3647ec681f3Smrg   if (!surface)
3657ec681f3Smrg      xcb_disconnect(conn);
3667ec681f3Smrg   if (reply)
3677ec681f3Smrg      free(reply);
3687ec681f3Smrg
3697ec681f3Smrg   return fd;
3707ec681f3Smrg}
3717ec681f3Smrg#endif
3727ec681f3Smrg
3737ec681f3Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR
3747ec681f3Smrgstruct v3dv_wayland_info {
3757ec681f3Smrg   struct wl_drm *wl_drm;
3767ec681f3Smrg   int fd;
3777ec681f3Smrg   bool is_set;
3787ec681f3Smrg   bool authenticated;
3797ec681f3Smrg};
3807ec681f3Smrg
3817ec681f3Smrgstatic void
3827ec681f3Smrgv3dv_drm_handle_device(void *data, struct wl_drm *drm, const char *device)
3837ec681f3Smrg{
3847ec681f3Smrg   struct v3dv_wayland_info *info = data;
3857ec681f3Smrg   info->fd = open(device, O_RDWR | O_CLOEXEC);
3867ec681f3Smrg   info->is_set = info->fd != -1;
3877ec681f3Smrg   if (!info->is_set) {
3887ec681f3Smrg      fprintf(stderr, "v3dv_drm_handle_device: could not open %s (%s)\n",
3897ec681f3Smrg              device, strerror(errno));
3907ec681f3Smrg      return;
3917ec681f3Smrg   }
3927ec681f3Smrg
3937ec681f3Smrg   drm_magic_t magic;
3947ec681f3Smrg   if (drmGetMagic(info->fd, &magic)) {
3957ec681f3Smrg      fprintf(stderr, "v3dv_drm_handle_device: drmGetMagic failed\n");
3967ec681f3Smrg      close(info->fd);
3977ec681f3Smrg      info->fd = -1;
3987ec681f3Smrg      info->is_set = false;
3997ec681f3Smrg      return;
4007ec681f3Smrg   }
4017ec681f3Smrg   wl_drm_authenticate(info->wl_drm, magic);
4027ec681f3Smrg}
4037ec681f3Smrg
4047ec681f3Smrgstatic void
4057ec681f3Smrgv3dv_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
4067ec681f3Smrg{
4077ec681f3Smrg}
4087ec681f3Smrg
4097ec681f3Smrgstatic void
4107ec681f3Smrgv3dv_drm_handle_authenticated(void *data, struct wl_drm *drm)
4117ec681f3Smrg{
4127ec681f3Smrg   struct v3dv_wayland_info *info = data;
4137ec681f3Smrg   info->authenticated = true;
4147ec681f3Smrg}
4157ec681f3Smrg
4167ec681f3Smrgstatic void
4177ec681f3Smrgv3dv_drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
4187ec681f3Smrg{
4197ec681f3Smrg}
4207ec681f3Smrg
4217ec681f3Smrgstruct wl_drm_listener v3dv_drm_listener = {
4227ec681f3Smrg   .device = v3dv_drm_handle_device,
4237ec681f3Smrg   .format = v3dv_drm_handle_format,
4247ec681f3Smrg   .authenticated = v3dv_drm_handle_authenticated,
4257ec681f3Smrg   .capabilities = v3dv_drm_handle_capabilities
4267ec681f3Smrg};
4277ec681f3Smrg
4287ec681f3Smrgstatic void
4297ec681f3Smrgv3dv_registry_global(void *data,
4307ec681f3Smrg                     struct wl_registry *registry,
4317ec681f3Smrg                     uint32_t name,
4327ec681f3Smrg                     const char *interface,
4337ec681f3Smrg                     uint32_t version)
4347ec681f3Smrg{
4357ec681f3Smrg   struct v3dv_wayland_info *info = data;
4367ec681f3Smrg   if (strcmp(interface, "wl_drm") == 0) {
4377ec681f3Smrg      info->wl_drm = wl_registry_bind(registry, name, &wl_drm_interface,
4387ec681f3Smrg                                      MIN2(version, 2));
4397ec681f3Smrg      wl_drm_add_listener(info->wl_drm, &v3dv_drm_listener, data);
4407ec681f3Smrg   };
4417ec681f3Smrg}
4427ec681f3Smrg
4437ec681f3Smrgstatic void
4447ec681f3Smrgv3dv_registry_global_remove_cb(void *data,
4457ec681f3Smrg                               struct wl_registry *registry,
4467ec681f3Smrg                               uint32_t name)
4477ec681f3Smrg{
4487ec681f3Smrg}
4497ec681f3Smrg
4507ec681f3Smrgstatic int
4517ec681f3Smrgcreate_display_fd_wayland(VkIcdSurfaceBase *surface)
4527ec681f3Smrg{
4537ec681f3Smrg   struct wl_display *display;
4547ec681f3Smrg   struct wl_registry *registry = NULL;
4557ec681f3Smrg
4567ec681f3Smrg   struct v3dv_wayland_info info = {
4577ec681f3Smrg      .wl_drm = NULL,
4587ec681f3Smrg      .fd = -1,
4597ec681f3Smrg      .is_set = false,
4607ec681f3Smrg      .authenticated = false
4617ec681f3Smrg   };
4627ec681f3Smrg
4637ec681f3Smrg   if (surface)
4647ec681f3Smrg      display = ((VkIcdSurfaceWayland *) surface)->display;
4657ec681f3Smrg   else
4667ec681f3Smrg      display = wl_display_connect(NULL);
4677ec681f3Smrg
4687ec681f3Smrg   if (!display)
4697ec681f3Smrg      return -1;
4707ec681f3Smrg
4717ec681f3Smrg   registry = wl_display_get_registry(display);
4727ec681f3Smrg   if (!registry) {
4737ec681f3Smrg      if (!surface)
4747ec681f3Smrg         wl_display_disconnect(display);
4757ec681f3Smrg      return -1;
4767ec681f3Smrg   }
4777ec681f3Smrg
4787ec681f3Smrg   static const struct wl_registry_listener registry_listener = {
4797ec681f3Smrg      v3dv_registry_global,
4807ec681f3Smrg      v3dv_registry_global_remove_cb
4817ec681f3Smrg   };
4827ec681f3Smrg   wl_registry_add_listener(registry, &registry_listener, &info);
4837ec681f3Smrg
4847ec681f3Smrg   wl_display_roundtrip(display); /* For the registry advertisement */
4857ec681f3Smrg   wl_display_roundtrip(display); /* For the DRM device event */
4867ec681f3Smrg   wl_display_roundtrip(display); /* For the authentication event */
4877ec681f3Smrg
4887ec681f3Smrg   wl_drm_destroy(info.wl_drm);
4897ec681f3Smrg   wl_registry_destroy(registry);
4907ec681f3Smrg
4917ec681f3Smrg   if (!surface)
4927ec681f3Smrg      wl_display_disconnect(display);
4937ec681f3Smrg
4947ec681f3Smrg   if (!info.is_set)
4957ec681f3Smrg      return -1;
4967ec681f3Smrg
4977ec681f3Smrg   if (!info.authenticated)
4987ec681f3Smrg      return -1;
4997ec681f3Smrg
5007ec681f3Smrg   return info.fd;
5017ec681f3Smrg}
5027ec681f3Smrg#endif
5037ec681f3Smrg
5047ec681f3Smrg/* Acquire an authenticated display fd without a surface reference. This is the
5057ec681f3Smrg * case where the application is making WSI allocations outside the Vulkan
5067ec681f3Smrg * swapchain context (only Zink, for now). Since we lack information about the
5077ec681f3Smrg * underlying surface we just try our best to figure out the correct display
5087ec681f3Smrg * and platform to use. It should work in most cases.
5097ec681f3Smrg */
5107ec681f3Smrgstatic void
5117ec681f3Smrgacquire_display_device_no_surface(struct v3dv_instance *instance,
5127ec681f3Smrg                                  struct v3dv_physical_device *pdevice)
5137ec681f3Smrg{
5147ec681f3Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR
5157ec681f3Smrg   pdevice->display_fd = create_display_fd_wayland(NULL);
5167ec681f3Smrg#endif
5177ec681f3Smrg
5187ec681f3Smrg#ifdef VK_USE_PLATFORM_XCB_KHR
5197ec681f3Smrg   if (pdevice->display_fd == -1)
5207ec681f3Smrg      pdevice->display_fd = create_display_fd_xcb(NULL);
5217ec681f3Smrg#endif
5227ec681f3Smrg
5237ec681f3Smrg#ifdef VK_USE_PLATFORM_DISPLAY_KHR
5247ec681f3Smrg   if (pdevice->display_fd == - 1 && pdevice->master_fd >= 0)
5257ec681f3Smrg      pdevice->display_fd = dup(pdevice->master_fd);
5267ec681f3Smrg#endif
5277ec681f3Smrg}
5287ec681f3Smrg
5297ec681f3Smrg/* Acquire an authenticated display fd from the surface. This is the regular
5307ec681f3Smrg * case where the application is using swapchains to create WSI allocations.
5317ec681f3Smrg * In this case we use the surface information to figure out the correct
5327ec681f3Smrg * display and platform combination.
5337ec681f3Smrg */
5347ec681f3Smrgstatic void
5357ec681f3Smrgacquire_display_device_surface(struct v3dv_instance *instance,
5367ec681f3Smrg                               struct v3dv_physical_device *pdevice,
5377ec681f3Smrg                               VkIcdSurfaceBase *surface)
5387ec681f3Smrg{
5397ec681f3Smrg   /* Mesa will set both of VK_USE_PLATFORM_{XCB,XLIB} when building with
5407ec681f3Smrg    * platform X11, so only check for XCB and rely on XCB to get an
5417ec681f3Smrg    * authenticated device also for Xlib.
5427ec681f3Smrg    */
5437ec681f3Smrg#ifdef VK_USE_PLATFORM_XCB_KHR
5447ec681f3Smrg   if (surface->platform == VK_ICD_WSI_PLATFORM_XCB ||
5457ec681f3Smrg       surface->platform == VK_ICD_WSI_PLATFORM_XLIB) {
5467ec681f3Smrg      pdevice->display_fd = create_display_fd_xcb(surface);
5477ec681f3Smrg   }
5487ec681f3Smrg#endif
5497ec681f3Smrg
5507ec681f3Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR
5517ec681f3Smrg   if (surface->platform == VK_ICD_WSI_PLATFORM_WAYLAND)
5527ec681f3Smrg      pdevice->display_fd = create_display_fd_wayland(surface);
5537ec681f3Smrg#endif
5547ec681f3Smrg
5557ec681f3Smrg#ifdef VK_USE_PLATFORM_DISPLAY_KHR
5567ec681f3Smrg   if (surface->platform == VK_ICD_WSI_PLATFORM_DISPLAY &&
5577ec681f3Smrg       pdevice->master_fd >= 0) {
5587ec681f3Smrg      pdevice->display_fd = dup(pdevice->master_fd);
5597ec681f3Smrg   }
5607ec681f3Smrg#endif
5617ec681f3Smrg}
5627ec681f3Smrg#endif /* !using_v3d_simulator */
5637ec681f3Smrg
5647ec681f3Smrg/* Attempts to get an authenticated display fd from the display server that
5657ec681f3Smrg * we can use to allocate BOs for presentable images.
5667ec681f3Smrg */
5677ec681f3SmrgVkResult
5687ec681f3Smrgv3dv_physical_device_acquire_display(struct v3dv_instance *instance,
5697ec681f3Smrg                                     struct v3dv_physical_device *pdevice,
5707ec681f3Smrg                                     VkIcdSurfaceBase *surface)
5717ec681f3Smrg{
5727ec681f3Smrg   VkResult result = VK_SUCCESS;
5737ec681f3Smrg   mtx_lock(&pdevice->mutex);
5747ec681f3Smrg
5757ec681f3Smrg   if (pdevice->display_fd != -1)
5767ec681f3Smrg      goto done;
5777ec681f3Smrg
5787ec681f3Smrg   /* When running on the simulator we do everything on a single render node so
5797ec681f3Smrg    * we don't need to get an authenticated display fd from the display server.
5807ec681f3Smrg    */
5817ec681f3Smrg#if !using_v3d_simulator
5827ec681f3Smrg   if (surface)
5837ec681f3Smrg      acquire_display_device_surface(instance, pdevice, surface);
5847ec681f3Smrg   else
5857ec681f3Smrg      acquire_display_device_no_surface(instance, pdevice);
5867ec681f3Smrg
5877ec681f3Smrg   if (pdevice->display_fd == -1)
5887ec681f3Smrg      result = VK_ERROR_INITIALIZATION_FAILED;
5897ec681f3Smrg#endif
5907ec681f3Smrg
5917ec681f3Smrgdone:
5927ec681f3Smrg   mtx_unlock(&pdevice->mutex);
5937ec681f3Smrg   return result;
5947ec681f3Smrg}
5957ec681f3Smrg
5967ec681f3Smrgstatic bool
5977ec681f3Smrgv3d_has_feature(struct v3dv_physical_device *device, enum drm_v3d_param feature)
5987ec681f3Smrg{
5997ec681f3Smrg   struct drm_v3d_get_param p = {
6007ec681f3Smrg      .param = feature,
6017ec681f3Smrg   };
6027ec681f3Smrg   if (v3dv_ioctl(device->render_fd, DRM_IOCTL_V3D_GET_PARAM, &p) != 0)
6037ec681f3Smrg      return false;
6047ec681f3Smrg   return p.value;
6057ec681f3Smrg}
6067ec681f3Smrg
6077ec681f3Smrgstatic bool
6087ec681f3Smrgdevice_has_expected_features(struct v3dv_physical_device *device)
6097ec681f3Smrg{
6107ec681f3Smrg   return v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_TFU) &&
6117ec681f3Smrg          v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CSD) &&
6127ec681f3Smrg          v3d_has_feature(device, DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH);
6137ec681f3Smrg}
6147ec681f3Smrg
6157ec681f3Smrg
6167ec681f3Smrgstatic VkResult
6177ec681f3Smrginit_uuids(struct v3dv_physical_device *device)
6187ec681f3Smrg{
6197ec681f3Smrg   const struct build_id_note *note =
6207ec681f3Smrg      build_id_find_nhdr_for_addr(init_uuids);
6217ec681f3Smrg   if (!note) {
6227ec681f3Smrg      return vk_errorf(device->vk.instance,
6237ec681f3Smrg                       VK_ERROR_INITIALIZATION_FAILED,
6247ec681f3Smrg                       "Failed to find build-id");
6257ec681f3Smrg   }
6267ec681f3Smrg
6277ec681f3Smrg   unsigned build_id_len = build_id_length(note);
6287ec681f3Smrg   if (build_id_len < 20) {
6297ec681f3Smrg      return vk_errorf(device->vk.instance,
6307ec681f3Smrg                       VK_ERROR_INITIALIZATION_FAILED,
6317ec681f3Smrg                       "build-id too short.  It needs to be a SHA");
6327ec681f3Smrg   }
6337ec681f3Smrg
6347ec681f3Smrg   memcpy(device->driver_build_sha1, build_id_data(note), 20);
6357ec681f3Smrg
6367ec681f3Smrg   uint32_t vendor_id = v3dv_physical_device_vendor_id(device);
6377ec681f3Smrg   uint32_t device_id = v3dv_physical_device_device_id(device);
6387ec681f3Smrg
6397ec681f3Smrg   struct mesa_sha1 sha1_ctx;
6407ec681f3Smrg   uint8_t sha1[20];
6417ec681f3Smrg   STATIC_ASSERT(VK_UUID_SIZE <= sizeof(sha1));
6427ec681f3Smrg
6437ec681f3Smrg   /* The pipeline cache UUID is used for determining when a pipeline cache is
6447ec681f3Smrg    * invalid.  It needs both a driver build and the PCI ID of the device.
6457ec681f3Smrg    */
6467ec681f3Smrg   _mesa_sha1_init(&sha1_ctx);
6477ec681f3Smrg   _mesa_sha1_update(&sha1_ctx, build_id_data(note), build_id_len);
6487ec681f3Smrg   _mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id));
6497ec681f3Smrg   _mesa_sha1_final(&sha1_ctx, sha1);
6507ec681f3Smrg   memcpy(device->pipeline_cache_uuid, sha1, VK_UUID_SIZE);
6517ec681f3Smrg
6527ec681f3Smrg   /* The driver UUID is used for determining sharability of images and memory
6537ec681f3Smrg    * between two Vulkan instances in separate processes.  People who want to
6547ec681f3Smrg    * share memory need to also check the device UUID (below) so all this
6557ec681f3Smrg    * needs to be is the build-id.
6567ec681f3Smrg    */
6577ec681f3Smrg   memcpy(device->driver_uuid, build_id_data(note), VK_UUID_SIZE);
6587ec681f3Smrg
6597ec681f3Smrg   /* The device UUID uniquely identifies the given device within the machine.
6607ec681f3Smrg    * Since we never have more than one device, this doesn't need to be a real
6617ec681f3Smrg    * UUID.
6627ec681f3Smrg    */
6637ec681f3Smrg   _mesa_sha1_init(&sha1_ctx);
6647ec681f3Smrg   _mesa_sha1_update(&sha1_ctx, &vendor_id, sizeof(vendor_id));
6657ec681f3Smrg   _mesa_sha1_update(&sha1_ctx, &device_id, sizeof(device_id));
6667ec681f3Smrg   _mesa_sha1_final(&sha1_ctx, sha1);
6677ec681f3Smrg   memcpy(device->device_uuid, sha1, VK_UUID_SIZE);
6687ec681f3Smrg
6697ec681f3Smrg   return VK_SUCCESS;
6707ec681f3Smrg}
6717ec681f3Smrg
6727ec681f3Smrgstatic void
6737ec681f3Smrgv3dv_physical_device_init_disk_cache(struct v3dv_physical_device *device)
6747ec681f3Smrg{
6757ec681f3Smrg#ifdef ENABLE_SHADER_CACHE
6767ec681f3Smrg   char timestamp[41];
6777ec681f3Smrg   _mesa_sha1_format(timestamp, device->driver_build_sha1);
6787ec681f3Smrg
6797ec681f3Smrg   assert(device->name);
6807ec681f3Smrg   device->disk_cache = disk_cache_create(device->name, timestamp, 0);
6817ec681f3Smrg#else
6827ec681f3Smrg   device->disk_cache = NULL;
6837ec681f3Smrg#endif
6847ec681f3Smrg}
6857ec681f3Smrg
6867ec681f3Smrgstatic VkResult
6877ec681f3Smrgphysical_device_init(struct v3dv_physical_device *device,
6887ec681f3Smrg                     struct v3dv_instance *instance,
6897ec681f3Smrg                     drmDevicePtr drm_render_device,
6907ec681f3Smrg                     drmDevicePtr drm_primary_device)
6917ec681f3Smrg{
6927ec681f3Smrg   VkResult result = VK_SUCCESS;
6937ec681f3Smrg   int32_t master_fd = -1;
6947ec681f3Smrg   int32_t render_fd = -1;
6957ec681f3Smrg
6967ec681f3Smrg   struct vk_physical_device_dispatch_table dispatch_table;
6977ec681f3Smrg   vk_physical_device_dispatch_table_from_entrypoints
6987ec681f3Smrg      (&dispatch_table, &v3dv_physical_device_entrypoints, true);
6997ec681f3Smrg   vk_physical_device_dispatch_table_from_entrypoints(
7007ec681f3Smrg      &dispatch_table, &wsi_physical_device_entrypoints, false);
7017ec681f3Smrg
7027ec681f3Smrg   result = vk_physical_device_init(&device->vk, &instance->vk, NULL,
7037ec681f3Smrg                                    &dispatch_table);
7047ec681f3Smrg
7057ec681f3Smrg   if (result != VK_SUCCESS)
7067ec681f3Smrg      goto fail;
7077ec681f3Smrg
7087ec681f3Smrg   assert(drm_render_device);
7097ec681f3Smrg   const char *path = drm_render_device->nodes[DRM_NODE_RENDER];
7107ec681f3Smrg   render_fd = open(path, O_RDWR | O_CLOEXEC);
7117ec681f3Smrg   if (render_fd < 0) {
7127ec681f3Smrg      fprintf(stderr, "Opening %s failed: %s\n", path, strerror(errno));
7137ec681f3Smrg      result = VK_ERROR_INCOMPATIBLE_DRIVER;
7147ec681f3Smrg      goto fail;
7157ec681f3Smrg   }
7167ec681f3Smrg
7177ec681f3Smrg   /* If we are running on VK_KHR_display we need to acquire the master
7187ec681f3Smrg    * display device now for the v3dv_wsi_init() call below. For anything else
7197ec681f3Smrg    * we postpone that until a swapchain is created.
7207ec681f3Smrg    */
7217ec681f3Smrg
7227ec681f3Smrg   const char *primary_path;
7237ec681f3Smrg#if !using_v3d_simulator
7247ec681f3Smrg   if (drm_primary_device)
7257ec681f3Smrg      primary_path = drm_primary_device->nodes[DRM_NODE_PRIMARY];
7267ec681f3Smrg   else
7277ec681f3Smrg      primary_path = NULL;
7287ec681f3Smrg#else
7297ec681f3Smrg   primary_path = drm_render_device->nodes[DRM_NODE_PRIMARY];
7307ec681f3Smrg#endif
7317ec681f3Smrg
7327ec681f3Smrg   struct stat primary_stat = {0}, render_stat = {0};
7337ec681f3Smrg
7347ec681f3Smrg   device->has_primary = primary_path;
7357ec681f3Smrg   if (device->has_primary) {
7367ec681f3Smrg      if (stat(primary_path, &primary_stat) != 0) {
7377ec681f3Smrg         result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
7387ec681f3Smrg                            "failed to stat DRM primary node %s",
7397ec681f3Smrg                            primary_path);
7407ec681f3Smrg         goto fail;
7417ec681f3Smrg      }
7427ec681f3Smrg
7437ec681f3Smrg      device->primary_devid = primary_stat.st_rdev;
7447ec681f3Smrg   }
7457ec681f3Smrg
7467ec681f3Smrg   if (fstat(render_fd, &render_stat) != 0) {
7477ec681f3Smrg      result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
7487ec681f3Smrg                         "failed to stat DRM render node %s",
7497ec681f3Smrg                         path);
7507ec681f3Smrg      goto fail;
7517ec681f3Smrg   }
7527ec681f3Smrg   device->has_render = true;
7537ec681f3Smrg   device->render_devid = render_stat.st_rdev;
7547ec681f3Smrg
7557ec681f3Smrg   if (instance->vk.enabled_extensions.KHR_display) {
7567ec681f3Smrg#if !using_v3d_simulator
7577ec681f3Smrg      /* Open the primary node on the vc4 display device */
7587ec681f3Smrg      assert(drm_primary_device);
7597ec681f3Smrg      master_fd = open(primary_path, O_RDWR | O_CLOEXEC);
7607ec681f3Smrg#else
7617ec681f3Smrg      /* There is only one device with primary and render nodes.
7627ec681f3Smrg       * Open its primary node.
7637ec681f3Smrg       */
7647ec681f3Smrg      master_fd = open(primary_path, O_RDWR | O_CLOEXEC);
7657ec681f3Smrg#endif
7667ec681f3Smrg   }
7677ec681f3Smrg
7687ec681f3Smrg#if using_v3d_simulator
7697ec681f3Smrg   device->sim_file = v3d_simulator_init(render_fd);
7707ec681f3Smrg#endif
7717ec681f3Smrg
7727ec681f3Smrg   device->render_fd = render_fd;    /* The v3d render node  */
7737ec681f3Smrg   device->display_fd = -1;          /* Authenticated vc4 primary node */
7747ec681f3Smrg   device->master_fd = master_fd;    /* Master vc4 primary node */
7757ec681f3Smrg
7767ec681f3Smrg   if (!v3d_get_device_info(device->render_fd, &device->devinfo, &v3dv_ioctl)) {
7777ec681f3Smrg      result = VK_ERROR_INCOMPATIBLE_DRIVER;
7787ec681f3Smrg      goto fail;
7797ec681f3Smrg   }
7807ec681f3Smrg
7817ec681f3Smrg   if (device->devinfo.ver < 42) {
7827ec681f3Smrg      result = VK_ERROR_INCOMPATIBLE_DRIVER;
7837ec681f3Smrg      goto fail;
7847ec681f3Smrg   }
7857ec681f3Smrg
7867ec681f3Smrg   if (!device_has_expected_features(device)) {
7877ec681f3Smrg      result = VK_ERROR_INCOMPATIBLE_DRIVER;
7887ec681f3Smrg      goto fail;
7897ec681f3Smrg   }
7907ec681f3Smrg
7917ec681f3Smrg   result = init_uuids(device);
7927ec681f3Smrg   if (result != VK_SUCCESS)
7937ec681f3Smrg      goto fail;
7947ec681f3Smrg
7957ec681f3Smrg   device->compiler = v3d_compiler_init(&device->devinfo);
7967ec681f3Smrg   device->next_program_id = 0;
7977ec681f3Smrg
7987ec681f3Smrg   ASSERTED int len =
7997ec681f3Smrg      asprintf(&device->name, "V3D %d.%d",
8007ec681f3Smrg               device->devinfo.ver / 10, device->devinfo.ver % 10);
8017ec681f3Smrg   assert(len != -1);
8027ec681f3Smrg
8037ec681f3Smrg   v3dv_physical_device_init_disk_cache(device);
8047ec681f3Smrg
8057ec681f3Smrg   /* Setup available memory heaps and types */
8067ec681f3Smrg   VkPhysicalDeviceMemoryProperties *mem = &device->memory;
8077ec681f3Smrg   mem->memoryHeapCount = 1;
8087ec681f3Smrg   mem->memoryHeaps[0].size = compute_heap_size();
8097ec681f3Smrg   mem->memoryHeaps[0].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
8107ec681f3Smrg
8117ec681f3Smrg   /* This is the only combination required by the spec */
8127ec681f3Smrg   mem->memoryTypeCount = 1;
8137ec681f3Smrg   mem->memoryTypes[0].propertyFlags =
8147ec681f3Smrg      VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
8157ec681f3Smrg      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
8167ec681f3Smrg      VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
8177ec681f3Smrg   mem->memoryTypes[0].heapIndex = 0;
8187ec681f3Smrg
8197ec681f3Smrg   device->options.merge_jobs = getenv("V3DV_NO_MERGE_JOBS") == NULL;
8207ec681f3Smrg
8217ec681f3Smrg   result = v3dv_wsi_init(device);
8227ec681f3Smrg   if (result != VK_SUCCESS) {
8237ec681f3Smrg      vk_error(instance, result);
8247ec681f3Smrg      goto fail;
8257ec681f3Smrg   }
8267ec681f3Smrg
8277ec681f3Smrg   get_device_extensions(device, &device->vk.supported_extensions);
8287ec681f3Smrg
8297ec681f3Smrg   pthread_mutex_init(&device->mutex, NULL);
8307ec681f3Smrg
8317ec681f3Smrg   return VK_SUCCESS;
8327ec681f3Smrg
8337ec681f3Smrgfail:
8347ec681f3Smrg   vk_physical_device_finish(&device->vk);
8357ec681f3Smrg
8367ec681f3Smrg   if (render_fd >= 0)
8377ec681f3Smrg      close(render_fd);
8387ec681f3Smrg   if (master_fd >= 0)
8397ec681f3Smrg      close(master_fd);
8407ec681f3Smrg
8417ec681f3Smrg   return result;
8427ec681f3Smrg}
8437ec681f3Smrg
8447ec681f3Smrgstatic VkResult
8457ec681f3Smrgenumerate_devices(struct v3dv_instance *instance)
8467ec681f3Smrg{
8477ec681f3Smrg   /* TODO: Check for more devices? */
8487ec681f3Smrg   drmDevicePtr devices[8];
8497ec681f3Smrg   VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER;
8507ec681f3Smrg   int max_devices;
8517ec681f3Smrg
8527ec681f3Smrg   instance->physicalDeviceCount = 0;
8537ec681f3Smrg
8547ec681f3Smrg   max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
8557ec681f3Smrg   if (max_devices < 1)
8567ec681f3Smrg      return VK_ERROR_INCOMPATIBLE_DRIVER;
8577ec681f3Smrg
8587ec681f3Smrg#if !using_v3d_simulator
8597ec681f3Smrg   int32_t v3d_idx = -1;
8607ec681f3Smrg   int32_t vc4_idx = -1;
8617ec681f3Smrg#endif
8627ec681f3Smrg   for (unsigned i = 0; i < (unsigned)max_devices; i++) {
8637ec681f3Smrg#if using_v3d_simulator
8647ec681f3Smrg      /* In the simulator, we look for an Intel render node */
8657ec681f3Smrg      const int required_nodes = (1 << DRM_NODE_RENDER) | (1 << DRM_NODE_PRIMARY);
8667ec681f3Smrg      if ((devices[i]->available_nodes & required_nodes) == required_nodes &&
8677ec681f3Smrg           devices[i]->bustype == DRM_BUS_PCI &&
8687ec681f3Smrg           devices[i]->deviceinfo.pci->vendor_id == 0x8086) {
8697ec681f3Smrg         result = physical_device_init(&instance->physicalDevice, instance,
8707ec681f3Smrg                                       devices[i], NULL);
8717ec681f3Smrg         if (result != VK_ERROR_INCOMPATIBLE_DRIVER)
8727ec681f3Smrg            break;
8737ec681f3Smrg      }
8747ec681f3Smrg#else
8757ec681f3Smrg      /* On actual hardware, we should have a render node (v3d)
8767ec681f3Smrg       * and a primary node (vc4). We will need to use the primary
8777ec681f3Smrg       * to allocate WSI buffers and share them with the render node
8787ec681f3Smrg       * via prime, but that is a privileged operation so we need the
8797ec681f3Smrg       * primary node to be authenticated, and for that we need the
8807ec681f3Smrg       * display server to provide the device fd (with DRI3), so we
8817ec681f3Smrg       * here we only check that the device is present but we don't
8827ec681f3Smrg       * try to open it.
8837ec681f3Smrg       */
8847ec681f3Smrg      if (devices[i]->bustype != DRM_BUS_PLATFORM)
8857ec681f3Smrg         continue;
8867ec681f3Smrg
8877ec681f3Smrg      if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER) {
8887ec681f3Smrg         char **compat = devices[i]->deviceinfo.platform->compatible;
8897ec681f3Smrg         while (*compat) {
8907ec681f3Smrg            if (strncmp(*compat, "brcm,2711-v3d", 13) == 0) {
8917ec681f3Smrg               v3d_idx = i;
8927ec681f3Smrg               break;
8937ec681f3Smrg            }
8947ec681f3Smrg            compat++;
8957ec681f3Smrg         }
8967ec681f3Smrg      } else if (devices[i]->available_nodes & 1 << DRM_NODE_PRIMARY) {
8977ec681f3Smrg         char **compat = devices[i]->deviceinfo.platform->compatible;
8987ec681f3Smrg         while (*compat) {
8997ec681f3Smrg            if (strncmp(*compat, "brcm,bcm2711-vc5", 16) == 0 ||
9007ec681f3Smrg                strncmp(*compat, "brcm,bcm2835-vc4", 16) == 0 ) {
9017ec681f3Smrg               vc4_idx = i;
9027ec681f3Smrg               break;
9037ec681f3Smrg            }
9047ec681f3Smrg            compat++;
9057ec681f3Smrg         }
9067ec681f3Smrg      }
9077ec681f3Smrg#endif
9087ec681f3Smrg   }
9097ec681f3Smrg
9107ec681f3Smrg#if !using_v3d_simulator
9117ec681f3Smrg   if (v3d_idx == -1 || vc4_idx == -1)
9127ec681f3Smrg      result = VK_ERROR_INCOMPATIBLE_DRIVER;
9137ec681f3Smrg   else
9147ec681f3Smrg      result = physical_device_init(&instance->physicalDevice, instance,
9157ec681f3Smrg                                    devices[v3d_idx], devices[vc4_idx]);
9167ec681f3Smrg#endif
9177ec681f3Smrg
9187ec681f3Smrg   drmFreeDevices(devices, max_devices);
9197ec681f3Smrg
9207ec681f3Smrg   if (result == VK_SUCCESS)
9217ec681f3Smrg      instance->physicalDeviceCount = 1;
9227ec681f3Smrg
9237ec681f3Smrg   return result;
9247ec681f3Smrg}
9257ec681f3Smrg
9267ec681f3Smrgstatic VkResult
9277ec681f3Smrginstance_ensure_physical_device(struct v3dv_instance *instance)
9287ec681f3Smrg{
9297ec681f3Smrg   if (instance->physicalDeviceCount < 0) {
9307ec681f3Smrg      VkResult result = enumerate_devices(instance);
9317ec681f3Smrg      if (result != VK_SUCCESS &&
9327ec681f3Smrg          result != VK_ERROR_INCOMPATIBLE_DRIVER)
9337ec681f3Smrg         return result;
9347ec681f3Smrg   }
9357ec681f3Smrg
9367ec681f3Smrg   return VK_SUCCESS;
9377ec681f3Smrg}
9387ec681f3Smrg
9397ec681f3SmrgVKAPI_ATTR VkResult  VKAPI_CALL
9407ec681f3Smrgv3dv_EnumeratePhysicalDevices(VkInstance _instance,
9417ec681f3Smrg                              uint32_t *pPhysicalDeviceCount,
9427ec681f3Smrg                              VkPhysicalDevice *pPhysicalDevices)
9437ec681f3Smrg{
9447ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
9457ec681f3Smrg   VK_OUTARRAY_MAKE(out, pPhysicalDevices, pPhysicalDeviceCount);
9467ec681f3Smrg
9477ec681f3Smrg   VkResult result = instance_ensure_physical_device(instance);
9487ec681f3Smrg   if (result != VK_SUCCESS)
9497ec681f3Smrg      return result;
9507ec681f3Smrg
9517ec681f3Smrg   if (instance->physicalDeviceCount == 0)
9527ec681f3Smrg      return VK_SUCCESS;
9537ec681f3Smrg
9547ec681f3Smrg   assert(instance->physicalDeviceCount == 1);
9557ec681f3Smrg   vk_outarray_append(&out, i) {
9567ec681f3Smrg      *i = v3dv_physical_device_to_handle(&instance->physicalDevice);
9577ec681f3Smrg   }
9587ec681f3Smrg
9597ec681f3Smrg   return vk_outarray_status(&out);
9607ec681f3Smrg}
9617ec681f3Smrg
9627ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
9637ec681f3Smrgv3dv_EnumeratePhysicalDeviceGroups(
9647ec681f3Smrg    VkInstance _instance,
9657ec681f3Smrg    uint32_t *pPhysicalDeviceGroupCount,
9667ec681f3Smrg    VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties)
9677ec681f3Smrg{
9687ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
9697ec681f3Smrg   VK_OUTARRAY_MAKE(out, pPhysicalDeviceGroupProperties,
9707ec681f3Smrg                         pPhysicalDeviceGroupCount);
9717ec681f3Smrg
9727ec681f3Smrg   VkResult result = instance_ensure_physical_device(instance);
9737ec681f3Smrg   if (result != VK_SUCCESS)
9747ec681f3Smrg      return result;
9757ec681f3Smrg
9767ec681f3Smrg   assert(instance->physicalDeviceCount == 1);
9777ec681f3Smrg
9787ec681f3Smrg   vk_outarray_append(&out, p) {
9797ec681f3Smrg      p->physicalDeviceCount = 1;
9807ec681f3Smrg      memset(p->physicalDevices, 0, sizeof(p->physicalDevices));
9817ec681f3Smrg      p->physicalDevices[0] =
9827ec681f3Smrg         v3dv_physical_device_to_handle(&instance->physicalDevice);
9837ec681f3Smrg      p->subsetAllocation = false;
9847ec681f3Smrg
9857ec681f3Smrg      vk_foreach_struct(ext, p->pNext)
9867ec681f3Smrg         v3dv_debug_ignored_stype(ext->sType);
9877ec681f3Smrg   }
9887ec681f3Smrg
9897ec681f3Smrg   return vk_outarray_status(&out);
9907ec681f3Smrg}
9917ec681f3Smrg
9927ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
9937ec681f3Smrgv3dv_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
9947ec681f3Smrg                               VkPhysicalDeviceFeatures *pFeatures)
9957ec681f3Smrg{
9967ec681f3Smrg   memset(pFeatures, 0, sizeof(*pFeatures));
9977ec681f3Smrg
9987ec681f3Smrg   *pFeatures = (VkPhysicalDeviceFeatures) {
9997ec681f3Smrg      .robustBufferAccess = true, /* This feature is mandatory */
10007ec681f3Smrg      .fullDrawIndexUint32 = false, /* Only available since V3D 4.4.9.1 */
10017ec681f3Smrg      .imageCubeArray = true,
10027ec681f3Smrg      .independentBlend = true,
10037ec681f3Smrg      .geometryShader = true,
10047ec681f3Smrg      .tessellationShader = false,
10057ec681f3Smrg      .sampleRateShading = true,
10067ec681f3Smrg      .dualSrcBlend = false,
10077ec681f3Smrg      .logicOp = true,
10087ec681f3Smrg      .multiDrawIndirect = false,
10097ec681f3Smrg      .drawIndirectFirstInstance = true,
10107ec681f3Smrg      .depthClamp = false,
10117ec681f3Smrg      .depthBiasClamp = true,
10127ec681f3Smrg      .fillModeNonSolid = true,
10137ec681f3Smrg      .depthBounds = false, /* Only available since V3D 4.3.16.2 */
10147ec681f3Smrg      .wideLines = true,
10157ec681f3Smrg      .largePoints = true,
10167ec681f3Smrg      .alphaToOne = true,
10177ec681f3Smrg      .multiViewport = false,
10187ec681f3Smrg      .samplerAnisotropy = true,
10197ec681f3Smrg      .textureCompressionETC2 = true,
10207ec681f3Smrg      .textureCompressionASTC_LDR = true,
10217ec681f3Smrg      /* Note that textureCompressionBC requires that the driver support all
10227ec681f3Smrg       * the BC formats. V3D 4.2 only support the BC1-3, so we can't claim
10237ec681f3Smrg       * that we support it.
10247ec681f3Smrg       */
10257ec681f3Smrg      .textureCompressionBC = false,
10267ec681f3Smrg      .occlusionQueryPrecise = true,
10277ec681f3Smrg      .pipelineStatisticsQuery = false,
10287ec681f3Smrg      .vertexPipelineStoresAndAtomics = true,
10297ec681f3Smrg      .fragmentStoresAndAtomics = true,
10307ec681f3Smrg      .shaderTessellationAndGeometryPointSize = true,
10317ec681f3Smrg      .shaderImageGatherExtended = false,
10327ec681f3Smrg      .shaderStorageImageExtendedFormats = true,
10337ec681f3Smrg      .shaderStorageImageMultisample = false,
10347ec681f3Smrg      .shaderStorageImageReadWithoutFormat = false,
10357ec681f3Smrg      .shaderStorageImageWriteWithoutFormat = false,
10367ec681f3Smrg      .shaderUniformBufferArrayDynamicIndexing = false,
10377ec681f3Smrg      .shaderSampledImageArrayDynamicIndexing = false,
10387ec681f3Smrg      .shaderStorageBufferArrayDynamicIndexing = false,
10397ec681f3Smrg      .shaderStorageImageArrayDynamicIndexing = false,
10407ec681f3Smrg      .shaderClipDistance = true,
10417ec681f3Smrg      .shaderCullDistance = false,
10427ec681f3Smrg      .shaderFloat64 = false,
10437ec681f3Smrg      .shaderInt64 = false,
10447ec681f3Smrg      .shaderInt16 = false,
10457ec681f3Smrg      .shaderResourceResidency = false,
10467ec681f3Smrg      .shaderResourceMinLod = false,
10477ec681f3Smrg      .sparseBinding = false,
10487ec681f3Smrg      .sparseResidencyBuffer = false,
10497ec681f3Smrg      .sparseResidencyImage2D = false,
10507ec681f3Smrg      .sparseResidencyImage3D = false,
10517ec681f3Smrg      .sparseResidency2Samples = false,
10527ec681f3Smrg      .sparseResidency4Samples = false,
10537ec681f3Smrg      .sparseResidency8Samples = false,
10547ec681f3Smrg      .sparseResidency16Samples = false,
10557ec681f3Smrg      .sparseResidencyAliased = false,
10567ec681f3Smrg      .variableMultisampleRate = false,
10577ec681f3Smrg      .inheritedQueries = true,
10587ec681f3Smrg   };
10597ec681f3Smrg}
10607ec681f3Smrg
10617ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
10627ec681f3Smrgv3dv_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
10637ec681f3Smrg                                VkPhysicalDeviceFeatures2 *pFeatures)
10647ec681f3Smrg{
10657ec681f3Smrg   v3dv_GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features);
10667ec681f3Smrg
10677ec681f3Smrg   VkPhysicalDeviceVulkan11Features vk11 = {
10687ec681f3Smrg      .storageBuffer16BitAccess = false,
10697ec681f3Smrg      .uniformAndStorageBuffer16BitAccess = false,
10707ec681f3Smrg      .storagePushConstant16 = false,
10717ec681f3Smrg      .storageInputOutput16 = false,
10727ec681f3Smrg      .multiview = true,
10737ec681f3Smrg      .multiviewGeometryShader = false,
10747ec681f3Smrg      .multiviewTessellationShader = false,
10757ec681f3Smrg      .variablePointersStorageBuffer = true,
10767ec681f3Smrg      /* FIXME: this needs support for non-constant index on UBO/SSBO */
10777ec681f3Smrg      .variablePointers = false,
10787ec681f3Smrg      .protectedMemory = false,
10797ec681f3Smrg      .samplerYcbcrConversion = false,
10807ec681f3Smrg      .shaderDrawParameters = false,
10817ec681f3Smrg   };
10827ec681f3Smrg
10837ec681f3Smrg   vk_foreach_struct(ext, pFeatures->pNext) {
10847ec681f3Smrg      switch (ext->sType) {
10857ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: {
10867ec681f3Smrg         VkPhysicalDeviceCustomBorderColorFeaturesEXT *features =
10877ec681f3Smrg            (VkPhysicalDeviceCustomBorderColorFeaturesEXT *)ext;
10887ec681f3Smrg         features->customBorderColors = true;
10897ec681f3Smrg         features->customBorderColorWithoutFormat = false;
10907ec681f3Smrg         break;
10917ec681f3Smrg      }
10927ec681f3Smrg
10937ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR: {
10947ec681f3Smrg         VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR *features =
10957ec681f3Smrg            (VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR *)ext;
10967ec681f3Smrg         features->uniformBufferStandardLayout = true;
10977ec681f3Smrg         break;
10987ec681f3Smrg      }
10997ec681f3Smrg
11007ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT: {
11017ec681f3Smrg         VkPhysicalDevicePrivateDataFeaturesEXT *features =
11027ec681f3Smrg            (VkPhysicalDevicePrivateDataFeaturesEXT *)ext;
11037ec681f3Smrg         features->privateData = true;
11047ec681f3Smrg         break;
11057ec681f3Smrg      }
11067ec681f3Smrg
11077ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT: {
11087ec681f3Smrg         VkPhysicalDeviceIndexTypeUint8FeaturesEXT *features =
11097ec681f3Smrg            (VkPhysicalDeviceIndexTypeUint8FeaturesEXT *)ext;
11107ec681f3Smrg         features->indexTypeUint8 = true;
11117ec681f3Smrg         break;
11127ec681f3Smrg      }
11137ec681f3Smrg
11147ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: {
11157ec681f3Smrg          VkPhysicalDeviceColorWriteEnableFeaturesEXT *features = (void *) ext;
11167ec681f3Smrg          features->colorWriteEnable = true;
11177ec681f3Smrg          break;
11187ec681f3Smrg      }
11197ec681f3Smrg
11207ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT: {
11217ec681f3Smrg         VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT *features = (void *) ext;
11227ec681f3Smrg         features->pipelineCreationCacheControl = true;
11237ec681f3Smrg         break;
11247ec681f3Smrg      }
11257ec681f3Smrg
11267ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT: {
11277ec681f3Smrg         VkPhysicalDeviceProvokingVertexFeaturesEXT *features = (void *) ext;
11287ec681f3Smrg         features->provokingVertexLast = true;
11297ec681f3Smrg         /* FIXME: update when supporting EXT_transform_feedback */
11307ec681f3Smrg         features->transformFeedbackPreservesProvokingVertex = false;
11317ec681f3Smrg         break;
11327ec681f3Smrg      }
11337ec681f3Smrg
11347ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: {
11357ec681f3Smrg         VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *features =
11367ec681f3Smrg            (void *) ext;
11377ec681f3Smrg         features->vertexAttributeInstanceRateDivisor = true;
11387ec681f3Smrg         features->vertexAttributeInstanceRateZeroDivisor = false;
11397ec681f3Smrg         break;
11407ec681f3Smrg      }
11417ec681f3Smrg
11427ec681f3Smrg      /* Vulkan 1.1 */
11437ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: {
11447ec681f3Smrg         VkPhysicalDeviceVulkan11Features *features =
11457ec681f3Smrg            (VkPhysicalDeviceVulkan11Features *)ext;
11467ec681f3Smrg         memcpy(features, &vk11, sizeof(VkPhysicalDeviceVulkan11Features));
11477ec681f3Smrg         break;
11487ec681f3Smrg      }
11497ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: {
11507ec681f3Smrg         VkPhysicalDevice16BitStorageFeatures *features = (void *) ext;
11517ec681f3Smrg         features->storageBuffer16BitAccess = vk11.storageBuffer16BitAccess;
11527ec681f3Smrg         features->uniformAndStorageBuffer16BitAccess =
11537ec681f3Smrg            vk11.uniformAndStorageBuffer16BitAccess;
11547ec681f3Smrg         features->storagePushConstant16 = vk11.storagePushConstant16;
11557ec681f3Smrg         features->storageInputOutput16 = vk11.storageInputOutput16;
11567ec681f3Smrg         break;
11577ec681f3Smrg      }
11587ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: {
11597ec681f3Smrg         VkPhysicalDeviceMultiviewFeatures *features = (void *) ext;
11607ec681f3Smrg         features->multiview = vk11.multiview;
11617ec681f3Smrg         features->multiviewGeometryShader = vk11.multiviewGeometryShader;
11627ec681f3Smrg         features->multiviewTessellationShader = vk11.multiviewTessellationShader;
11637ec681f3Smrg         break;
11647ec681f3Smrg      }
11657ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: {
11667ec681f3Smrg         VkPhysicalDeviceProtectedMemoryFeatures *features = (void *) ext;
11677ec681f3Smrg         features->protectedMemory = vk11.protectedMemory;
11687ec681f3Smrg         break;
11697ec681f3Smrg      }
11707ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: {
11717ec681f3Smrg         VkPhysicalDeviceSamplerYcbcrConversionFeatures *features = (void *) ext;
11727ec681f3Smrg         features->samplerYcbcrConversion = vk11.samplerYcbcrConversion;
11737ec681f3Smrg         break;
11747ec681f3Smrg      }
11757ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: {
11767ec681f3Smrg         VkPhysicalDeviceShaderDrawParametersFeatures *features = (void *) ext;
11777ec681f3Smrg         features->shaderDrawParameters = vk11.shaderDrawParameters;
11787ec681f3Smrg         break;
11797ec681f3Smrg      }
11807ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: {
11817ec681f3Smrg         VkPhysicalDeviceVariablePointersFeatures *features = (void *) ext;
11827ec681f3Smrg         features->variablePointersStorageBuffer =
11837ec681f3Smrg            vk11.variablePointersStorageBuffer;
11847ec681f3Smrg         features->variablePointers = vk11.variablePointers;
11857ec681f3Smrg         break;
11867ec681f3Smrg      }
11877ec681f3Smrg
11887ec681f3Smrg      default:
11897ec681f3Smrg         v3dv_debug_ignored_stype(ext->sType);
11907ec681f3Smrg         break;
11917ec681f3Smrg      }
11927ec681f3Smrg   }
11937ec681f3Smrg}
11947ec681f3Smrg
11957ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
11967ec681f3Smrgv3dv_GetDeviceGroupPeerMemoryFeatures(VkDevice device,
11977ec681f3Smrg                                      uint32_t heapIndex,
11987ec681f3Smrg                                      uint32_t localDeviceIndex,
11997ec681f3Smrg                                      uint32_t remoteDeviceIndex,
12007ec681f3Smrg                                      VkPeerMemoryFeatureFlags *pPeerMemoryFeatures)
12017ec681f3Smrg{
12027ec681f3Smrg   assert(localDeviceIndex == 0 && remoteDeviceIndex == 0);
12037ec681f3Smrg   *pPeerMemoryFeatures = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT |
12047ec681f3Smrg                          VK_PEER_MEMORY_FEATURE_COPY_DST_BIT |
12057ec681f3Smrg                          VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT |
12067ec681f3Smrg                          VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT;
12077ec681f3Smrg}
12087ec681f3Smrg
12097ec681f3Smrguint32_t
12107ec681f3Smrgv3dv_physical_device_vendor_id(struct v3dv_physical_device *dev)
12117ec681f3Smrg{
12127ec681f3Smrg   return 0x14E4; /* Broadcom */
12137ec681f3Smrg}
12147ec681f3Smrg
12157ec681f3Smrg
12167ec681f3Smrg#if using_v3d_simulator
12177ec681f3Smrgstatic bool
12187ec681f3Smrgget_i915_param(int fd, uint32_t param, int *value)
12197ec681f3Smrg{
12207ec681f3Smrg   int tmp;
12217ec681f3Smrg
12227ec681f3Smrg   struct drm_i915_getparam gp = {
12237ec681f3Smrg      .param = param,
12247ec681f3Smrg      .value = &tmp,
12257ec681f3Smrg   };
12267ec681f3Smrg
12277ec681f3Smrg   int ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
12287ec681f3Smrg   if (ret != 0)
12297ec681f3Smrg      return false;
12307ec681f3Smrg
12317ec681f3Smrg   *value = tmp;
12327ec681f3Smrg   return true;
12337ec681f3Smrg}
12347ec681f3Smrg#endif
12357ec681f3Smrg
12367ec681f3Smrguint32_t
12377ec681f3Smrgv3dv_physical_device_device_id(struct v3dv_physical_device *dev)
12387ec681f3Smrg{
12397ec681f3Smrg#if using_v3d_simulator
12407ec681f3Smrg   int devid = 0;
12417ec681f3Smrg
12427ec681f3Smrg   if (!get_i915_param(dev->render_fd, I915_PARAM_CHIPSET_ID, &devid))
12437ec681f3Smrg      fprintf(stderr, "Error getting device_id\n");
12447ec681f3Smrg
12457ec681f3Smrg   return devid;
12467ec681f3Smrg#else
12477ec681f3Smrg   switch (dev->devinfo.ver) {
12487ec681f3Smrg   case 42:
12497ec681f3Smrg      return 0xBE485FD3; /* Broadcom deviceID for 2711 */
12507ec681f3Smrg   default:
12517ec681f3Smrg      unreachable("Unsupported V3D version");
12527ec681f3Smrg   }
12537ec681f3Smrg#endif
12547ec681f3Smrg}
12557ec681f3Smrg
12567ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
12577ec681f3Smrgv3dv_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
12587ec681f3Smrg                                 VkPhysicalDeviceProperties *pProperties)
12597ec681f3Smrg{
12607ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice);
12617ec681f3Smrg
12627ec681f3Smrg   STATIC_ASSERT(MAX_SAMPLED_IMAGES + MAX_STORAGE_IMAGES + MAX_INPUT_ATTACHMENTS
12637ec681f3Smrg                 <= V3D_MAX_TEXTURE_SAMPLERS);
12647ec681f3Smrg   STATIC_ASSERT(MAX_UNIFORM_BUFFERS >= MAX_DYNAMIC_UNIFORM_BUFFERS);
12657ec681f3Smrg   STATIC_ASSERT(MAX_STORAGE_BUFFERS >= MAX_DYNAMIC_STORAGE_BUFFERS);
12667ec681f3Smrg
12677ec681f3Smrg   const uint32_t page_size = 4096;
12687ec681f3Smrg   const uint32_t mem_size = compute_heap_size();
12697ec681f3Smrg
12707ec681f3Smrg   const uint32_t max_varying_components = 16 * 4;
12717ec681f3Smrg
12727ec681f3Smrg   const uint32_t v3d_coord_shift = 6;
12737ec681f3Smrg
12747ec681f3Smrg   const float v3d_point_line_granularity = 2.0f / (1 << v3d_coord_shift);
12757ec681f3Smrg   const uint32_t max_fb_size = 4096;
12767ec681f3Smrg
12777ec681f3Smrg   const VkSampleCountFlags supported_sample_counts =
12787ec681f3Smrg      VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
12797ec681f3Smrg
12807ec681f3Smrg   struct timespec clock_res;
12817ec681f3Smrg   clock_getres(CLOCK_MONOTONIC, &clock_res);
12827ec681f3Smrg   const float timestamp_period =
12837ec681f3Smrg      clock_res.tv_sec * 1000000000.0f + clock_res.tv_nsec;
12847ec681f3Smrg
12857ec681f3Smrg   /* FIXME: this will probably require an in-depth review */
12867ec681f3Smrg   VkPhysicalDeviceLimits limits = {
12877ec681f3Smrg      .maxImageDimension1D                      = 4096,
12887ec681f3Smrg      .maxImageDimension2D                      = 4096,
12897ec681f3Smrg      .maxImageDimension3D                      = 4096,
12907ec681f3Smrg      .maxImageDimensionCube                    = 4096,
12917ec681f3Smrg      .maxImageArrayLayers                      = 2048,
12927ec681f3Smrg      .maxTexelBufferElements                   = (1ul << 28),
12937ec681f3Smrg      .maxUniformBufferRange                    = V3D_MAX_BUFFER_RANGE,
12947ec681f3Smrg      .maxStorageBufferRange                    = V3D_MAX_BUFFER_RANGE,
12957ec681f3Smrg      .maxPushConstantsSize                     = MAX_PUSH_CONSTANTS_SIZE,
12967ec681f3Smrg      .maxMemoryAllocationCount                 = mem_size / page_size,
12977ec681f3Smrg      .maxSamplerAllocationCount                = 64 * 1024,
12987ec681f3Smrg      .bufferImageGranularity                   = 256, /* A cache line */
12997ec681f3Smrg      .sparseAddressSpaceSize                   = 0,
13007ec681f3Smrg      .maxBoundDescriptorSets                   = MAX_SETS,
13017ec681f3Smrg      .maxPerStageDescriptorSamplers            = V3D_MAX_TEXTURE_SAMPLERS,
13027ec681f3Smrg      .maxPerStageDescriptorUniformBuffers      = MAX_UNIFORM_BUFFERS,
13037ec681f3Smrg      .maxPerStageDescriptorStorageBuffers      = MAX_STORAGE_BUFFERS,
13047ec681f3Smrg      .maxPerStageDescriptorSampledImages       = MAX_SAMPLED_IMAGES,
13057ec681f3Smrg      .maxPerStageDescriptorStorageImages       = MAX_STORAGE_IMAGES,
13067ec681f3Smrg      .maxPerStageDescriptorInputAttachments    = MAX_INPUT_ATTACHMENTS,
13077ec681f3Smrg      .maxPerStageResources                     = 128,
13087ec681f3Smrg
13097ec681f3Smrg      /* Some of these limits are multiplied by 6 because they need to
13107ec681f3Smrg       * include all possible shader stages (even if not supported). See
13117ec681f3Smrg       * 'Required Limits' table in the Vulkan spec.
13127ec681f3Smrg       */
13137ec681f3Smrg      .maxDescriptorSetSamplers                 = 6 * V3D_MAX_TEXTURE_SAMPLERS,
13147ec681f3Smrg      .maxDescriptorSetUniformBuffers           = 6 * MAX_UNIFORM_BUFFERS,
13157ec681f3Smrg      .maxDescriptorSetUniformBuffersDynamic    = MAX_DYNAMIC_UNIFORM_BUFFERS,
13167ec681f3Smrg      .maxDescriptorSetStorageBuffers           = 6 * MAX_STORAGE_BUFFERS,
13177ec681f3Smrg      .maxDescriptorSetStorageBuffersDynamic    = MAX_DYNAMIC_STORAGE_BUFFERS,
13187ec681f3Smrg      .maxDescriptorSetSampledImages            = 6 * MAX_SAMPLED_IMAGES,
13197ec681f3Smrg      .maxDescriptorSetStorageImages            = 6 * MAX_STORAGE_IMAGES,
13207ec681f3Smrg      .maxDescriptorSetInputAttachments         = MAX_INPUT_ATTACHMENTS,
13217ec681f3Smrg
13227ec681f3Smrg      /* Vertex limits */
13237ec681f3Smrg      .maxVertexInputAttributes                 = MAX_VERTEX_ATTRIBS,
13247ec681f3Smrg      .maxVertexInputBindings                   = MAX_VBS,
13257ec681f3Smrg      .maxVertexInputAttributeOffset            = 0xffffffff,
13267ec681f3Smrg      .maxVertexInputBindingStride              = 0xffffffff,
13277ec681f3Smrg      .maxVertexOutputComponents                = max_varying_components,
13287ec681f3Smrg
13297ec681f3Smrg      /* Tessellation limits */
13307ec681f3Smrg      .maxTessellationGenerationLevel           = 0,
13317ec681f3Smrg      .maxTessellationPatchSize                 = 0,
13327ec681f3Smrg      .maxTessellationControlPerVertexInputComponents = 0,
13337ec681f3Smrg      .maxTessellationControlPerVertexOutputComponents = 0,
13347ec681f3Smrg      .maxTessellationControlPerPatchOutputComponents = 0,
13357ec681f3Smrg      .maxTessellationControlTotalOutputComponents = 0,
13367ec681f3Smrg      .maxTessellationEvaluationInputComponents = 0,
13377ec681f3Smrg      .maxTessellationEvaluationOutputComponents = 0,
13387ec681f3Smrg
13397ec681f3Smrg      /* Geometry limits */
13407ec681f3Smrg      .maxGeometryShaderInvocations             = 32,
13417ec681f3Smrg      .maxGeometryInputComponents               = 64,
13427ec681f3Smrg      .maxGeometryOutputComponents              = 64,
13437ec681f3Smrg      .maxGeometryOutputVertices                = 256,
13447ec681f3Smrg      .maxGeometryTotalOutputComponents         = 1024,
13457ec681f3Smrg
13467ec681f3Smrg      /* Fragment limits */
13477ec681f3Smrg      .maxFragmentInputComponents               = max_varying_components,
13487ec681f3Smrg      .maxFragmentOutputAttachments             = 4,
13497ec681f3Smrg      .maxFragmentDualSrcAttachments            = 0,
13507ec681f3Smrg      .maxFragmentCombinedOutputResources       = MAX_RENDER_TARGETS +
13517ec681f3Smrg                                                  MAX_STORAGE_BUFFERS +
13527ec681f3Smrg                                                  MAX_STORAGE_IMAGES,
13537ec681f3Smrg
13547ec681f3Smrg      /* Compute limits */
13557ec681f3Smrg      .maxComputeSharedMemorySize               = 16384,
13567ec681f3Smrg      .maxComputeWorkGroupCount                 = { 65535, 65535, 65535 },
13577ec681f3Smrg      .maxComputeWorkGroupInvocations           = 256,
13587ec681f3Smrg      .maxComputeWorkGroupSize                  = { 256, 256, 256 },
13597ec681f3Smrg
13607ec681f3Smrg      .subPixelPrecisionBits                    = v3d_coord_shift,
13617ec681f3Smrg      .subTexelPrecisionBits                    = 8,
13627ec681f3Smrg      .mipmapPrecisionBits                      = 8,
13637ec681f3Smrg      .maxDrawIndexedIndexValue                 = 0x00ffffff,
13647ec681f3Smrg      .maxDrawIndirectCount                     = 0x7fffffff,
13657ec681f3Smrg      .maxSamplerLodBias                        = 14.0f,
13667ec681f3Smrg      .maxSamplerAnisotropy                     = 16.0f,
13677ec681f3Smrg      .maxViewports                             = MAX_VIEWPORTS,
13687ec681f3Smrg      .maxViewportDimensions                    = { max_fb_size, max_fb_size },
13697ec681f3Smrg      .viewportBoundsRange                      = { -2.0 * max_fb_size,
13707ec681f3Smrg                                                    2.0 * max_fb_size - 1 },
13717ec681f3Smrg      .viewportSubPixelBits                     = 0,
13727ec681f3Smrg      .minMemoryMapAlignment                    = page_size,
13737ec681f3Smrg      .minTexelBufferOffsetAlignment            = V3D_UIFBLOCK_SIZE,
13747ec681f3Smrg      .minUniformBufferOffsetAlignment          = 32,
13757ec681f3Smrg      .minStorageBufferOffsetAlignment          = 32,
13767ec681f3Smrg      .minTexelOffset                           = -8,
13777ec681f3Smrg      .maxTexelOffset                           = 7,
13787ec681f3Smrg      .minTexelGatherOffset                     = -8,
13797ec681f3Smrg      .maxTexelGatherOffset                     = 7,
13807ec681f3Smrg      .minInterpolationOffset                   = -0.5,
13817ec681f3Smrg      .maxInterpolationOffset                   = 0.5,
13827ec681f3Smrg      .subPixelInterpolationOffsetBits          = v3d_coord_shift,
13837ec681f3Smrg      .maxFramebufferWidth                      = max_fb_size,
13847ec681f3Smrg      .maxFramebufferHeight                     = max_fb_size,
13857ec681f3Smrg      .maxFramebufferLayers                     = 256,
13867ec681f3Smrg      .framebufferColorSampleCounts             = supported_sample_counts,
13877ec681f3Smrg      .framebufferDepthSampleCounts             = supported_sample_counts,
13887ec681f3Smrg      .framebufferStencilSampleCounts           = supported_sample_counts,
13897ec681f3Smrg      .framebufferNoAttachmentsSampleCounts     = supported_sample_counts,
13907ec681f3Smrg      .maxColorAttachments                      = MAX_RENDER_TARGETS,
13917ec681f3Smrg      .sampledImageColorSampleCounts            = supported_sample_counts,
13927ec681f3Smrg      .sampledImageIntegerSampleCounts          = supported_sample_counts,
13937ec681f3Smrg      .sampledImageDepthSampleCounts            = supported_sample_counts,
13947ec681f3Smrg      .sampledImageStencilSampleCounts          = supported_sample_counts,
13957ec681f3Smrg      .storageImageSampleCounts                 = VK_SAMPLE_COUNT_1_BIT,
13967ec681f3Smrg      .maxSampleMaskWords                       = 1,
13977ec681f3Smrg      .timestampComputeAndGraphics              = true,
13987ec681f3Smrg      .timestampPeriod                          = timestamp_period,
13997ec681f3Smrg      .maxClipDistances                         = 8,
14007ec681f3Smrg      .maxCullDistances                         = 0,
14017ec681f3Smrg      .maxCombinedClipAndCullDistances          = 8,
14027ec681f3Smrg      .discreteQueuePriorities                  = 2,
14037ec681f3Smrg      .pointSizeRange                           = { v3d_point_line_granularity,
14047ec681f3Smrg                                                    V3D_MAX_POINT_SIZE },
14057ec681f3Smrg      .lineWidthRange                           = { 1.0f, V3D_MAX_LINE_WIDTH },
14067ec681f3Smrg      .pointSizeGranularity                     = v3d_point_line_granularity,
14077ec681f3Smrg      .lineWidthGranularity                     = v3d_point_line_granularity,
14087ec681f3Smrg      .strictLines                              = true,
14097ec681f3Smrg      .standardSampleLocations                  = false,
14107ec681f3Smrg      .optimalBufferCopyOffsetAlignment         = 32,
14117ec681f3Smrg      .optimalBufferCopyRowPitchAlignment       = 32,
14127ec681f3Smrg      .nonCoherentAtomSize                      = 256,
14137ec681f3Smrg   };
14147ec681f3Smrg
14157ec681f3Smrg   *pProperties = (VkPhysicalDeviceProperties) {
14167ec681f3Smrg      .apiVersion = V3DV_API_VERSION,
14177ec681f3Smrg      .driverVersion = vk_get_driver_version(),
14187ec681f3Smrg      .vendorID = v3dv_physical_device_vendor_id(pdevice),
14197ec681f3Smrg      .deviceID = v3dv_physical_device_device_id(pdevice),
14207ec681f3Smrg      .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU,
14217ec681f3Smrg      .limits = limits,
14227ec681f3Smrg      .sparseProperties = { 0 },
14237ec681f3Smrg   };
14247ec681f3Smrg
14257ec681f3Smrg   snprintf(pProperties->deviceName, sizeof(pProperties->deviceName),
14267ec681f3Smrg            "%s", pdevice->name);
14277ec681f3Smrg   memcpy(pProperties->pipelineCacheUUID,
14287ec681f3Smrg          pdevice->pipeline_cache_uuid, VK_UUID_SIZE);
14297ec681f3Smrg}
14307ec681f3Smrg
14317ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
14327ec681f3Smrgv3dv_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
14337ec681f3Smrg                                  VkPhysicalDeviceProperties2 *pProperties)
14347ec681f3Smrg{
14357ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_physical_device, pdevice, physicalDevice);
14367ec681f3Smrg
14377ec681f3Smrg   v3dv_GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties);
14387ec681f3Smrg
14397ec681f3Smrg   vk_foreach_struct(ext, pProperties->pNext) {
14407ec681f3Smrg      switch (ext->sType) {
14417ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT: {
14427ec681f3Smrg         VkPhysicalDeviceCustomBorderColorPropertiesEXT *props =
14437ec681f3Smrg            (VkPhysicalDeviceCustomBorderColorPropertiesEXT *)ext;
14447ec681f3Smrg         props->maxCustomBorderColorSamplers = V3D_MAX_TEXTURE_SAMPLERS;
14457ec681f3Smrg         break;
14467ec681f3Smrg      }
14477ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT: {
14487ec681f3Smrg         VkPhysicalDeviceProvokingVertexPropertiesEXT *props =
14497ec681f3Smrg            (VkPhysicalDeviceProvokingVertexPropertiesEXT *)ext;
14507ec681f3Smrg         props->provokingVertexModePerPipeline = true;
14517ec681f3Smrg         /* FIXME: update when supporting EXT_transform_feedback */
14527ec681f3Smrg         props->transformFeedbackPreservesTriangleFanProvokingVertex = false;
14537ec681f3Smrg         break;
14547ec681f3Smrg      }
14557ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
14567ec681f3Smrg         VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *props =
14577ec681f3Smrg            (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)ext;
14587ec681f3Smrg         props->maxVertexAttribDivisor = 0xffff;
14597ec681f3Smrg         break;
14607ec681f3Smrg      }
14617ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {
14627ec681f3Smrg         VkPhysicalDeviceIDProperties *id_props =
14637ec681f3Smrg            (VkPhysicalDeviceIDProperties *)ext;
14647ec681f3Smrg         memcpy(id_props->deviceUUID, pdevice->device_uuid, VK_UUID_SIZE);
14657ec681f3Smrg         memcpy(id_props->driverUUID, pdevice->driver_uuid, VK_UUID_SIZE);
14667ec681f3Smrg         /* The LUID is for Windows. */
14677ec681f3Smrg         id_props->deviceLUIDValid = false;
14687ec681f3Smrg         break;
14697ec681f3Smrg      }
14707ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT: {
14717ec681f3Smrg         VkPhysicalDeviceDrmPropertiesEXT *props =
14727ec681f3Smrg            (VkPhysicalDeviceDrmPropertiesEXT *)ext;
14737ec681f3Smrg         props->hasPrimary = pdevice->has_primary;
14747ec681f3Smrg         if (props->hasPrimary) {
14757ec681f3Smrg            props->primaryMajor = (int64_t) major(pdevice->primary_devid);
14767ec681f3Smrg            props->primaryMinor = (int64_t) minor(pdevice->primary_devid);
14777ec681f3Smrg         }
14787ec681f3Smrg         props->hasRender = pdevice->has_render;
14797ec681f3Smrg         if (props->hasRender) {
14807ec681f3Smrg            props->renderMajor = (int64_t) major(pdevice->render_devid);
14817ec681f3Smrg            props->renderMinor = (int64_t) minor(pdevice->render_devid);
14827ec681f3Smrg         }
14837ec681f3Smrg         break;
14847ec681f3Smrg      }
14857ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: {
14867ec681f3Smrg         VkPhysicalDeviceMaintenance3Properties *props =
14877ec681f3Smrg            (VkPhysicalDeviceMaintenance3Properties *)ext;
14887ec681f3Smrg         /* We don't really have special restrictions for the maximum
14897ec681f3Smrg          * descriptors per set, other than maybe not exceeding the limits
14907ec681f3Smrg          * of addressable memory in a single allocation on either the host
14917ec681f3Smrg          * or the GPU. This will be a much larger limit than any of the
14927ec681f3Smrg          * per-stage limits already available in Vulkan though, so in practice,
14937ec681f3Smrg          * it is not expected to limit anything beyond what is already
14947ec681f3Smrg          * constrained through per-stage limits.
14957ec681f3Smrg          */
14967ec681f3Smrg         uint32_t max_host_descriptors =
14977ec681f3Smrg            (UINT32_MAX - sizeof(struct v3dv_descriptor_set)) /
14987ec681f3Smrg            sizeof(struct v3dv_descriptor);
14997ec681f3Smrg         uint32_t max_gpu_descriptors =
15007ec681f3Smrg            (UINT32_MAX / v3dv_X(pdevice, max_descriptor_bo_size)());
15017ec681f3Smrg         props->maxPerSetDescriptors =
15027ec681f3Smrg            MIN2(max_host_descriptors, max_gpu_descriptors);
15037ec681f3Smrg
15047ec681f3Smrg         /* Minimum required by the spec */
15057ec681f3Smrg         props->maxMemoryAllocationSize = MAX_MEMORY_ALLOCATION_SIZE;
15067ec681f3Smrg         break;
15077ec681f3Smrg      }
15087ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES: {
15097ec681f3Smrg         VkPhysicalDeviceMultiviewProperties *props =
15107ec681f3Smrg            (VkPhysicalDeviceMultiviewProperties *)ext;
15117ec681f3Smrg         props->maxMultiviewViewCount = MAX_MULTIVIEW_VIEW_COUNT;
15127ec681f3Smrg         props->maxMultiviewInstanceIndex = UINT32_MAX - 1;
15137ec681f3Smrg         break;
15147ec681f3Smrg      }
15157ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT:
15167ec681f3Smrg         /* Do nothing, not even logging. This is a non-PCI device, so we will
15177ec681f3Smrg          * never provide this extension.
15187ec681f3Smrg          */
15197ec681f3Smrg         break;
15207ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: {
15217ec681f3Smrg         VkPhysicalDevicePointClippingProperties *props =
15227ec681f3Smrg            (VkPhysicalDevicePointClippingProperties *)ext;
15237ec681f3Smrg         props->pointClippingBehavior =
15247ec681f3Smrg            VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES;
15257ec681f3Smrg         break;
15267ec681f3Smrg      }
15277ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES: {
15287ec681f3Smrg         VkPhysicalDeviceProtectedMemoryProperties *props =
15297ec681f3Smrg            (VkPhysicalDeviceProtectedMemoryProperties *)ext;
15307ec681f3Smrg         props->protectedNoFault = false;
15317ec681f3Smrg         break;
15327ec681f3Smrg      }
15337ec681f3Smrg      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES: {
15347ec681f3Smrg         VkPhysicalDeviceSubgroupProperties *props =
15357ec681f3Smrg            (VkPhysicalDeviceSubgroupProperties *)ext;
15367ec681f3Smrg         props->subgroupSize = V3D_CHANNELS;
15377ec681f3Smrg         props->supportedStages = VK_SHADER_STAGE_COMPUTE_BIT;
15387ec681f3Smrg         props->supportedOperations = VK_SUBGROUP_FEATURE_BASIC_BIT;
15397ec681f3Smrg         props->quadOperationsInAllStages = false;
15407ec681f3Smrg         break;
15417ec681f3Smrg      }
15427ec681f3Smrg      default:
15437ec681f3Smrg         v3dv_debug_ignored_stype(ext->sType);
15447ec681f3Smrg         break;
15457ec681f3Smrg      }
15467ec681f3Smrg   }
15477ec681f3Smrg}
15487ec681f3Smrg
15497ec681f3Smrg/* We support exactly one queue family. */
15507ec681f3Smrgstatic const VkQueueFamilyProperties
15517ec681f3Smrgv3dv_queue_family_properties = {
15527ec681f3Smrg   .queueFlags = VK_QUEUE_GRAPHICS_BIT |
15537ec681f3Smrg                 VK_QUEUE_COMPUTE_BIT |
15547ec681f3Smrg                 VK_QUEUE_TRANSFER_BIT,
15557ec681f3Smrg   .queueCount = 1,
15567ec681f3Smrg   .timestampValidBits = 64,
15577ec681f3Smrg   .minImageTransferGranularity = { 1, 1, 1 },
15587ec681f3Smrg};
15597ec681f3Smrg
15607ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
15617ec681f3Smrgv3dv_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
15627ec681f3Smrg                                            uint32_t *pCount,
15637ec681f3Smrg                                            VkQueueFamilyProperties *pQueueFamilyProperties)
15647ec681f3Smrg{
15657ec681f3Smrg   VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pCount);
15667ec681f3Smrg
15677ec681f3Smrg   vk_outarray_append(&out, p) {
15687ec681f3Smrg      *p = v3dv_queue_family_properties;
15697ec681f3Smrg   }
15707ec681f3Smrg}
15717ec681f3Smrg
15727ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
15737ec681f3Smrgv3dv_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
15747ec681f3Smrg                                             uint32_t *pQueueFamilyPropertyCount,
15757ec681f3Smrg                                             VkQueueFamilyProperties2 *pQueueFamilyProperties)
15767ec681f3Smrg{
15777ec681f3Smrg   VK_OUTARRAY_MAKE(out, pQueueFamilyProperties, pQueueFamilyPropertyCount);
15787ec681f3Smrg
15797ec681f3Smrg   vk_outarray_append(&out, p) {
15807ec681f3Smrg      p->queueFamilyProperties = v3dv_queue_family_properties;
15817ec681f3Smrg
15827ec681f3Smrg      vk_foreach_struct(s, p->pNext) {
15837ec681f3Smrg         v3dv_debug_ignored_stype(s->sType);
15847ec681f3Smrg      }
15857ec681f3Smrg   }
15867ec681f3Smrg}
15877ec681f3Smrg
15887ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
15897ec681f3Smrgv3dv_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
15907ec681f3Smrg                                       VkPhysicalDeviceMemoryProperties *pMemoryProperties)
15917ec681f3Smrg{
15927ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_physical_device, device, physicalDevice);
15937ec681f3Smrg   *pMemoryProperties = device->memory;
15947ec681f3Smrg}
15957ec681f3Smrg
15967ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
15977ec681f3Smrgv3dv_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,
15987ec681f3Smrg                                        VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
15997ec681f3Smrg{
16007ec681f3Smrg   v3dv_GetPhysicalDeviceMemoryProperties(physicalDevice,
16017ec681f3Smrg                                          &pMemoryProperties->memoryProperties);
16027ec681f3Smrg
16037ec681f3Smrg   vk_foreach_struct(ext, pMemoryProperties->pNext) {
16047ec681f3Smrg      switch (ext->sType) {
16057ec681f3Smrg      default:
16067ec681f3Smrg         v3dv_debug_ignored_stype(ext->sType);
16077ec681f3Smrg         break;
16087ec681f3Smrg      }
16097ec681f3Smrg   }
16107ec681f3Smrg}
16117ec681f3Smrg
16127ec681f3SmrgVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
16137ec681f3Smrgv3dv_GetInstanceProcAddr(VkInstance _instance,
16147ec681f3Smrg                         const char *pName)
16157ec681f3Smrg{
16167ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
16177ec681f3Smrg   return vk_instance_get_proc_addr(&instance->vk,
16187ec681f3Smrg                                    &v3dv_instance_entrypoints,
16197ec681f3Smrg                                    pName);
16207ec681f3Smrg}
16217ec681f3Smrg
16227ec681f3Smrg/* With version 1+ of the loader interface the ICD should expose
16237ec681f3Smrg * vk_icdGetInstanceProcAddr to work around certain LD_PRELOAD issues seen in apps.
16247ec681f3Smrg */
16257ec681f3SmrgPUBLIC
16267ec681f3SmrgVKAPI_ATTR PFN_vkVoidFunction
16277ec681f3SmrgVKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance,
16287ec681f3Smrg                                     const char *pName);
16297ec681f3Smrg
16307ec681f3SmrgPUBLIC
16317ec681f3SmrgVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
16327ec681f3Smrgvk_icdGetInstanceProcAddr(VkInstance instance,
16337ec681f3Smrg                          const char*                                 pName)
16347ec681f3Smrg{
16357ec681f3Smrg   return v3dv_GetInstanceProcAddr(instance, pName);
16367ec681f3Smrg}
16377ec681f3Smrg
16387ec681f3Smrg/* With version 4+ of the loader interface the ICD should expose
16397ec681f3Smrg * vk_icdGetPhysicalDeviceProcAddr()
16407ec681f3Smrg */
16417ec681f3SmrgPUBLIC
16427ec681f3SmrgVKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
16437ec681f3Smrgvk_icdGetPhysicalDeviceProcAddr(VkInstance  _instance,
16447ec681f3Smrg                                const char* pName);
16457ec681f3Smrg
16467ec681f3SmrgPFN_vkVoidFunction
16477ec681f3Smrgvk_icdGetPhysicalDeviceProcAddr(VkInstance  _instance,
16487ec681f3Smrg                                const char* pName)
16497ec681f3Smrg{
16507ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_instance, instance, _instance);
16517ec681f3Smrg
16527ec681f3Smrg   return vk_instance_get_physical_device_proc_addr(&instance->vk, pName);
16537ec681f3Smrg}
16547ec681f3Smrg
16557ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
16567ec681f3Smrgv3dv_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
16577ec681f3Smrg                                      VkLayerProperties *pProperties)
16587ec681f3Smrg{
16597ec681f3Smrg   if (pProperties == NULL) {
16607ec681f3Smrg      *pPropertyCount = 0;
16617ec681f3Smrg      return VK_SUCCESS;
16627ec681f3Smrg   }
16637ec681f3Smrg
16647ec681f3Smrg   return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
16657ec681f3Smrg}
16667ec681f3Smrg
16677ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
16687ec681f3Smrgv3dv_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,
16697ec681f3Smrg                                    uint32_t *pPropertyCount,
16707ec681f3Smrg                                    VkLayerProperties *pProperties)
16717ec681f3Smrg{
16727ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice);
16737ec681f3Smrg
16747ec681f3Smrg   if (pProperties == NULL) {
16757ec681f3Smrg      *pPropertyCount = 0;
16767ec681f3Smrg      return VK_SUCCESS;
16777ec681f3Smrg   }
16787ec681f3Smrg
16797ec681f3Smrg   return vk_error(physical_device, VK_ERROR_LAYER_NOT_PRESENT);
16807ec681f3Smrg}
16817ec681f3Smrg
16827ec681f3Smrgstatic VkResult
16837ec681f3Smrgqueue_init(struct v3dv_device *device, struct v3dv_queue *queue,
16847ec681f3Smrg           const VkDeviceQueueCreateInfo *create_info,
16857ec681f3Smrg           uint32_t index_in_family)
16867ec681f3Smrg{
16877ec681f3Smrg   VkResult result = vk_queue_init(&queue->vk, &device->vk, create_info,
16887ec681f3Smrg                                   index_in_family);
16897ec681f3Smrg   if (result != VK_SUCCESS)
16907ec681f3Smrg      return result;
16917ec681f3Smrg   queue->device = device;
16927ec681f3Smrg   queue->noop_job = NULL;
16937ec681f3Smrg   list_inithead(&queue->submit_wait_list);
16947ec681f3Smrg   pthread_mutex_init(&queue->mutex, NULL);
16957ec681f3Smrg   return VK_SUCCESS;
16967ec681f3Smrg}
16977ec681f3Smrg
16987ec681f3Smrgstatic void
16997ec681f3Smrgqueue_finish(struct v3dv_queue *queue)
17007ec681f3Smrg{
17017ec681f3Smrg   vk_queue_finish(&queue->vk);
17027ec681f3Smrg   assert(list_is_empty(&queue->submit_wait_list));
17037ec681f3Smrg   if (queue->noop_job)
17047ec681f3Smrg      v3dv_job_destroy(queue->noop_job);
17057ec681f3Smrg   pthread_mutex_destroy(&queue->mutex);
17067ec681f3Smrg}
17077ec681f3Smrg
17087ec681f3Smrgstatic void
17097ec681f3Smrginit_device_meta(struct v3dv_device *device)
17107ec681f3Smrg{
17117ec681f3Smrg   mtx_init(&device->meta.mtx, mtx_plain);
17127ec681f3Smrg   v3dv_meta_clear_init(device);
17137ec681f3Smrg   v3dv_meta_blit_init(device);
17147ec681f3Smrg   v3dv_meta_texel_buffer_copy_init(device);
17157ec681f3Smrg}
17167ec681f3Smrg
17177ec681f3Smrgstatic void
17187ec681f3Smrgdestroy_device_meta(struct v3dv_device *device)
17197ec681f3Smrg{
17207ec681f3Smrg   mtx_destroy(&device->meta.mtx);
17217ec681f3Smrg   v3dv_meta_clear_finish(device);
17227ec681f3Smrg   v3dv_meta_blit_finish(device);
17237ec681f3Smrg   v3dv_meta_texel_buffer_copy_finish(device);
17247ec681f3Smrg}
17257ec681f3Smrg
17267ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
17277ec681f3Smrgv3dv_CreateDevice(VkPhysicalDevice physicalDevice,
17287ec681f3Smrg                  const VkDeviceCreateInfo *pCreateInfo,
17297ec681f3Smrg                  const VkAllocationCallbacks *pAllocator,
17307ec681f3Smrg                  VkDevice *pDevice)
17317ec681f3Smrg{
17327ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_physical_device, physical_device, physicalDevice);
17337ec681f3Smrg   struct v3dv_instance *instance = (struct v3dv_instance*) physical_device->vk.instance;
17347ec681f3Smrg   VkResult result;
17357ec681f3Smrg   struct v3dv_device *device;
17367ec681f3Smrg
17377ec681f3Smrg   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);
17387ec681f3Smrg
17397ec681f3Smrg   /* Check requested queues (we only expose one queue ) */
17407ec681f3Smrg   assert(pCreateInfo->queueCreateInfoCount == 1);
17417ec681f3Smrg   for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
17427ec681f3Smrg      assert(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex == 0);
17437ec681f3Smrg      assert(pCreateInfo->pQueueCreateInfos[i].queueCount == 1);
17447ec681f3Smrg      if (pCreateInfo->pQueueCreateInfos[i].flags != 0)
17457ec681f3Smrg         return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);
17467ec681f3Smrg   }
17477ec681f3Smrg
17487ec681f3Smrg   device = vk_zalloc2(&physical_device->vk.instance->alloc, pAllocator,
17497ec681f3Smrg                       sizeof(*device), 8,
17507ec681f3Smrg                       VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
17517ec681f3Smrg   if (!device)
17527ec681f3Smrg      return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
17537ec681f3Smrg
17547ec681f3Smrg   struct vk_device_dispatch_table dispatch_table;
17557ec681f3Smrg   vk_device_dispatch_table_from_entrypoints(&dispatch_table,
17567ec681f3Smrg                                             &v3dv_device_entrypoints, true);
17577ec681f3Smrg   vk_device_dispatch_table_from_entrypoints(&dispatch_table,
17587ec681f3Smrg                                             &wsi_device_entrypoints, false);
17597ec681f3Smrg   result = vk_device_init(&device->vk, &physical_device->vk,
17607ec681f3Smrg                           &dispatch_table, pCreateInfo, pAllocator);
17617ec681f3Smrg   if (result != VK_SUCCESS) {
17627ec681f3Smrg      vk_free(&device->vk.alloc, device);
17637ec681f3Smrg      return vk_error(NULL, result);
17647ec681f3Smrg   }
17657ec681f3Smrg
17667ec681f3Smrg   device->instance = instance;
17677ec681f3Smrg   device->pdevice = physical_device;
17687ec681f3Smrg
17697ec681f3Smrg   if (pAllocator)
17707ec681f3Smrg      device->vk.alloc = *pAllocator;
17717ec681f3Smrg   else
17727ec681f3Smrg      device->vk.alloc = physical_device->vk.instance->alloc;
17737ec681f3Smrg
17747ec681f3Smrg   pthread_mutex_init(&device->mutex, NULL);
17757ec681f3Smrg
17767ec681f3Smrg   result = queue_init(device, &device->queue,
17777ec681f3Smrg                       pCreateInfo->pQueueCreateInfos, 0);
17787ec681f3Smrg   if (result != VK_SUCCESS)
17797ec681f3Smrg      goto fail;
17807ec681f3Smrg
17817ec681f3Smrg   device->devinfo = physical_device->devinfo;
17827ec681f3Smrg
17837ec681f3Smrg   /* Vulkan 1.1 and VK_KHR_get_physical_device_properties2 added
17847ec681f3Smrg    * VkPhysicalDeviceFeatures2 which can be used in the pNext chain of
17857ec681f3Smrg    * vkDeviceCreateInfo, in which case it should be used instead of
17867ec681f3Smrg    * pEnabledFeatures.
17877ec681f3Smrg    */
17887ec681f3Smrg   const VkPhysicalDeviceFeatures2 *features2 =
17897ec681f3Smrg      vk_find_struct_const(pCreateInfo->pNext, PHYSICAL_DEVICE_FEATURES_2);
17907ec681f3Smrg   if (features2) {
17917ec681f3Smrg      memcpy(&device->features, &features2->features,
17927ec681f3Smrg             sizeof(device->features));
17937ec681f3Smrg   } else  if (pCreateInfo->pEnabledFeatures) {
17947ec681f3Smrg      memcpy(&device->features, pCreateInfo->pEnabledFeatures,
17957ec681f3Smrg             sizeof(device->features));
17967ec681f3Smrg   }
17977ec681f3Smrg
17987ec681f3Smrg   if (device->features.robustBufferAccess)
17997ec681f3Smrg      perf_debug("Device created with Robust Buffer Access enabled.\n");
18007ec681f3Smrg
18017ec681f3Smrg   int ret = drmSyncobjCreate(physical_device->render_fd,
18027ec681f3Smrg                              DRM_SYNCOBJ_CREATE_SIGNALED,
18037ec681f3Smrg                              &device->last_job_sync);
18047ec681f3Smrg   if (ret) {
18057ec681f3Smrg      result = VK_ERROR_INITIALIZATION_FAILED;
18067ec681f3Smrg      goto fail;
18077ec681f3Smrg   }
18087ec681f3Smrg
18097ec681f3Smrg#ifdef DEBUG
18107ec681f3Smrg   v3dv_X(device, device_check_prepacked_sizes)();
18117ec681f3Smrg#endif
18127ec681f3Smrg   init_device_meta(device);
18137ec681f3Smrg   v3dv_bo_cache_init(device);
18147ec681f3Smrg   v3dv_pipeline_cache_init(&device->default_pipeline_cache, device, 0,
18157ec681f3Smrg                            device->instance->default_pipeline_cache_enabled);
18167ec681f3Smrg   device->default_attribute_float =
18177ec681f3Smrg      v3dv_pipeline_create_default_attribute_values(device, NULL);
18187ec681f3Smrg
18197ec681f3Smrg   *pDevice = v3dv_device_to_handle(device);
18207ec681f3Smrg
18217ec681f3Smrg   return VK_SUCCESS;
18227ec681f3Smrg
18237ec681f3Smrgfail:
18247ec681f3Smrg   vk_device_finish(&device->vk);
18257ec681f3Smrg   vk_free(&device->vk.alloc, device);
18267ec681f3Smrg
18277ec681f3Smrg   return result;
18287ec681f3Smrg}
18297ec681f3Smrg
18307ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
18317ec681f3Smrgv3dv_DestroyDevice(VkDevice _device,
18327ec681f3Smrg                   const VkAllocationCallbacks *pAllocator)
18337ec681f3Smrg{
18347ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
18357ec681f3Smrg
18367ec681f3Smrg   v3dv_DeviceWaitIdle(_device);
18377ec681f3Smrg   queue_finish(&device->queue);
18387ec681f3Smrg   pthread_mutex_destroy(&device->mutex);
18397ec681f3Smrg   drmSyncobjDestroy(device->pdevice->render_fd, device->last_job_sync);
18407ec681f3Smrg   destroy_device_meta(device);
18417ec681f3Smrg   v3dv_pipeline_cache_finish(&device->default_pipeline_cache);
18427ec681f3Smrg
18437ec681f3Smrg   if (device->default_attribute_float) {
18447ec681f3Smrg      v3dv_bo_free(device, device->default_attribute_float);
18457ec681f3Smrg      device->default_attribute_float = NULL;
18467ec681f3Smrg   }
18477ec681f3Smrg
18487ec681f3Smrg   /* Bo cache should be removed the last, as any other object could be
18497ec681f3Smrg    * freeing their private bos
18507ec681f3Smrg    */
18517ec681f3Smrg   v3dv_bo_cache_destroy(device);
18527ec681f3Smrg
18537ec681f3Smrg   vk_device_finish(&device->vk);
18547ec681f3Smrg   vk_free2(&device->vk.alloc, pAllocator, device);
18557ec681f3Smrg}
18567ec681f3Smrg
18577ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
18587ec681f3Smrgv3dv_DeviceWaitIdle(VkDevice _device)
18597ec681f3Smrg{
18607ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
18617ec681f3Smrg   return v3dv_QueueWaitIdle(v3dv_queue_to_handle(&device->queue));
18627ec681f3Smrg}
18637ec681f3Smrg
18647ec681f3Smrgstatic VkResult
18657ec681f3Smrgdevice_alloc(struct v3dv_device *device,
18667ec681f3Smrg             struct v3dv_device_memory *mem,
18677ec681f3Smrg             VkDeviceSize size)
18687ec681f3Smrg{
18697ec681f3Smrg   /* Our kernel interface is 32-bit */
18707ec681f3Smrg   assert(size <= UINT32_MAX);
18717ec681f3Smrg
18727ec681f3Smrg   mem->bo = v3dv_bo_alloc(device, size, "device_alloc", false);
18737ec681f3Smrg   if (!mem->bo)
18747ec681f3Smrg      return VK_ERROR_OUT_OF_DEVICE_MEMORY;
18757ec681f3Smrg
18767ec681f3Smrg   return VK_SUCCESS;
18777ec681f3Smrg}
18787ec681f3Smrg
18797ec681f3Smrgstatic void
18807ec681f3Smrgdevice_free_wsi_dumb(int32_t display_fd, int32_t dumb_handle)
18817ec681f3Smrg{
18827ec681f3Smrg   assert(display_fd != -1);
18837ec681f3Smrg   if (dumb_handle < 0)
18847ec681f3Smrg      return;
18857ec681f3Smrg
18867ec681f3Smrg   struct drm_mode_destroy_dumb destroy_dumb = {
18877ec681f3Smrg      .handle = dumb_handle,
18887ec681f3Smrg   };
18897ec681f3Smrg   if (v3dv_ioctl(display_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb)) {
18907ec681f3Smrg      fprintf(stderr, "destroy dumb object %d: %s\n", dumb_handle, strerror(errno));
18917ec681f3Smrg   }
18927ec681f3Smrg}
18937ec681f3Smrg
18947ec681f3Smrgstatic void
18957ec681f3Smrgdevice_free(struct v3dv_device *device, struct v3dv_device_memory *mem)
18967ec681f3Smrg{
18977ec681f3Smrg   /* If this memory allocation was for WSI, then we need to use the
18987ec681f3Smrg    * display device to free the allocated dumb BO.
18997ec681f3Smrg    */
19007ec681f3Smrg   if (mem->is_for_wsi) {
19017ec681f3Smrg      assert(mem->has_bo_ownership);
19027ec681f3Smrg      device_free_wsi_dumb(device->instance->physicalDevice.display_fd,
19037ec681f3Smrg                           mem->bo->dumb_handle);
19047ec681f3Smrg   }
19057ec681f3Smrg
19067ec681f3Smrg   if (mem->has_bo_ownership)
19077ec681f3Smrg      v3dv_bo_free(device, mem->bo);
19087ec681f3Smrg   else if (mem->bo)
19097ec681f3Smrg      vk_free(&device->vk.alloc, mem->bo);
19107ec681f3Smrg}
19117ec681f3Smrg
19127ec681f3Smrgstatic void
19137ec681f3Smrgdevice_unmap(struct v3dv_device *device, struct v3dv_device_memory *mem)
19147ec681f3Smrg{
19157ec681f3Smrg   assert(mem && mem->bo->map && mem->bo->map_size > 0);
19167ec681f3Smrg   v3dv_bo_unmap(device, mem->bo);
19177ec681f3Smrg}
19187ec681f3Smrg
19197ec681f3Smrgstatic VkResult
19207ec681f3Smrgdevice_map(struct v3dv_device *device, struct v3dv_device_memory *mem)
19217ec681f3Smrg{
19227ec681f3Smrg   assert(mem && mem->bo);
19237ec681f3Smrg
19247ec681f3Smrg   /* From the spec:
19257ec681f3Smrg    *
19267ec681f3Smrg    *   "After a successful call to vkMapMemory the memory object memory is
19277ec681f3Smrg    *   considered to be currently host mapped. It is an application error to
19287ec681f3Smrg    *   call vkMapMemory on a memory object that is already host mapped."
19297ec681f3Smrg    *
19307ec681f3Smrg    * We are not concerned with this ourselves (validation layers should
19317ec681f3Smrg    * catch these errors and warn users), however, the driver may internally
19327ec681f3Smrg    * map things (for example for debug CLIF dumps or some CPU-side operations)
19337ec681f3Smrg    * so by the time the user calls here the buffer might already been mapped
19347ec681f3Smrg    * internally by the driver.
19357ec681f3Smrg    */
19367ec681f3Smrg   if (mem->bo->map) {
19377ec681f3Smrg      assert(mem->bo->map_size == mem->bo->size);
19387ec681f3Smrg      return VK_SUCCESS;
19397ec681f3Smrg   }
19407ec681f3Smrg
19417ec681f3Smrg   bool ok = v3dv_bo_map(device, mem->bo, mem->bo->size);
19427ec681f3Smrg   if (!ok)
19437ec681f3Smrg      return VK_ERROR_MEMORY_MAP_FAILED;
19447ec681f3Smrg
19457ec681f3Smrg   return VK_SUCCESS;
19467ec681f3Smrg}
19477ec681f3Smrg
19487ec681f3Smrgstatic VkResult
19497ec681f3Smrgdevice_import_bo(struct v3dv_device *device,
19507ec681f3Smrg                 const VkAllocationCallbacks *pAllocator,
19517ec681f3Smrg                 int fd, uint64_t size,
19527ec681f3Smrg                 struct v3dv_bo **bo)
19537ec681f3Smrg{
19547ec681f3Smrg   VkResult result;
19557ec681f3Smrg
19567ec681f3Smrg   *bo = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(struct v3dv_bo), 8,
19577ec681f3Smrg                   VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
19587ec681f3Smrg   if (*bo == NULL) {
19597ec681f3Smrg      result = VK_ERROR_OUT_OF_HOST_MEMORY;
19607ec681f3Smrg      goto fail;
19617ec681f3Smrg   }
19627ec681f3Smrg
19637ec681f3Smrg   off_t real_size = lseek(fd, 0, SEEK_END);
19647ec681f3Smrg   lseek(fd, 0, SEEK_SET);
19657ec681f3Smrg   if (real_size < 0 || (uint64_t) real_size < size) {
19667ec681f3Smrg      result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
19677ec681f3Smrg      goto fail;
19687ec681f3Smrg   }
19697ec681f3Smrg
19707ec681f3Smrg   int render_fd = device->pdevice->render_fd;
19717ec681f3Smrg   assert(render_fd >= 0);
19727ec681f3Smrg
19737ec681f3Smrg   int ret;
19747ec681f3Smrg   uint32_t handle;
19757ec681f3Smrg   ret = drmPrimeFDToHandle(render_fd, fd, &handle);
19767ec681f3Smrg   if (ret) {
19777ec681f3Smrg      result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
19787ec681f3Smrg      goto fail;
19797ec681f3Smrg   }
19807ec681f3Smrg
19817ec681f3Smrg   struct drm_v3d_get_bo_offset get_offset = {
19827ec681f3Smrg      .handle = handle,
19837ec681f3Smrg   };
19847ec681f3Smrg   ret = v3dv_ioctl(render_fd, DRM_IOCTL_V3D_GET_BO_OFFSET, &get_offset);
19857ec681f3Smrg   if (ret) {
19867ec681f3Smrg      result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
19877ec681f3Smrg      goto fail;
19887ec681f3Smrg   }
19897ec681f3Smrg   assert(get_offset.offset != 0);
19907ec681f3Smrg
19917ec681f3Smrg   v3dv_bo_init(*bo, handle, size, get_offset.offset, "import", false);
19927ec681f3Smrg
19937ec681f3Smrg   return VK_SUCCESS;
19947ec681f3Smrg
19957ec681f3Smrgfail:
19967ec681f3Smrg   if (*bo) {
19977ec681f3Smrg      vk_free2(&device->vk.alloc, pAllocator, *bo);
19987ec681f3Smrg      *bo = NULL;
19997ec681f3Smrg   }
20007ec681f3Smrg   return result;
20017ec681f3Smrg}
20027ec681f3Smrg
20037ec681f3Smrgstatic VkResult
20047ec681f3Smrgdevice_alloc_for_wsi(struct v3dv_device *device,
20057ec681f3Smrg                     const VkAllocationCallbacks *pAllocator,
20067ec681f3Smrg                     struct v3dv_device_memory *mem,
20077ec681f3Smrg                     VkDeviceSize size)
20087ec681f3Smrg{
20097ec681f3Smrg   /* In the simulator we can get away with a regular allocation since both
20107ec681f3Smrg    * allocation and rendering happen in the same DRM render node. On actual
20117ec681f3Smrg    * hardware we need to allocate our winsys BOs on the vc4 display device
20127ec681f3Smrg    * and import them into v3d.
20137ec681f3Smrg    */
20147ec681f3Smrg#if using_v3d_simulator
20157ec681f3Smrg      return device_alloc(device, mem, size);
20167ec681f3Smrg#else
20177ec681f3Smrg   /* If we are allocating for WSI we should have a swapchain and thus,
20187ec681f3Smrg    * we should've initialized the display device. However, Zink doesn't
20197ec681f3Smrg    * use swapchains, so in that case we can get here without acquiring the
20207ec681f3Smrg    * display device and we need to do it now.
20217ec681f3Smrg    */
20227ec681f3Smrg   VkResult result;
20237ec681f3Smrg   struct v3dv_instance *instance = device->instance;
20247ec681f3Smrg   struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;
20257ec681f3Smrg   if (unlikely(pdevice->display_fd < 0)) {
20267ec681f3Smrg      result = v3dv_physical_device_acquire_display(instance, pdevice, NULL);
20277ec681f3Smrg      if (result != VK_SUCCESS)
20287ec681f3Smrg         return result;
20297ec681f3Smrg   }
20307ec681f3Smrg   assert(pdevice->display_fd != -1);
20317ec681f3Smrg
20327ec681f3Smrg   mem->is_for_wsi = true;
20337ec681f3Smrg
20347ec681f3Smrg   int display_fd = pdevice->display_fd;
20357ec681f3Smrg   struct drm_mode_create_dumb create_dumb = {
20367ec681f3Smrg      .width = 1024, /* one page */
20377ec681f3Smrg      .height = align(size, 4096) / 4096,
20387ec681f3Smrg      .bpp = util_format_get_blocksizebits(PIPE_FORMAT_RGBA8888_UNORM),
20397ec681f3Smrg   };
20407ec681f3Smrg
20417ec681f3Smrg   int err;
20427ec681f3Smrg   err = v3dv_ioctl(display_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
20437ec681f3Smrg   if (err < 0)
20447ec681f3Smrg      goto fail_create;
20457ec681f3Smrg
20467ec681f3Smrg   int fd;
20477ec681f3Smrg   err =
20487ec681f3Smrg      drmPrimeHandleToFD(display_fd, create_dumb.handle, O_CLOEXEC, &fd);
20497ec681f3Smrg   if (err < 0)
20507ec681f3Smrg      goto fail_export;
20517ec681f3Smrg
20527ec681f3Smrg   result = device_import_bo(device, pAllocator, fd, size, &mem->bo);
20537ec681f3Smrg   close(fd);
20547ec681f3Smrg   if (result != VK_SUCCESS)
20557ec681f3Smrg      goto fail_import;
20567ec681f3Smrg
20577ec681f3Smrg   mem->bo->dumb_handle = create_dumb.handle;
20587ec681f3Smrg   return VK_SUCCESS;
20597ec681f3Smrg
20607ec681f3Smrgfail_import:
20617ec681f3Smrgfail_export:
20627ec681f3Smrg   device_free_wsi_dumb(display_fd, create_dumb.handle);
20637ec681f3Smrg
20647ec681f3Smrgfail_create:
20657ec681f3Smrg   return VK_ERROR_OUT_OF_DEVICE_MEMORY;
20667ec681f3Smrg#endif
20677ec681f3Smrg}
20687ec681f3Smrg
20697ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
20707ec681f3Smrgv3dv_AllocateMemory(VkDevice _device,
20717ec681f3Smrg                    const VkMemoryAllocateInfo *pAllocateInfo,
20727ec681f3Smrg                    const VkAllocationCallbacks *pAllocator,
20737ec681f3Smrg                    VkDeviceMemory *pMem)
20747ec681f3Smrg{
20757ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
20767ec681f3Smrg   struct v3dv_device_memory *mem;
20777ec681f3Smrg   struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;
20787ec681f3Smrg
20797ec681f3Smrg   assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO);
20807ec681f3Smrg
20817ec681f3Smrg   /* The Vulkan 1.0.33 spec says "allocationSize must be greater than 0". */
20827ec681f3Smrg   assert(pAllocateInfo->allocationSize > 0);
20837ec681f3Smrg
20847ec681f3Smrg   mem = vk_object_zalloc(&device->vk, pAllocator, sizeof(*mem),
20857ec681f3Smrg                          VK_OBJECT_TYPE_DEVICE_MEMORY);
20867ec681f3Smrg   if (mem == NULL)
20877ec681f3Smrg      return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
20887ec681f3Smrg
20897ec681f3Smrg   assert(pAllocateInfo->memoryTypeIndex < pdevice->memory.memoryTypeCount);
20907ec681f3Smrg   mem->type = &pdevice->memory.memoryTypes[pAllocateInfo->memoryTypeIndex];
20917ec681f3Smrg   mem->has_bo_ownership = true;
20927ec681f3Smrg   mem->is_for_wsi = false;
20937ec681f3Smrg
20947ec681f3Smrg   const struct wsi_memory_allocate_info *wsi_info = NULL;
20957ec681f3Smrg   const VkImportMemoryFdInfoKHR *fd_info = NULL;
20967ec681f3Smrg   vk_foreach_struct_const(ext, pAllocateInfo->pNext) {
20977ec681f3Smrg      switch ((unsigned)ext->sType) {
20987ec681f3Smrg      case VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA:
20997ec681f3Smrg         wsi_info = (void *)ext;
21007ec681f3Smrg         break;
21017ec681f3Smrg      case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:
21027ec681f3Smrg         fd_info = (void *)ext;
21037ec681f3Smrg         break;
21047ec681f3Smrg      case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO:
21057ec681f3Smrg         /* We don't support VK_KHR_buffer_device_address or multiple
21067ec681f3Smrg          * devices per device group, so we can ignore this.
21077ec681f3Smrg          */
21087ec681f3Smrg         break;
21097ec681f3Smrg      case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR:
21107ec681f3Smrg         /* We don't have particular optimizations associated with memory
21117ec681f3Smrg          * allocations that won't be suballocated to multiple resources.
21127ec681f3Smrg          */
21137ec681f3Smrg         break;
21147ec681f3Smrg      case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR:
21157ec681f3Smrg         /* The mask of handle types specified here must be supported
21167ec681f3Smrg          * according to VkExternalImageFormatProperties, so it must be
21177ec681f3Smrg          * fd or dmabuf, which don't have special requirements for us.
21187ec681f3Smrg          */
21197ec681f3Smrg         break;
21207ec681f3Smrg      default:
21217ec681f3Smrg         v3dv_debug_ignored_stype(ext->sType);
21227ec681f3Smrg         break;
21237ec681f3Smrg      }
21247ec681f3Smrg   }
21257ec681f3Smrg
21267ec681f3Smrg   VkResult result = VK_SUCCESS;
21277ec681f3Smrg
21287ec681f3Smrg   /* We always allocate device memory in multiples of a page, so round up
21297ec681f3Smrg    * requested size to that.
21307ec681f3Smrg    */
21317ec681f3Smrg   VkDeviceSize alloc_size = ALIGN(pAllocateInfo->allocationSize, 4096);
21327ec681f3Smrg
21337ec681f3Smrg   if (unlikely(alloc_size > MAX_MEMORY_ALLOCATION_SIZE)) {
21347ec681f3Smrg      result = VK_ERROR_OUT_OF_DEVICE_MEMORY;
21357ec681f3Smrg   } else {
21367ec681f3Smrg      if (wsi_info) {
21377ec681f3Smrg         result = device_alloc_for_wsi(device, pAllocator, mem, alloc_size);
21387ec681f3Smrg      } else if (fd_info && fd_info->handleType) {
21397ec681f3Smrg         assert(fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
21407ec681f3Smrg                fd_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
21417ec681f3Smrg         result = device_import_bo(device, pAllocator,
21427ec681f3Smrg                                   fd_info->fd, alloc_size, &mem->bo);
21437ec681f3Smrg         mem->has_bo_ownership = false;
21447ec681f3Smrg         if (result == VK_SUCCESS)
21457ec681f3Smrg            close(fd_info->fd);
21467ec681f3Smrg      } else {
21477ec681f3Smrg         result = device_alloc(device, mem, alloc_size);
21487ec681f3Smrg      }
21497ec681f3Smrg   }
21507ec681f3Smrg
21517ec681f3Smrg   if (result != VK_SUCCESS) {
21527ec681f3Smrg      vk_object_free(&device->vk, pAllocator, mem);
21537ec681f3Smrg      return vk_error(device, result);
21547ec681f3Smrg   }
21557ec681f3Smrg
21567ec681f3Smrg   *pMem = v3dv_device_memory_to_handle(mem);
21577ec681f3Smrg   return result;
21587ec681f3Smrg}
21597ec681f3Smrg
21607ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
21617ec681f3Smrgv3dv_FreeMemory(VkDevice _device,
21627ec681f3Smrg                VkDeviceMemory _mem,
21637ec681f3Smrg                const VkAllocationCallbacks *pAllocator)
21647ec681f3Smrg{
21657ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
21667ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device_memory, mem, _mem);
21677ec681f3Smrg
21687ec681f3Smrg   if (mem == NULL)
21697ec681f3Smrg      return;
21707ec681f3Smrg
21717ec681f3Smrg   if (mem->bo->map)
21727ec681f3Smrg      v3dv_UnmapMemory(_device, _mem);
21737ec681f3Smrg
21747ec681f3Smrg   device_free(device, mem);
21757ec681f3Smrg
21767ec681f3Smrg   vk_object_free(&device->vk, pAllocator, mem);
21777ec681f3Smrg}
21787ec681f3Smrg
21797ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
21807ec681f3Smrgv3dv_MapMemory(VkDevice _device,
21817ec681f3Smrg               VkDeviceMemory _memory,
21827ec681f3Smrg               VkDeviceSize offset,
21837ec681f3Smrg               VkDeviceSize size,
21847ec681f3Smrg               VkMemoryMapFlags flags,
21857ec681f3Smrg               void **ppData)
21867ec681f3Smrg{
21877ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
21887ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
21897ec681f3Smrg
21907ec681f3Smrg   if (mem == NULL) {
21917ec681f3Smrg      *ppData = NULL;
21927ec681f3Smrg      return VK_SUCCESS;
21937ec681f3Smrg   }
21947ec681f3Smrg
21957ec681f3Smrg   assert(offset < mem->bo->size);
21967ec681f3Smrg
21977ec681f3Smrg   /* Since the driver can map BOs internally as well and the mapped range
21987ec681f3Smrg    * required by the user or the driver might not be the same, we always map
21997ec681f3Smrg    * the entire BO and then add the requested offset to the start address
22007ec681f3Smrg    * of the mapped region.
22017ec681f3Smrg    */
22027ec681f3Smrg   VkResult result = device_map(device, mem);
22037ec681f3Smrg   if (result != VK_SUCCESS)
22047ec681f3Smrg      return vk_error(device, result);
22057ec681f3Smrg
22067ec681f3Smrg   *ppData = ((uint8_t *) mem->bo->map) + offset;
22077ec681f3Smrg   return VK_SUCCESS;
22087ec681f3Smrg}
22097ec681f3Smrg
22107ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
22117ec681f3Smrgv3dv_UnmapMemory(VkDevice _device,
22127ec681f3Smrg                 VkDeviceMemory _memory)
22137ec681f3Smrg{
22147ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
22157ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device_memory, mem, _memory);
22167ec681f3Smrg
22177ec681f3Smrg   if (mem == NULL)
22187ec681f3Smrg      return;
22197ec681f3Smrg
22207ec681f3Smrg   device_unmap(device, mem);
22217ec681f3Smrg}
22227ec681f3Smrg
22237ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
22247ec681f3Smrgv3dv_FlushMappedMemoryRanges(VkDevice _device,
22257ec681f3Smrg                             uint32_t memoryRangeCount,
22267ec681f3Smrg                             const VkMappedMemoryRange *pMemoryRanges)
22277ec681f3Smrg{
22287ec681f3Smrg   return VK_SUCCESS;
22297ec681f3Smrg}
22307ec681f3Smrg
22317ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
22327ec681f3Smrgv3dv_InvalidateMappedMemoryRanges(VkDevice _device,
22337ec681f3Smrg                                  uint32_t memoryRangeCount,
22347ec681f3Smrg                                  const VkMappedMemoryRange *pMemoryRanges)
22357ec681f3Smrg{
22367ec681f3Smrg   return VK_SUCCESS;
22377ec681f3Smrg}
22387ec681f3Smrg
22397ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
22407ec681f3Smrgv3dv_GetImageMemoryRequirements2(VkDevice device,
22417ec681f3Smrg                                 const VkImageMemoryRequirementsInfo2 *pInfo,
22427ec681f3Smrg                                 VkMemoryRequirements2 *pMemoryRequirements)
22437ec681f3Smrg{
22447ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_image, image, pInfo->image);
22457ec681f3Smrg
22467ec681f3Smrg   pMemoryRequirements->memoryRequirements = (VkMemoryRequirements) {
22477ec681f3Smrg      .memoryTypeBits = 0x1,
22487ec681f3Smrg      .alignment = image->alignment,
22497ec681f3Smrg      .size = image->size
22507ec681f3Smrg   };
22517ec681f3Smrg
22527ec681f3Smrg   vk_foreach_struct(ext, pMemoryRequirements->pNext) {
22537ec681f3Smrg      switch (ext->sType) {
22547ec681f3Smrg      case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
22557ec681f3Smrg         VkMemoryDedicatedRequirements *req =
22567ec681f3Smrg            (VkMemoryDedicatedRequirements *) ext;
22577ec681f3Smrg         req->requiresDedicatedAllocation = image->vk.external_handle_types != 0;
22587ec681f3Smrg         req->prefersDedicatedAllocation = image->vk.external_handle_types != 0;
22597ec681f3Smrg         break;
22607ec681f3Smrg      }
22617ec681f3Smrg      default:
22627ec681f3Smrg         v3dv_debug_ignored_stype(ext->sType);
22637ec681f3Smrg         break;
22647ec681f3Smrg      }
22657ec681f3Smrg   }
22667ec681f3Smrg}
22677ec681f3Smrg
22687ec681f3Smrgstatic void
22697ec681f3Smrgbind_image_memory(const VkBindImageMemoryInfo *info)
22707ec681f3Smrg{
22717ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_image, image, info->image);
22727ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device_memory, mem, info->memory);
22737ec681f3Smrg
22747ec681f3Smrg   /* Valid usage:
22757ec681f3Smrg    *
22767ec681f3Smrg    *   "memoryOffset must be an integer multiple of the alignment member of
22777ec681f3Smrg    *    the VkMemoryRequirements structure returned from a call to
22787ec681f3Smrg    *    vkGetImageMemoryRequirements with image"
22797ec681f3Smrg    */
22807ec681f3Smrg   assert(info->memoryOffset % image->alignment == 0);
22817ec681f3Smrg   assert(info->memoryOffset < mem->bo->size);
22827ec681f3Smrg
22837ec681f3Smrg   image->mem = mem;
22847ec681f3Smrg   image->mem_offset = info->memoryOffset;
22857ec681f3Smrg}
22867ec681f3Smrg
22877ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
22887ec681f3Smrgv3dv_BindImageMemory2(VkDevice _device,
22897ec681f3Smrg                      uint32_t bindInfoCount,
22907ec681f3Smrg                      const VkBindImageMemoryInfo *pBindInfos)
22917ec681f3Smrg{
22927ec681f3Smrg   for (uint32_t i = 0; i < bindInfoCount; i++) {
22937ec681f3Smrg      const VkBindImageMemorySwapchainInfoKHR *swapchain_info =
22947ec681f3Smrg         vk_find_struct_const(pBindInfos->pNext,
22957ec681f3Smrg                              BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR);
22967ec681f3Smrg      if (swapchain_info && swapchain_info->swapchain) {
22977ec681f3Smrg         struct v3dv_image *swapchain_image =
22987ec681f3Smrg            v3dv_wsi_get_image_from_swapchain(swapchain_info->swapchain,
22997ec681f3Smrg                                              swapchain_info->imageIndex);
23007ec681f3Smrg         VkBindImageMemoryInfo swapchain_bind = {
23017ec681f3Smrg            .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
23027ec681f3Smrg            .image = pBindInfos[i].image,
23037ec681f3Smrg            .memory = v3dv_device_memory_to_handle(swapchain_image->mem),
23047ec681f3Smrg            .memoryOffset = swapchain_image->mem_offset,
23057ec681f3Smrg         };
23067ec681f3Smrg         bind_image_memory(&swapchain_bind);
23077ec681f3Smrg      } else {
23087ec681f3Smrg         bind_image_memory(&pBindInfos[i]);
23097ec681f3Smrg      }
23107ec681f3Smrg   }
23117ec681f3Smrg
23127ec681f3Smrg   return VK_SUCCESS;
23137ec681f3Smrg}
23147ec681f3Smrg
23157ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
23167ec681f3Smrgv3dv_GetBufferMemoryRequirements2(VkDevice device,
23177ec681f3Smrg                                  const VkBufferMemoryRequirementsInfo2 *pInfo,
23187ec681f3Smrg                                  VkMemoryRequirements2 *pMemoryRequirements)
23197ec681f3Smrg{
23207ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_buffer, buffer, pInfo->buffer);
23217ec681f3Smrg
23227ec681f3Smrg   pMemoryRequirements->memoryRequirements = (VkMemoryRequirements) {
23237ec681f3Smrg      .memoryTypeBits = 0x1,
23247ec681f3Smrg      .alignment = buffer->alignment,
23257ec681f3Smrg      .size = align64(buffer->size, buffer->alignment),
23267ec681f3Smrg   };
23277ec681f3Smrg
23287ec681f3Smrg   vk_foreach_struct(ext, pMemoryRequirements->pNext) {
23297ec681f3Smrg      switch (ext->sType) {
23307ec681f3Smrg      case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
23317ec681f3Smrg         VkMemoryDedicatedRequirements *req =
23327ec681f3Smrg            (VkMemoryDedicatedRequirements *) ext;
23337ec681f3Smrg         req->requiresDedicatedAllocation = false;
23347ec681f3Smrg         req->prefersDedicatedAllocation = false;
23357ec681f3Smrg         break;
23367ec681f3Smrg      }
23377ec681f3Smrg      default:
23387ec681f3Smrg         v3dv_debug_ignored_stype(ext->sType);
23397ec681f3Smrg         break;
23407ec681f3Smrg      }
23417ec681f3Smrg   }
23427ec681f3Smrg}
23437ec681f3Smrg
23447ec681f3Smrgstatic void
23457ec681f3Smrgbind_buffer_memory(const VkBindBufferMemoryInfo *info)
23467ec681f3Smrg{
23477ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_buffer, buffer, info->buffer);
23487ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device_memory, mem, info->memory);
23497ec681f3Smrg
23507ec681f3Smrg   /* Valid usage:
23517ec681f3Smrg    *
23527ec681f3Smrg    *   "memoryOffset must be an integer multiple of the alignment member of
23537ec681f3Smrg    *    the VkMemoryRequirements structure returned from a call to
23547ec681f3Smrg    *    vkGetBufferMemoryRequirements with buffer"
23557ec681f3Smrg    */
23567ec681f3Smrg   assert(info->memoryOffset % buffer->alignment == 0);
23577ec681f3Smrg   assert(info->memoryOffset < mem->bo->size);
23587ec681f3Smrg
23597ec681f3Smrg   buffer->mem = mem;
23607ec681f3Smrg   buffer->mem_offset = info->memoryOffset;
23617ec681f3Smrg}
23627ec681f3Smrg
23637ec681f3Smrg
23647ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
23657ec681f3Smrgv3dv_BindBufferMemory2(VkDevice device,
23667ec681f3Smrg                       uint32_t bindInfoCount,
23677ec681f3Smrg                       const VkBindBufferMemoryInfo *pBindInfos)
23687ec681f3Smrg{
23697ec681f3Smrg   for (uint32_t i = 0; i < bindInfoCount; i++)
23707ec681f3Smrg      bind_buffer_memory(&pBindInfos[i]);
23717ec681f3Smrg
23727ec681f3Smrg   return VK_SUCCESS;
23737ec681f3Smrg}
23747ec681f3Smrg
23757ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
23767ec681f3Smrgv3dv_CreateBuffer(VkDevice  _device,
23777ec681f3Smrg                  const VkBufferCreateInfo *pCreateInfo,
23787ec681f3Smrg                  const VkAllocationCallbacks *pAllocator,
23797ec681f3Smrg                  VkBuffer *pBuffer)
23807ec681f3Smrg{
23817ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
23827ec681f3Smrg   struct v3dv_buffer *buffer;
23837ec681f3Smrg
23847ec681f3Smrg   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO);
23857ec681f3Smrg   assert(pCreateInfo->usage != 0);
23867ec681f3Smrg
23877ec681f3Smrg   /* We don't support any flags for now */
23887ec681f3Smrg   assert(pCreateInfo->flags == 0);
23897ec681f3Smrg
23907ec681f3Smrg   buffer = vk_object_zalloc(&device->vk, pAllocator, sizeof(*buffer),
23917ec681f3Smrg                             VK_OBJECT_TYPE_BUFFER);
23927ec681f3Smrg   if (buffer == NULL)
23937ec681f3Smrg      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
23947ec681f3Smrg
23957ec681f3Smrg   buffer->size = pCreateInfo->size;
23967ec681f3Smrg   buffer->usage = pCreateInfo->usage;
23977ec681f3Smrg   buffer->alignment = 256; /* nonCoherentAtomSize */
23987ec681f3Smrg
23997ec681f3Smrg   /* Limit allocations to 32-bit */
24007ec681f3Smrg   const VkDeviceSize aligned_size = align64(buffer->size, buffer->alignment);
24017ec681f3Smrg   if (aligned_size > UINT32_MAX || aligned_size < buffer->size)
24027ec681f3Smrg      return VK_ERROR_OUT_OF_DEVICE_MEMORY;
24037ec681f3Smrg
24047ec681f3Smrg   *pBuffer = v3dv_buffer_to_handle(buffer);
24057ec681f3Smrg
24067ec681f3Smrg   return VK_SUCCESS;
24077ec681f3Smrg}
24087ec681f3Smrg
24097ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
24107ec681f3Smrgv3dv_DestroyBuffer(VkDevice _device,
24117ec681f3Smrg                   VkBuffer _buffer,
24127ec681f3Smrg                   const VkAllocationCallbacks *pAllocator)
24137ec681f3Smrg{
24147ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
24157ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_buffer, buffer, _buffer);
24167ec681f3Smrg
24177ec681f3Smrg   if (!buffer)
24187ec681f3Smrg      return;
24197ec681f3Smrg
24207ec681f3Smrg   vk_object_free(&device->vk, pAllocator, buffer);
24217ec681f3Smrg}
24227ec681f3Smrg
24237ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
24247ec681f3Smrgv3dv_CreateFramebuffer(VkDevice _device,
24257ec681f3Smrg                       const VkFramebufferCreateInfo *pCreateInfo,
24267ec681f3Smrg                       const VkAllocationCallbacks *pAllocator,
24277ec681f3Smrg                       VkFramebuffer *pFramebuffer)
24287ec681f3Smrg{
24297ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
24307ec681f3Smrg   struct v3dv_framebuffer *framebuffer;
24317ec681f3Smrg
24327ec681f3Smrg   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO);
24337ec681f3Smrg
24347ec681f3Smrg   size_t size = sizeof(*framebuffer) +
24357ec681f3Smrg                 sizeof(struct v3dv_image_view *) * pCreateInfo->attachmentCount;
24367ec681f3Smrg   framebuffer = vk_object_zalloc(&device->vk, pAllocator, size,
24377ec681f3Smrg                                  VK_OBJECT_TYPE_FRAMEBUFFER);
24387ec681f3Smrg   if (framebuffer == NULL)
24397ec681f3Smrg      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
24407ec681f3Smrg
24417ec681f3Smrg   framebuffer->width = pCreateInfo->width;
24427ec681f3Smrg   framebuffer->height = pCreateInfo->height;
24437ec681f3Smrg   framebuffer->layers = pCreateInfo->layers;
24447ec681f3Smrg   framebuffer->has_edge_padding = true;
24457ec681f3Smrg
24467ec681f3Smrg   framebuffer->attachment_count = pCreateInfo->attachmentCount;
24477ec681f3Smrg   framebuffer->color_attachment_count = 0;
24487ec681f3Smrg   for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
24497ec681f3Smrg      framebuffer->attachments[i] =
24507ec681f3Smrg         v3dv_image_view_from_handle(pCreateInfo->pAttachments[i]);
24517ec681f3Smrg      if (framebuffer->attachments[i]->vk.aspects & VK_IMAGE_ASPECT_COLOR_BIT)
24527ec681f3Smrg         framebuffer->color_attachment_count++;
24537ec681f3Smrg   }
24547ec681f3Smrg
24557ec681f3Smrg   *pFramebuffer = v3dv_framebuffer_to_handle(framebuffer);
24567ec681f3Smrg
24577ec681f3Smrg   return VK_SUCCESS;
24587ec681f3Smrg}
24597ec681f3Smrg
24607ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
24617ec681f3Smrgv3dv_DestroyFramebuffer(VkDevice _device,
24627ec681f3Smrg                        VkFramebuffer _fb,
24637ec681f3Smrg                        const VkAllocationCallbacks *pAllocator)
24647ec681f3Smrg{
24657ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
24667ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_framebuffer, fb, _fb);
24677ec681f3Smrg
24687ec681f3Smrg   if (!fb)
24697ec681f3Smrg      return;
24707ec681f3Smrg
24717ec681f3Smrg   vk_object_free(&device->vk, pAllocator, fb);
24727ec681f3Smrg}
24737ec681f3Smrg
24747ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
24757ec681f3Smrgv3dv_GetMemoryFdPropertiesKHR(VkDevice _device,
24767ec681f3Smrg                              VkExternalMemoryHandleTypeFlagBits handleType,
24777ec681f3Smrg                              int fd,
24787ec681f3Smrg                              VkMemoryFdPropertiesKHR *pMemoryFdProperties)
24797ec681f3Smrg{
24807ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
24817ec681f3Smrg   struct v3dv_physical_device *pdevice = &device->instance->physicalDevice;
24827ec681f3Smrg
24837ec681f3Smrg   switch (handleType) {
24847ec681f3Smrg   case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT:
24857ec681f3Smrg      pMemoryFdProperties->memoryTypeBits =
24867ec681f3Smrg         (1 << pdevice->memory.memoryTypeCount) - 1;
24877ec681f3Smrg      return VK_SUCCESS;
24887ec681f3Smrg   default:
24897ec681f3Smrg      return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
24907ec681f3Smrg   }
24917ec681f3Smrg}
24927ec681f3Smrg
24937ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
24947ec681f3Smrgv3dv_GetMemoryFdKHR(VkDevice _device,
24957ec681f3Smrg                    const VkMemoryGetFdInfoKHR *pGetFdInfo,
24967ec681f3Smrg                    int *pFd)
24977ec681f3Smrg{
24987ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
24997ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device_memory, mem, pGetFdInfo->memory);
25007ec681f3Smrg
25017ec681f3Smrg   assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR);
25027ec681f3Smrg   assert(pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT ||
25037ec681f3Smrg          pGetFdInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
25047ec681f3Smrg
25057ec681f3Smrg   int fd, ret;
25067ec681f3Smrg   ret = drmPrimeHandleToFD(device->pdevice->render_fd,
25077ec681f3Smrg                            mem->bo->handle,
25087ec681f3Smrg                            DRM_CLOEXEC, &fd);
25097ec681f3Smrg   if (ret)
25107ec681f3Smrg      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
25117ec681f3Smrg
25127ec681f3Smrg   *pFd = fd;
25137ec681f3Smrg
25147ec681f3Smrg   return VK_SUCCESS;
25157ec681f3Smrg}
25167ec681f3Smrg
25177ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
25187ec681f3Smrgv3dv_CreateEvent(VkDevice _device,
25197ec681f3Smrg                 const VkEventCreateInfo *pCreateInfo,
25207ec681f3Smrg                 const VkAllocationCallbacks *pAllocator,
25217ec681f3Smrg                 VkEvent *pEvent)
25227ec681f3Smrg{
25237ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
25247ec681f3Smrg   struct v3dv_event *event =
25257ec681f3Smrg      vk_object_zalloc(&device->vk, pAllocator, sizeof(*event),
25267ec681f3Smrg                       VK_OBJECT_TYPE_EVENT);
25277ec681f3Smrg   if (!event)
25287ec681f3Smrg      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
25297ec681f3Smrg
25307ec681f3Smrg   /* Events are created in the unsignaled state */
25317ec681f3Smrg   event->state = false;
25327ec681f3Smrg   *pEvent = v3dv_event_to_handle(event);
25337ec681f3Smrg
25347ec681f3Smrg   return VK_SUCCESS;
25357ec681f3Smrg}
25367ec681f3Smrg
25377ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
25387ec681f3Smrgv3dv_DestroyEvent(VkDevice _device,
25397ec681f3Smrg                  VkEvent _event,
25407ec681f3Smrg                  const VkAllocationCallbacks *pAllocator)
25417ec681f3Smrg{
25427ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
25437ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_event, event, _event);
25447ec681f3Smrg
25457ec681f3Smrg   if (!event)
25467ec681f3Smrg      return;
25477ec681f3Smrg
25487ec681f3Smrg   vk_object_free(&device->vk, pAllocator, event);
25497ec681f3Smrg}
25507ec681f3Smrg
25517ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
25527ec681f3Smrgv3dv_GetEventStatus(VkDevice _device, VkEvent _event)
25537ec681f3Smrg{
25547ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_event, event, _event);
25557ec681f3Smrg   return p_atomic_read(&event->state) ? VK_EVENT_SET : VK_EVENT_RESET;
25567ec681f3Smrg}
25577ec681f3Smrg
25587ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
25597ec681f3Smrgv3dv_SetEvent(VkDevice _device, VkEvent _event)
25607ec681f3Smrg{
25617ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_event, event, _event);
25627ec681f3Smrg   p_atomic_set(&event->state, 1);
25637ec681f3Smrg   return VK_SUCCESS;
25647ec681f3Smrg}
25657ec681f3Smrg
25667ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
25677ec681f3Smrgv3dv_ResetEvent(VkDevice _device, VkEvent _event)
25687ec681f3Smrg{
25697ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_event, event, _event);
25707ec681f3Smrg   p_atomic_set(&event->state, 0);
25717ec681f3Smrg   return VK_SUCCESS;
25727ec681f3Smrg}
25737ec681f3Smrg
25747ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
25757ec681f3Smrgv3dv_CreateSampler(VkDevice _device,
25767ec681f3Smrg                 const VkSamplerCreateInfo *pCreateInfo,
25777ec681f3Smrg                 const VkAllocationCallbacks *pAllocator,
25787ec681f3Smrg                 VkSampler *pSampler)
25797ec681f3Smrg{
25807ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
25817ec681f3Smrg   struct v3dv_sampler *sampler;
25827ec681f3Smrg
25837ec681f3Smrg   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
25847ec681f3Smrg
25857ec681f3Smrg   sampler = vk_object_zalloc(&device->vk, pAllocator, sizeof(*sampler),
25867ec681f3Smrg                              VK_OBJECT_TYPE_SAMPLER);
25877ec681f3Smrg   if (!sampler)
25887ec681f3Smrg      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
25897ec681f3Smrg
25907ec681f3Smrg   sampler->compare_enable = pCreateInfo->compareEnable;
25917ec681f3Smrg   sampler->unnormalized_coordinates = pCreateInfo->unnormalizedCoordinates;
25927ec681f3Smrg
25937ec681f3Smrg   const VkSamplerCustomBorderColorCreateInfoEXT *bc_info =
25947ec681f3Smrg      vk_find_struct_const(pCreateInfo->pNext,
25957ec681f3Smrg                           SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT);
25967ec681f3Smrg
25977ec681f3Smrg   v3dv_X(device, pack_sampler_state)(sampler, pCreateInfo, bc_info);
25987ec681f3Smrg
25997ec681f3Smrg   *pSampler = v3dv_sampler_to_handle(sampler);
26007ec681f3Smrg
26017ec681f3Smrg   return VK_SUCCESS;
26027ec681f3Smrg}
26037ec681f3Smrg
26047ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
26057ec681f3Smrgv3dv_DestroySampler(VkDevice _device,
26067ec681f3Smrg                  VkSampler _sampler,
26077ec681f3Smrg                  const VkAllocationCallbacks *pAllocator)
26087ec681f3Smrg{
26097ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_device, device, _device);
26107ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_sampler, sampler, _sampler);
26117ec681f3Smrg
26127ec681f3Smrg   if (!sampler)
26137ec681f3Smrg      return;
26147ec681f3Smrg
26157ec681f3Smrg   vk_object_free(&device->vk, pAllocator, sampler);
26167ec681f3Smrg}
26177ec681f3Smrg
26187ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
26197ec681f3Smrgv3dv_GetDeviceMemoryCommitment(VkDevice device,
26207ec681f3Smrg                               VkDeviceMemory memory,
26217ec681f3Smrg                               VkDeviceSize *pCommittedMemoryInBytes)
26227ec681f3Smrg{
26237ec681f3Smrg   *pCommittedMemoryInBytes = 0;
26247ec681f3Smrg}
26257ec681f3Smrg
26267ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
26277ec681f3Smrgv3dv_GetImageSparseMemoryRequirements(
26287ec681f3Smrg    VkDevice device,
26297ec681f3Smrg    VkImage image,
26307ec681f3Smrg    uint32_t *pSparseMemoryRequirementCount,
26317ec681f3Smrg    VkSparseImageMemoryRequirements *pSparseMemoryRequirements)
26327ec681f3Smrg{
26337ec681f3Smrg   *pSparseMemoryRequirementCount = 0;
26347ec681f3Smrg}
26357ec681f3Smrg
26367ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
26377ec681f3Smrgv3dv_GetImageSparseMemoryRequirements2(
26387ec681f3Smrg   VkDevice device,
26397ec681f3Smrg   const VkImageSparseMemoryRequirementsInfo2 *pInfo,
26407ec681f3Smrg   uint32_t *pSparseMemoryRequirementCount,
26417ec681f3Smrg   VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
26427ec681f3Smrg{
26437ec681f3Smrg   *pSparseMemoryRequirementCount = 0;
26447ec681f3Smrg}
26457ec681f3Smrg
26467ec681f3Smrg/* vk_icd.h does not declare this function, so we declare it here to
26477ec681f3Smrg * suppress Wmissing-prototypes.
26487ec681f3Smrg */
26497ec681f3SmrgPUBLIC VKAPI_ATTR VkResult VKAPI_CALL
26507ec681f3Smrgvk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion);
26517ec681f3Smrg
26527ec681f3SmrgPUBLIC VKAPI_ATTR VkResult VKAPI_CALL
26537ec681f3Smrgvk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion)
26547ec681f3Smrg{
26557ec681f3Smrg   /* For the full details on loader interface versioning, see
26567ec681f3Smrg    * <https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md>.
26577ec681f3Smrg    * What follows is a condensed summary, to help you navigate the large and
26587ec681f3Smrg    * confusing official doc.
26597ec681f3Smrg    *
26607ec681f3Smrg    *   - Loader interface v0 is incompatible with later versions. We don't
26617ec681f3Smrg    *     support it.
26627ec681f3Smrg    *
26637ec681f3Smrg    *   - In loader interface v1:
26647ec681f3Smrg    *       - The first ICD entrypoint called by the loader is
26657ec681f3Smrg    *         vk_icdGetInstanceProcAddr(). The ICD must statically expose this
26667ec681f3Smrg    *         entrypoint.
26677ec681f3Smrg    *       - The ICD must statically expose no other Vulkan symbol unless it is
26687ec681f3Smrg    *         linked with -Bsymbolic.
26697ec681f3Smrg    *       - Each dispatchable Vulkan handle created by the ICD must be
26707ec681f3Smrg    *         a pointer to a struct whose first member is VK_LOADER_DATA. The
26717ec681f3Smrg    *         ICD must initialize VK_LOADER_DATA.loadMagic to ICD_LOADER_MAGIC.
26727ec681f3Smrg    *       - The loader implements vkCreate{PLATFORM}SurfaceKHR() and
26737ec681f3Smrg    *         vkDestroySurfaceKHR(). The ICD must be capable of working with
26747ec681f3Smrg    *         such loader-managed surfaces.
26757ec681f3Smrg    *
26767ec681f3Smrg    *    - Loader interface v2 differs from v1 in:
26777ec681f3Smrg    *       - The first ICD entrypoint called by the loader is
26787ec681f3Smrg    *         vk_icdNegotiateLoaderICDInterfaceVersion(). The ICD must
26797ec681f3Smrg    *         statically expose this entrypoint.
26807ec681f3Smrg    *
26817ec681f3Smrg    *    - Loader interface v3 differs from v2 in:
26827ec681f3Smrg    *        - The ICD must implement vkCreate{PLATFORM}SurfaceKHR(),
26837ec681f3Smrg    *          vkDestroySurfaceKHR(), and other API which uses VKSurfaceKHR,
26847ec681f3Smrg    *          because the loader no longer does so.
26857ec681f3Smrg    *
26867ec681f3Smrg    *    - Loader interface v4 differs from v3 in:
26877ec681f3Smrg    *        - The ICD must implement vk_icdGetPhysicalDeviceProcAddr().
26887ec681f3Smrg    */
26897ec681f3Smrg   *pSupportedVersion = MIN2(*pSupportedVersion, 3u);
26907ec681f3Smrg   return VK_SUCCESS;
26917ec681f3Smrg}
2692