17ec681f3Smrg/*
27ec681f3Smrg * Copyright 2019 Google LLC
37ec681f3Smrg * SPDX-License-Identifier: MIT
47ec681f3Smrg *
57ec681f3Smrg * based in part on anv and radv which are:
67ec681f3Smrg * Copyright © 2015 Intel Corporation
77ec681f3Smrg * Copyright © 2016 Red Hat.
87ec681f3Smrg * Copyright © 2016 Bas Nieuwenhuizen
97ec681f3Smrg */
107ec681f3Smrg
117ec681f3Smrg#include "vn_device.h"
127ec681f3Smrg
137ec681f3Smrg#include "venus-protocol/vn_protocol_driver_device.h"
147ec681f3Smrg
157ec681f3Smrg#include "vn_android.h"
167ec681f3Smrg#include "vn_instance.h"
177ec681f3Smrg#include "vn_physical_device.h"
187ec681f3Smrg#include "vn_queue.h"
197ec681f3Smrg
207ec681f3Smrg/* device commands */
217ec681f3Smrg
227ec681f3Smrgstatic void
237ec681f3Smrgvn_queue_fini(struct vn_queue *queue)
247ec681f3Smrg{
257ec681f3Smrg   if (queue->wait_fence != VK_NULL_HANDLE) {
267ec681f3Smrg      vn_DestroyFence(vn_device_to_handle(queue->device), queue->wait_fence,
277ec681f3Smrg                      NULL);
287ec681f3Smrg   }
297ec681f3Smrg   vn_object_base_fini(&queue->base);
307ec681f3Smrg}
317ec681f3Smrg
327ec681f3Smrgstatic VkResult
337ec681f3Smrgvn_queue_init(struct vn_device *dev,
347ec681f3Smrg              struct vn_queue *queue,
357ec681f3Smrg              const VkDeviceQueueCreateInfo *queue_info,
367ec681f3Smrg              uint32_t queue_index)
377ec681f3Smrg{
387ec681f3Smrg   vn_object_base_init(&queue->base, VK_OBJECT_TYPE_QUEUE, &dev->base);
397ec681f3Smrg
407ec681f3Smrg   VkQueue queue_handle = vn_queue_to_handle(queue);
417ec681f3Smrg   vn_async_vkGetDeviceQueue2(
427ec681f3Smrg      dev->instance, vn_device_to_handle(dev),
437ec681f3Smrg      &(VkDeviceQueueInfo2){
447ec681f3Smrg         .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2,
457ec681f3Smrg         .flags = queue_info->flags,
467ec681f3Smrg         .queueFamilyIndex = queue_info->queueFamilyIndex,
477ec681f3Smrg         .queueIndex = queue_index,
487ec681f3Smrg      },
497ec681f3Smrg      &queue_handle);
507ec681f3Smrg
517ec681f3Smrg   queue->device = dev;
527ec681f3Smrg   queue->family = queue_info->queueFamilyIndex;
537ec681f3Smrg   queue->index = queue_index;
547ec681f3Smrg   queue->flags = queue_info->flags;
557ec681f3Smrg
567ec681f3Smrg   const VkExportFenceCreateInfo export_fence_info = {
577ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO,
587ec681f3Smrg      .pNext = NULL,
597ec681f3Smrg      .handleTypes = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT,
607ec681f3Smrg   };
617ec681f3Smrg   const VkFenceCreateInfo fence_info = {
627ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
637ec681f3Smrg      .pNext = dev->instance->experimental.globalFencing == VK_TRUE
647ec681f3Smrg                  ? &export_fence_info
657ec681f3Smrg                  : NULL,
667ec681f3Smrg      .flags = 0,
677ec681f3Smrg   };
687ec681f3Smrg   VkResult result = vn_CreateFence(vn_device_to_handle(dev), &fence_info,
697ec681f3Smrg                                    NULL, &queue->wait_fence);
707ec681f3Smrg   if (result != VK_SUCCESS)
717ec681f3Smrg      return result;
727ec681f3Smrg
737ec681f3Smrg   return VK_SUCCESS;
747ec681f3Smrg}
757ec681f3Smrg
767ec681f3Smrgstatic VkResult
777ec681f3Smrgvn_device_init_queues(struct vn_device *dev,
787ec681f3Smrg                      const VkDeviceCreateInfo *create_info)
797ec681f3Smrg{
807ec681f3Smrg   const VkAllocationCallbacks *alloc = &dev->base.base.alloc;
817ec681f3Smrg
827ec681f3Smrg   uint32_t count = 0;
837ec681f3Smrg   for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++)
847ec681f3Smrg      count += create_info->pQueueCreateInfos[i].queueCount;
857ec681f3Smrg
867ec681f3Smrg   struct vn_queue *queues =
877ec681f3Smrg      vk_zalloc(alloc, sizeof(*queues) * count, VN_DEFAULT_ALIGN,
887ec681f3Smrg                VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
897ec681f3Smrg   if (!queues)
907ec681f3Smrg      return VK_ERROR_OUT_OF_HOST_MEMORY;
917ec681f3Smrg
927ec681f3Smrg   VkResult result = VK_SUCCESS;
937ec681f3Smrg   count = 0;
947ec681f3Smrg   for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) {
957ec681f3Smrg      const VkDeviceQueueCreateInfo *queue_info =
967ec681f3Smrg         &create_info->pQueueCreateInfos[i];
977ec681f3Smrg      for (uint32_t j = 0; j < queue_info->queueCount; j++) {
987ec681f3Smrg         result = vn_queue_init(dev, &queues[count], queue_info, j);
997ec681f3Smrg         if (result != VK_SUCCESS)
1007ec681f3Smrg            break;
1017ec681f3Smrg
1027ec681f3Smrg         count++;
1037ec681f3Smrg      }
1047ec681f3Smrg   }
1057ec681f3Smrg
1067ec681f3Smrg   if (result != VK_SUCCESS) {
1077ec681f3Smrg      for (uint32_t i = 0; i < count; i++)
1087ec681f3Smrg         vn_queue_fini(&queues[i]);
1097ec681f3Smrg      vk_free(alloc, queues);
1107ec681f3Smrg
1117ec681f3Smrg      return result;
1127ec681f3Smrg   }
1137ec681f3Smrg
1147ec681f3Smrg   dev->queues = queues;
1157ec681f3Smrg   dev->queue_count = count;
1167ec681f3Smrg
1177ec681f3Smrg   return VK_SUCCESS;
1187ec681f3Smrg}
1197ec681f3Smrg
1207ec681f3Smrgstatic bool
1217ec681f3Smrgfind_extension_names(const char *const *exts,
1227ec681f3Smrg                     uint32_t ext_count,
1237ec681f3Smrg                     const char *name)
1247ec681f3Smrg{
1257ec681f3Smrg   for (uint32_t i = 0; i < ext_count; i++) {
1267ec681f3Smrg      if (!strcmp(exts[i], name))
1277ec681f3Smrg         return true;
1287ec681f3Smrg   }
1297ec681f3Smrg   return false;
1307ec681f3Smrg}
1317ec681f3Smrg
1327ec681f3Smrgstatic bool
1337ec681f3Smrgmerge_extension_names(const char *const *exts,
1347ec681f3Smrg                      uint32_t ext_count,
1357ec681f3Smrg                      const char *const *extra_exts,
1367ec681f3Smrg                      uint32_t extra_count,
1377ec681f3Smrg                      const char *const *block_exts,
1387ec681f3Smrg                      uint32_t block_count,
1397ec681f3Smrg                      const VkAllocationCallbacks *alloc,
1407ec681f3Smrg                      const char *const **out_exts,
1417ec681f3Smrg                      uint32_t *out_count)
1427ec681f3Smrg{
1437ec681f3Smrg   const char **merged =
1447ec681f3Smrg      vk_alloc(alloc, sizeof(*merged) * (ext_count + extra_count),
1457ec681f3Smrg               VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
1467ec681f3Smrg   if (!merged)
1477ec681f3Smrg      return false;
1487ec681f3Smrg
1497ec681f3Smrg   uint32_t count = 0;
1507ec681f3Smrg   for (uint32_t i = 0; i < ext_count; i++) {
1517ec681f3Smrg      if (!find_extension_names(block_exts, block_count, exts[i]))
1527ec681f3Smrg         merged[count++] = exts[i];
1537ec681f3Smrg   }
1547ec681f3Smrg   for (uint32_t i = 0; i < extra_count; i++) {
1557ec681f3Smrg      if (!find_extension_names(exts, ext_count, extra_exts[i]))
1567ec681f3Smrg         merged[count++] = extra_exts[i];
1577ec681f3Smrg   }
1587ec681f3Smrg
1597ec681f3Smrg   *out_exts = merged;
1607ec681f3Smrg   *out_count = count;
1617ec681f3Smrg   return true;
1627ec681f3Smrg}
1637ec681f3Smrg
1647ec681f3Smrgstatic const VkDeviceCreateInfo *
1657ec681f3Smrgvn_device_fix_create_info(const struct vn_device *dev,
1667ec681f3Smrg                          const VkDeviceCreateInfo *dev_info,
1677ec681f3Smrg                          const VkAllocationCallbacks *alloc,
1687ec681f3Smrg                          VkDeviceCreateInfo *local_info)
1697ec681f3Smrg{
1707ec681f3Smrg   const struct vn_physical_device *physical_dev = dev->physical_device;
1717ec681f3Smrg   const struct vk_device_extension_table *app_exts =
1727ec681f3Smrg      &dev->base.base.enabled_extensions;
1737ec681f3Smrg   /* extra_exts and block_exts must not overlap */
1747ec681f3Smrg   const char *extra_exts[16];
1757ec681f3Smrg   const char *block_exts[16];
1767ec681f3Smrg   uint32_t extra_count = 0;
1777ec681f3Smrg   uint32_t block_count = 0;
1787ec681f3Smrg
1797ec681f3Smrg   /* fix for WSI (treat AHB as WSI extension for simplicity) */
1807ec681f3Smrg   const bool has_wsi =
1817ec681f3Smrg      app_exts->KHR_swapchain || app_exts->ANDROID_native_buffer ||
1827ec681f3Smrg      app_exts->ANDROID_external_memory_android_hardware_buffer;
1837ec681f3Smrg   if (has_wsi) {
1847ec681f3Smrg      /* KHR_swapchain may be advertised without the renderer support for
1857ec681f3Smrg       * EXT_image_drm_format_modifier
1867ec681f3Smrg       */
1877ec681f3Smrg      if (!app_exts->EXT_image_drm_format_modifier &&
1887ec681f3Smrg          physical_dev->renderer_extensions.EXT_image_drm_format_modifier) {
1897ec681f3Smrg         extra_exts[extra_count++] =
1907ec681f3Smrg            VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME;
1917ec681f3Smrg
1927ec681f3Smrg         if (physical_dev->renderer_version < VK_API_VERSION_1_2 &&
1937ec681f3Smrg             !app_exts->KHR_image_format_list) {
1947ec681f3Smrg            extra_exts[extra_count++] =
1957ec681f3Smrg               VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME;
1967ec681f3Smrg         }
1977ec681f3Smrg      }
1987ec681f3Smrg
1997ec681f3Smrg      /* XXX KHR_swapchain may be advertised without the renderer support for
2007ec681f3Smrg       * EXT_queue_family_foreign
2017ec681f3Smrg       */
2027ec681f3Smrg      if (!app_exts->EXT_queue_family_foreign &&
2037ec681f3Smrg          physical_dev->renderer_extensions.EXT_queue_family_foreign) {
2047ec681f3Smrg         extra_exts[extra_count++] =
2057ec681f3Smrg            VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME;
2067ec681f3Smrg      }
2077ec681f3Smrg
2087ec681f3Smrg      if (app_exts->KHR_swapchain) {
2097ec681f3Smrg         /* see vn_physical_device_get_native_extensions */
2107ec681f3Smrg         block_exts[block_count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
2117ec681f3Smrg         block_exts[block_count++] =
2127ec681f3Smrg            VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME;
2137ec681f3Smrg         block_exts[block_count++] =
2147ec681f3Smrg            VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME;
2157ec681f3Smrg      }
2167ec681f3Smrg
2177ec681f3Smrg      if (app_exts->ANDROID_native_buffer)
2187ec681f3Smrg         block_exts[block_count++] = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
2197ec681f3Smrg
2207ec681f3Smrg      if (app_exts->ANDROID_external_memory_android_hardware_buffer) {
2217ec681f3Smrg         block_exts[block_count++] =
2227ec681f3Smrg            VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME;
2237ec681f3Smrg      }
2247ec681f3Smrg   }
2257ec681f3Smrg
2267ec681f3Smrg   if (app_exts->KHR_external_memory_fd ||
2277ec681f3Smrg       app_exts->EXT_external_memory_dma_buf || has_wsi) {
2287ec681f3Smrg      switch (physical_dev->external_memory.renderer_handle_type) {
2297ec681f3Smrg      case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT:
2307ec681f3Smrg         if (!app_exts->EXT_external_memory_dma_buf) {
2317ec681f3Smrg            extra_exts[extra_count++] =
2327ec681f3Smrg               VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME;
2337ec681f3Smrg         }
2347ec681f3Smrg         FALLTHROUGH;
2357ec681f3Smrg      case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
2367ec681f3Smrg         if (!app_exts->KHR_external_memory_fd) {
2377ec681f3Smrg            extra_exts[extra_count++] =
2387ec681f3Smrg               VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME;
2397ec681f3Smrg         }
2407ec681f3Smrg         break;
2417ec681f3Smrg      default:
2427ec681f3Smrg         /* TODO other handle types */
2437ec681f3Smrg         break;
2447ec681f3Smrg      }
2457ec681f3Smrg   }
2467ec681f3Smrg
2477ec681f3Smrg   assert(extra_count <= ARRAY_SIZE(extra_exts));
2487ec681f3Smrg   assert(block_count <= ARRAY_SIZE(block_exts));
2497ec681f3Smrg
2507ec681f3Smrg   if (!extra_count && (!block_count || !dev_info->enabledExtensionCount))
2517ec681f3Smrg      return dev_info;
2527ec681f3Smrg
2537ec681f3Smrg   *local_info = *dev_info;
2547ec681f3Smrg   if (!merge_extension_names(dev_info->ppEnabledExtensionNames,
2557ec681f3Smrg                              dev_info->enabledExtensionCount, extra_exts,
2567ec681f3Smrg                              extra_count, block_exts, block_count, alloc,
2577ec681f3Smrg                              &local_info->ppEnabledExtensionNames,
2587ec681f3Smrg                              &local_info->enabledExtensionCount))
2597ec681f3Smrg      return NULL;
2607ec681f3Smrg
2617ec681f3Smrg   return local_info;
2627ec681f3Smrg}
2637ec681f3Smrg
2647ec681f3SmrgVkResult
2657ec681f3Smrgvn_CreateDevice(VkPhysicalDevice physicalDevice,
2667ec681f3Smrg                const VkDeviceCreateInfo *pCreateInfo,
2677ec681f3Smrg                const VkAllocationCallbacks *pAllocator,
2687ec681f3Smrg                VkDevice *pDevice)
2697ec681f3Smrg{
2707ec681f3Smrg   struct vn_physical_device *physical_dev =
2717ec681f3Smrg      vn_physical_device_from_handle(physicalDevice);
2727ec681f3Smrg   struct vn_instance *instance = physical_dev->instance;
2737ec681f3Smrg   const VkAllocationCallbacks *alloc =
2747ec681f3Smrg      pAllocator ? pAllocator : &instance->base.base.alloc;
2757ec681f3Smrg   struct vn_device *dev;
2767ec681f3Smrg   VkResult result;
2777ec681f3Smrg
2787ec681f3Smrg   dev = vk_zalloc(alloc, sizeof(*dev), VN_DEFAULT_ALIGN,
2797ec681f3Smrg                   VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
2807ec681f3Smrg   if (!dev)
2817ec681f3Smrg      return vn_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
2827ec681f3Smrg
2837ec681f3Smrg   struct vk_device_dispatch_table dispatch_table;
2847ec681f3Smrg   vk_device_dispatch_table_from_entrypoints(&dispatch_table,
2857ec681f3Smrg                                             &vn_device_entrypoints, true);
2867ec681f3Smrg   vk_device_dispatch_table_from_entrypoints(&dispatch_table,
2877ec681f3Smrg                                             &wsi_device_entrypoints, false);
2887ec681f3Smrg   result = vn_device_base_init(&dev->base, &physical_dev->base,
2897ec681f3Smrg                                &dispatch_table, pCreateInfo, alloc);
2907ec681f3Smrg   if (result != VK_SUCCESS) {
2917ec681f3Smrg      vk_free(alloc, dev);
2927ec681f3Smrg      return vn_error(instance, result);
2937ec681f3Smrg   }
2947ec681f3Smrg
2957ec681f3Smrg   dev->instance = instance;
2967ec681f3Smrg   dev->physical_device = physical_dev;
2977ec681f3Smrg   dev->renderer = instance->renderer;
2987ec681f3Smrg
2997ec681f3Smrg   VkDeviceCreateInfo local_create_info;
3007ec681f3Smrg   pCreateInfo =
3017ec681f3Smrg      vn_device_fix_create_info(dev, pCreateInfo, alloc, &local_create_info);
3027ec681f3Smrg   if (!pCreateInfo) {
3037ec681f3Smrg      result = VK_ERROR_OUT_OF_HOST_MEMORY;
3047ec681f3Smrg      goto fail;
3057ec681f3Smrg   }
3067ec681f3Smrg
3077ec681f3Smrg   VkDevice dev_handle = vn_device_to_handle(dev);
3087ec681f3Smrg   result = vn_call_vkCreateDevice(instance, physicalDevice, pCreateInfo,
3097ec681f3Smrg                                   NULL, &dev_handle);
3107ec681f3Smrg   if (result != VK_SUCCESS)
3117ec681f3Smrg      goto fail;
3127ec681f3Smrg
3137ec681f3Smrg   result = vn_device_init_queues(dev, pCreateInfo);
3147ec681f3Smrg   if (result != VK_SUCCESS) {
3157ec681f3Smrg      vn_call_vkDestroyDevice(instance, dev_handle, NULL);
3167ec681f3Smrg      goto fail;
3177ec681f3Smrg   }
3187ec681f3Smrg
3197ec681f3Smrg   for (uint32_t i = 0; i < ARRAY_SIZE(dev->memory_pools); i++) {
3207ec681f3Smrg      struct vn_device_memory_pool *pool = &dev->memory_pools[i];
3217ec681f3Smrg      mtx_init(&pool->mutex, mtx_plain);
3227ec681f3Smrg   }
3237ec681f3Smrg
3247ec681f3Smrg   if (dev->base.base.enabled_extensions
3257ec681f3Smrg          .ANDROID_external_memory_android_hardware_buffer) {
3267ec681f3Smrg      result = vn_android_init_ahb_buffer_memory_type_bits(dev);
3277ec681f3Smrg      if (result != VK_SUCCESS) {
3287ec681f3Smrg         vn_call_vkDestroyDevice(instance, dev_handle, NULL);
3297ec681f3Smrg         goto fail;
3307ec681f3Smrg      }
3317ec681f3Smrg   }
3327ec681f3Smrg
3337ec681f3Smrg   *pDevice = dev_handle;
3347ec681f3Smrg
3357ec681f3Smrg   if (pCreateInfo == &local_create_info)
3367ec681f3Smrg      vk_free(alloc, (void *)pCreateInfo->ppEnabledExtensionNames);
3377ec681f3Smrg
3387ec681f3Smrg   return VK_SUCCESS;
3397ec681f3Smrg
3407ec681f3Smrgfail:
3417ec681f3Smrg   if (pCreateInfo == &local_create_info)
3427ec681f3Smrg      vk_free(alloc, (void *)pCreateInfo->ppEnabledExtensionNames);
3437ec681f3Smrg   vn_device_base_fini(&dev->base);
3447ec681f3Smrg   vk_free(alloc, dev);
3457ec681f3Smrg   return vn_error(instance, result);
3467ec681f3Smrg}
3477ec681f3Smrg
3487ec681f3Smrgvoid
3497ec681f3Smrgvn_DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator)
3507ec681f3Smrg{
3517ec681f3Smrg   struct vn_device *dev = vn_device_from_handle(device);
3527ec681f3Smrg   const VkAllocationCallbacks *alloc =
3537ec681f3Smrg      pAllocator ? pAllocator : &dev->base.base.alloc;
3547ec681f3Smrg
3557ec681f3Smrg   if (!dev)
3567ec681f3Smrg      return;
3577ec681f3Smrg
3587ec681f3Smrg   for (uint32_t i = 0; i < ARRAY_SIZE(dev->memory_pools); i++)
3597ec681f3Smrg      vn_device_memory_pool_fini(dev, i);
3607ec681f3Smrg
3617ec681f3Smrg   for (uint32_t i = 0; i < dev->queue_count; i++)
3627ec681f3Smrg      vn_queue_fini(&dev->queues[i]);
3637ec681f3Smrg
3647ec681f3Smrg   /* We must emit vkDestroyDevice before freeing dev->queues.  Otherwise,
3657ec681f3Smrg    * another thread might reuse their object ids while they still refer to
3667ec681f3Smrg    * the queues in the renderer.
3677ec681f3Smrg    */
3687ec681f3Smrg   vn_async_vkDestroyDevice(dev->instance, device, NULL);
3697ec681f3Smrg
3707ec681f3Smrg   vk_free(alloc, dev->queues);
3717ec681f3Smrg
3727ec681f3Smrg   vn_device_base_fini(&dev->base);
3737ec681f3Smrg   vk_free(alloc, dev);
3747ec681f3Smrg}
3757ec681f3Smrg
3767ec681f3SmrgPFN_vkVoidFunction
3777ec681f3Smrgvn_GetDeviceProcAddr(VkDevice device, const char *pName)
3787ec681f3Smrg{
3797ec681f3Smrg   struct vn_device *dev = vn_device_from_handle(device);
3807ec681f3Smrg   return vk_device_get_proc_addr(&dev->base.base, pName);
3817ec681f3Smrg}
3827ec681f3Smrg
3837ec681f3Smrgvoid
3847ec681f3Smrgvn_GetDeviceGroupPeerMemoryFeatures(
3857ec681f3Smrg   VkDevice device,
3867ec681f3Smrg   uint32_t heapIndex,
3877ec681f3Smrg   uint32_t localDeviceIndex,
3887ec681f3Smrg   uint32_t remoteDeviceIndex,
3897ec681f3Smrg   VkPeerMemoryFeatureFlags *pPeerMemoryFeatures)
3907ec681f3Smrg{
3917ec681f3Smrg   struct vn_device *dev = vn_device_from_handle(device);
3927ec681f3Smrg
3937ec681f3Smrg   /* TODO get and cache the values in vkCreateDevice */
3947ec681f3Smrg   vn_call_vkGetDeviceGroupPeerMemoryFeatures(
3957ec681f3Smrg      dev->instance, device, heapIndex, localDeviceIndex, remoteDeviceIndex,
3967ec681f3Smrg      pPeerMemoryFeatures);
3977ec681f3Smrg}
3987ec681f3Smrg
3997ec681f3SmrgVkResult
4007ec681f3Smrgvn_DeviceWaitIdle(VkDevice device)
4017ec681f3Smrg{
4027ec681f3Smrg   struct vn_device *dev = vn_device_from_handle(device);
4037ec681f3Smrg
4047ec681f3Smrg   for (uint32_t i = 0; i < dev->queue_count; i++) {
4057ec681f3Smrg      struct vn_queue *queue = &dev->queues[i];
4067ec681f3Smrg      VkResult result = vn_QueueWaitIdle(vn_queue_to_handle(queue));
4077ec681f3Smrg      if (result != VK_SUCCESS)
4087ec681f3Smrg         return vn_error(dev->instance, result);
4097ec681f3Smrg   }
4107ec681f3Smrg
4117ec681f3Smrg   return VK_SUCCESS;
4127ec681f3Smrg}
413