Home | History | Annotate | Line # | Download | only in vulkan
      1 /*
      2  * Copyright 2019 Google LLC
      3  * SPDX-License-Identifier: MIT
      4  *
      5  * based in part on anv and radv which are:
      6  * Copyright  2015 Intel Corporation
      7  * Copyright  2016 Red Hat.
      8  * Copyright  2016 Bas Nieuwenhuizen
      9  */
     10 
     11 #include "vn_device_memory.h"
     12 
     13 #include "venus-protocol/vn_protocol_driver_device_memory.h"
     14 #include "venus-protocol/vn_protocol_driver_transport.h"
     15 
     16 #include "vn_android.h"
     17 #include "vn_buffer.h"
     18 #include "vn_device.h"
     19 #include "vn_image.h"
     20 #include "vn_physical_device.h"
     21 
     22 /* device memory commands */
     23 
     24 static VkResult
     25 vn_device_memory_simple_alloc(struct vn_device *dev,
     26                               uint32_t mem_type_index,
     27                               VkDeviceSize size,
     28                               struct vn_device_memory **out_mem)
     29 {
     30    const VkAllocationCallbacks *alloc = &dev->base.base.alloc;
     31 
     32    struct vn_device_memory *mem =
     33       vk_zalloc(alloc, sizeof(*mem), VN_DEFAULT_ALIGN,
     34                 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
     35    if (!mem)
     36       return VK_ERROR_OUT_OF_HOST_MEMORY;
     37 
     38    vn_object_base_init(&mem->base, VK_OBJECT_TYPE_DEVICE_MEMORY, &dev->base);
     39    mem->size = size;
     40 
     41    VkDeviceMemory mem_handle = vn_device_memory_to_handle(mem);
     42    VkResult result = vn_call_vkAllocateMemory(
     43       dev->instance, vn_device_to_handle(dev),
     44       &(const VkMemoryAllocateInfo){
     45          .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
     46          .allocationSize = size,
     47          .memoryTypeIndex = mem_type_index,
     48       },
     49       NULL, &mem_handle);
     50    if (result != VK_SUCCESS) {
     51       vn_object_base_fini(&mem->base);
     52       vk_free(alloc, mem);
     53       return result;
     54    }
     55 
     56    const VkPhysicalDeviceMemoryProperties *mem_props =
     57       &dev->physical_device->memory_properties.memoryProperties;
     58    const VkMemoryType *mem_type = &mem_props->memoryTypes[mem_type_index];
     59    result = vn_renderer_bo_create_from_device_memory(
     60       dev->renderer, mem->size, mem->base.id, mem_type->propertyFlags, 0,
     61       &mem->base_bo);
     62    if (result != VK_SUCCESS) {
     63       vn_async_vkFreeMemory(dev->instance, vn_device_to_handle(dev),
     64                             mem_handle, NULL);
     65       vn_object_base_fini(&mem->base);
     66       vk_free(alloc, mem);
     67       return result;
     68    }
     69    vn_instance_roundtrip(dev->instance);
     70 
     71    *out_mem = mem;
     72 
     73    return VK_SUCCESS;
     74 }
     75 
     76 static void
     77 vn_device_memory_simple_free(struct vn_device *dev,
     78                              struct vn_device_memory *mem)
     79 {
     80    const VkAllocationCallbacks *alloc = &dev->base.base.alloc;
     81 
     82    if (mem->base_bo)
     83       vn_renderer_bo_unref(dev->renderer, mem->base_bo);
     84 
     85    vn_async_vkFreeMemory(dev->instance, vn_device_to_handle(dev),
     86                          vn_device_memory_to_handle(mem), NULL);
     87    vn_object_base_fini(&mem->base);
     88    vk_free(alloc, mem);
     89 }
     90 
     91 void
     92 vn_device_memory_pool_fini(struct vn_device *dev, uint32_t mem_type_index)
     93 {
     94    struct vn_device_memory_pool *pool = &dev->memory_pools[mem_type_index];
     95    if (pool->memory)
     96       vn_device_memory_simple_free(dev, pool->memory);
     97    mtx_destroy(&pool->mutex);
     98 }
     99 
    100 static VkResult
    101 vn_device_memory_pool_grow_locked(struct vn_device *dev,
    102                                   uint32_t mem_type_index,
    103                                   VkDeviceSize size)
    104 {
    105    struct vn_device_memory *mem;
    106    VkResult result =
    107       vn_device_memory_simple_alloc(dev, mem_type_index, size, &mem);
    108    if (result != VK_SUCCESS)
    109       return result;
    110 
    111    struct vn_device_memory_pool *pool = &dev->memory_pools[mem_type_index];
    112    if (pool->memory) {
    113       const bool bo_destroyed =
    114          vn_renderer_bo_unref(dev->renderer, pool->memory->base_bo);
    115       pool->memory->base_bo = NULL;
    116 
    117       /* we use pool->memory's base_bo to keep it alive */
    118       if (bo_destroyed)
    119          vn_device_memory_simple_free(dev, pool->memory);
    120    }
    121 
    122    pool->memory = mem;
    123    pool->used = 0;
    124 
    125    return VK_SUCCESS;
    126 }
    127 
    128 static VkResult
    129 vn_device_memory_pool_alloc(struct vn_device *dev,
    130                             uint32_t mem_type_index,
    131                             VkDeviceSize size,
    132                             struct vn_device_memory **base_mem,
    133                             struct vn_renderer_bo **base_bo,
    134                             VkDeviceSize *base_offset)
    135 {
    136    const VkDeviceSize pool_size = 16 * 1024 * 1024;
    137    /* XXX We don't know the alignment requirement.  We should probably use 64K
    138     * because some GPUs have 64K pages.
    139     */
    140    const VkDeviceSize pool_align = 4096;
    141    struct vn_device_memory_pool *pool = &dev->memory_pools[mem_type_index];
    142 
    143    assert(size <= pool_size);
    144 
    145    mtx_lock(&pool->mutex);
    146 
    147    if (!pool->memory || pool->used + size > pool_size) {
    148       VkResult result =
    149          vn_device_memory_pool_grow_locked(dev, mem_type_index, pool_size);
    150       if (result != VK_SUCCESS) {
    151          mtx_unlock(&pool->mutex);
    152          return result;
    153       }
    154    }
    155 
    156    /* we use base_bo to keep base_mem alive */
    157    *base_mem = pool->memory;
    158    *base_bo = vn_renderer_bo_ref(dev->renderer, pool->memory->base_bo);
    159 
    160    *base_offset = pool->used;
    161    pool->used += align64(size, pool_align);
    162 
    163    mtx_unlock(&pool->mutex);
    164 
    165    return VK_SUCCESS;
    166 }
    167 
    168 static void
    169 vn_device_memory_pool_free(struct vn_device *dev,
    170                            struct vn_device_memory *base_mem,
    171                            struct vn_renderer_bo *base_bo)
    172 {
    173    /* we use base_bo to keep base_mem alive */
    174    if (vn_renderer_bo_unref(dev->renderer, base_bo))
    175       vn_device_memory_simple_free(dev, base_mem);
    176 }
    177 
    178 static bool
    179 vn_device_memory_should_suballocate(const VkMemoryAllocateInfo *alloc_info,
    180                                     const VkMemoryType *mem_type)
    181 {
    182    /* We should not support suballocations because apps can do better.  But
    183     * each BO takes up a KVM memslot currently and some CTS tests exhausts
    184     * them.  This might not be needed on newer (host) kernels where there are
    185     * many more KVM memslots.
    186     */
    187 
    188    /* consider host-visible memory only */
    189    if (!(mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
    190       return false;
    191 
    192    /* reject larger allocations */
    193    if (alloc_info->allocationSize > 64 * 1024)
    194       return false;
    195 
    196    /* reject if there is any pnext struct other than
    197     * VkMemoryDedicatedAllocateInfo, or if dedicated allocation is required
    198     */
    199    if (alloc_info->pNext) {
    200       const VkMemoryDedicatedAllocateInfo *dedicated = alloc_info->pNext;
    201       if (dedicated->sType !=
    202              VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO ||
    203           dedicated->pNext)
    204          return false;
    205 
    206       const struct vn_image *img = vn_image_from_handle(dedicated->image);
    207       if (img) {
    208          for (uint32_t i = 0; i < ARRAY_SIZE(img->dedicated_requirements);
    209               i++) {
    210             if (img->dedicated_requirements[i].requiresDedicatedAllocation)
    211                return false;
    212          }
    213       }
    214 
    215       const struct vn_buffer *buf = vn_buffer_from_handle(dedicated->buffer);
    216       if (buf && buf->dedicated_requirements.requiresDedicatedAllocation)
    217          return false;
    218    }
    219 
    220    return true;
    221 }
    222 
    223 VkResult
    224 vn_device_memory_import_dma_buf(struct vn_device *dev,
    225                                 struct vn_device_memory *mem,
    226                                 const VkMemoryAllocateInfo *alloc_info,
    227                                 bool force_unmappable,
    228                                 int fd)
    229 {
    230    VkDevice device = vn_device_to_handle(dev);
    231    VkDeviceMemory memory = vn_device_memory_to_handle(mem);
    232    const VkPhysicalDeviceMemoryProperties *mem_props =
    233       &dev->physical_device->memory_properties.memoryProperties;
    234    VkMemoryPropertyFlags mem_flags =
    235       mem_props->memoryTypes[alloc_info->memoryTypeIndex].propertyFlags;
    236    struct vn_renderer_bo *bo;
    237    VkResult result = VK_SUCCESS;
    238 
    239    if (force_unmappable)
    240       mem_flags &= ~VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    241 
    242    result = vn_renderer_bo_create_from_dma_buf(
    243       dev->renderer, alloc_info->allocationSize, fd, mem_flags, &bo);
    244    if (result != VK_SUCCESS)
    245       return result;
    246 
    247    vn_instance_roundtrip(dev->instance);
    248 
    249    /* XXX fix VkImportMemoryResourceInfoMESA to support memory planes */
    250    const VkImportMemoryResourceInfoMESA import_memory_resource_info = {
    251       .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_RESOURCE_INFO_MESA,
    252       .pNext = alloc_info->pNext,
    253       .resourceId = bo->res_id,
    254    };
    255    const VkMemoryAllocateInfo memory_allocate_info = {
    256       .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
    257       .pNext = &import_memory_resource_info,
    258       .allocationSize = alloc_info->allocationSize,
    259       .memoryTypeIndex = alloc_info->memoryTypeIndex,
    260    };
    261    result = vn_call_vkAllocateMemory(dev->instance, device,
    262                                      &memory_allocate_info, NULL, &memory);
    263    if (result != VK_SUCCESS) {
    264       vn_renderer_bo_unref(dev->renderer, bo);
    265       return result;
    266    }
    267 
    268    /* need to close import fd on success to avoid fd leak */
    269    close(fd);
    270    mem->base_bo = bo;
    271 
    272    return VK_SUCCESS;
    273 }
    274 
    275 static VkResult
    276 vn_device_memory_alloc(struct vn_device *dev,
    277                        struct vn_device_memory *mem,
    278                        const VkMemoryAllocateInfo *alloc_info,
    279                        bool need_bo,
    280                        VkMemoryPropertyFlags flags,
    281                        VkExternalMemoryHandleTypeFlags external_handles)
    282 {
    283    VkDevice dev_handle = vn_device_to_handle(dev);
    284    VkDeviceMemory mem_handle = vn_device_memory_to_handle(mem);
    285    VkResult result = vn_call_vkAllocateMemory(dev->instance, dev_handle,
    286                                               alloc_info, NULL, &mem_handle);
    287    if (result != VK_SUCCESS || !need_bo)
    288       return result;
    289 
    290    result = vn_renderer_bo_create_from_device_memory(
    291       dev->renderer, mem->size, mem->base.id, flags, external_handles,
    292       &mem->base_bo);
    293    if (result != VK_SUCCESS) {
    294       vn_async_vkFreeMemory(dev->instance, dev_handle, mem_handle, NULL);
    295       return result;
    296    }
    297 
    298    vn_instance_roundtrip(dev->instance);
    299 
    300    return VK_SUCCESS;
    301 }
    302 
    303 VkResult
    304 vn_AllocateMemory(VkDevice device,
    305                   const VkMemoryAllocateInfo *pAllocateInfo,
    306                   const VkAllocationCallbacks *pAllocator,
    307                   VkDeviceMemory *pMemory)
    308 {
    309    struct vn_device *dev = vn_device_from_handle(device);
    310    const VkAllocationCallbacks *alloc =
    311       pAllocator ? pAllocator : &dev->base.base.alloc;
    312 
    313    const VkPhysicalDeviceMemoryProperties *mem_props =
    314       &dev->physical_device->memory_properties.memoryProperties;
    315    const VkMemoryType *mem_type =
    316       &mem_props->memoryTypes[pAllocateInfo->memoryTypeIndex];
    317 
    318    const VkExportMemoryAllocateInfo *export_info = NULL;
    319    const VkImportAndroidHardwareBufferInfoANDROID *import_ahb_info = NULL;
    320    const VkImportMemoryFdInfoKHR *import_fd_info = NULL;
    321    bool export_ahb = false;
    322 
    323    vk_foreach_struct_const(pnext, pAllocateInfo->pNext) {
    324       switch (pnext->sType) {
    325       case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
    326          export_info = (void *)pnext;
    327          if (export_info->handleTypes &
    328              VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
    329             export_ahb = true;
    330          else if (!export_info->handleTypes)
    331             export_info = NULL;
    332          break;
    333       case VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID:
    334          import_ahb_info = (void *)pnext;
    335          break;
    336       case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:
    337          import_fd_info = (void *)pnext;
    338          break;
    339       default:
    340          break;
    341       }
    342    }
    343 
    344    struct vn_device_memory *mem =
    345       vk_zalloc(alloc, sizeof(*mem), VN_DEFAULT_ALIGN,
    346                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    347    if (!mem)
    348       return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
    349 
    350    vn_object_base_init(&mem->base, VK_OBJECT_TYPE_DEVICE_MEMORY, &dev->base);
    351    mem->size = pAllocateInfo->allocationSize;
    352 
    353    VkDeviceMemory mem_handle = vn_device_memory_to_handle(mem);
    354    VkResult result;
    355    if (import_ahb_info) {
    356       result = vn_android_device_import_ahb(dev, mem, pAllocateInfo, alloc,
    357                                             import_ahb_info->buffer);
    358    } else if (export_ahb) {
    359       result = vn_android_device_allocate_ahb(dev, mem, pAllocateInfo, alloc);
    360    } else if (import_fd_info) {
    361       result = vn_device_memory_import_dma_buf(dev, mem, pAllocateInfo, false,
    362                                                import_fd_info->fd);
    363    } else if (export_info) {
    364       result = vn_device_memory_alloc(dev, mem, pAllocateInfo, true,
    365                                       mem_type->propertyFlags,
    366                                       export_info->handleTypes);
    367    } else if (vn_device_memory_should_suballocate(pAllocateInfo, mem_type)) {
    368       result = vn_device_memory_pool_alloc(
    369          dev, pAllocateInfo->memoryTypeIndex, mem->size, &mem->base_memory,
    370          &mem->base_bo, &mem->base_offset);
    371    } else {
    372       const bool need_bo =
    373          mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
    374       result = vn_device_memory_alloc(dev, mem, pAllocateInfo, need_bo,
    375                                       mem_type->propertyFlags, 0);
    376    }
    377    if (result != VK_SUCCESS) {
    378       vn_object_base_fini(&mem->base);
    379       vk_free(alloc, mem);
    380       return vn_error(dev->instance, result);
    381    }
    382 
    383    *pMemory = mem_handle;
    384 
    385    return VK_SUCCESS;
    386 }
    387 
    388 void
    389 vn_FreeMemory(VkDevice device,
    390               VkDeviceMemory memory,
    391               const VkAllocationCallbacks *pAllocator)
    392 {
    393    struct vn_device *dev = vn_device_from_handle(device);
    394    struct vn_device_memory *mem = vn_device_memory_from_handle(memory);
    395    const VkAllocationCallbacks *alloc =
    396       pAllocator ? pAllocator : &dev->base.base.alloc;
    397 
    398    if (!mem)
    399       return;
    400 
    401    if (mem->base_memory) {
    402       vn_device_memory_pool_free(dev, mem->base_memory, mem->base_bo);
    403    } else {
    404       if (mem->base_bo)
    405          vn_renderer_bo_unref(dev->renderer, mem->base_bo);
    406       vn_async_vkFreeMemory(dev->instance, device, memory, NULL);
    407    }
    408 
    409    if (mem->ahb)
    410       vn_android_release_ahb(mem->ahb);
    411 
    412    vn_object_base_fini(&mem->base);
    413    vk_free(alloc, mem);
    414 }
    415 
    416 uint64_t
    417 vn_GetDeviceMemoryOpaqueCaptureAddress(
    418    VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo)
    419 {
    420    struct vn_device *dev = vn_device_from_handle(device);
    421    ASSERTED struct vn_device_memory *mem =
    422       vn_device_memory_from_handle(pInfo->memory);
    423 
    424    assert(!mem->base_memory);
    425    return vn_call_vkGetDeviceMemoryOpaqueCaptureAddress(dev->instance, device,
    426                                                         pInfo);
    427 }
    428 
    429 VkResult
    430 vn_MapMemory(VkDevice device,
    431              VkDeviceMemory memory,
    432              VkDeviceSize offset,
    433              VkDeviceSize size,
    434              VkMemoryMapFlags flags,
    435              void **ppData)
    436 {
    437    struct vn_device *dev = vn_device_from_handle(device);
    438    struct vn_device_memory *mem = vn_device_memory_from_handle(memory);
    439 
    440    void *ptr = vn_renderer_bo_map(dev->renderer, mem->base_bo);
    441    if (!ptr)
    442       return vn_error(dev->instance, VK_ERROR_MEMORY_MAP_FAILED);
    443 
    444    mem->map_end = size == VK_WHOLE_SIZE ? mem->size : offset + size;
    445 
    446    *ppData = ptr + mem->base_offset + offset;
    447 
    448    return VK_SUCCESS;
    449 }
    450 
    451 void
    452 vn_UnmapMemory(VkDevice device, VkDeviceMemory memory)
    453 {
    454 }
    455 
    456 VkResult
    457 vn_FlushMappedMemoryRanges(VkDevice device,
    458                            uint32_t memoryRangeCount,
    459                            const VkMappedMemoryRange *pMemoryRanges)
    460 {
    461    struct vn_device *dev = vn_device_from_handle(device);
    462 
    463    for (uint32_t i = 0; i < memoryRangeCount; i++) {
    464       const VkMappedMemoryRange *range = &pMemoryRanges[i];
    465       struct vn_device_memory *mem =
    466          vn_device_memory_from_handle(range->memory);
    467 
    468       const VkDeviceSize size = range->size == VK_WHOLE_SIZE
    469                                    ? mem->map_end - range->offset
    470                                    : range->size;
    471       vn_renderer_bo_flush(dev->renderer, mem->base_bo,
    472                            mem->base_offset + range->offset, size);
    473    }
    474 
    475    return VK_SUCCESS;
    476 }
    477 
    478 VkResult
    479 vn_InvalidateMappedMemoryRanges(VkDevice device,
    480                                 uint32_t memoryRangeCount,
    481                                 const VkMappedMemoryRange *pMemoryRanges)
    482 {
    483    struct vn_device *dev = vn_device_from_handle(device);
    484 
    485    for (uint32_t i = 0; i < memoryRangeCount; i++) {
    486       const VkMappedMemoryRange *range = &pMemoryRanges[i];
    487       struct vn_device_memory *mem =
    488          vn_device_memory_from_handle(range->memory);
    489 
    490       const VkDeviceSize size = range->size == VK_WHOLE_SIZE
    491                                    ? mem->map_end - range->offset
    492                                    : range->size;
    493       vn_renderer_bo_invalidate(dev->renderer, mem->base_bo,
    494                                 mem->base_offset + range->offset, size);
    495    }
    496 
    497    return VK_SUCCESS;
    498 }
    499 
    500 void
    501 vn_GetDeviceMemoryCommitment(VkDevice device,
    502                              VkDeviceMemory memory,
    503                              VkDeviceSize *pCommittedMemoryInBytes)
    504 {
    505    struct vn_device *dev = vn_device_from_handle(device);
    506    ASSERTED struct vn_device_memory *mem =
    507       vn_device_memory_from_handle(memory);
    508 
    509    assert(!mem->base_memory);
    510    vn_call_vkGetDeviceMemoryCommitment(dev->instance, device, memory,
    511                                        pCommittedMemoryInBytes);
    512 }
    513 
    514 VkResult
    515 vn_GetMemoryFdKHR(VkDevice device,
    516                   const VkMemoryGetFdInfoKHR *pGetFdInfo,
    517                   int *pFd)
    518 {
    519    struct vn_device *dev = vn_device_from_handle(device);
    520    struct vn_device_memory *mem =
    521       vn_device_memory_from_handle(pGetFdInfo->memory);
    522 
    523    /* At the moment, we support only the below handle types. */
    524    assert(pGetFdInfo->handleType &
    525           (VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
    526            VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT));
    527    assert(!mem->base_memory && mem->base_bo);
    528    *pFd = vn_renderer_bo_export_dma_buf(dev->renderer, mem->base_bo);
    529    if (*pFd < 0)
    530       return vn_error(dev->instance, VK_ERROR_TOO_MANY_OBJECTS);
    531 
    532    return VK_SUCCESS;
    533 }
    534 
    535 VkResult
    536 vn_get_memory_dma_buf_properties(struct vn_device *dev,
    537                                  int fd,
    538                                  uint64_t *out_alloc_size,
    539                                  uint32_t *out_mem_type_bits)
    540 {
    541    VkDevice device = vn_device_to_handle(dev);
    542    struct vn_renderer_bo *bo = NULL;
    543    VkResult result = VK_SUCCESS;
    544 
    545    result = vn_renderer_bo_create_from_dma_buf(dev->renderer, 0 /* size */,
    546                                                fd, 0 /* flags */, &bo);
    547    if (result != VK_SUCCESS)
    548       return result;
    549 
    550    vn_instance_roundtrip(dev->instance);
    551 
    552    VkMemoryResourceAllocationSizeProperties100000MESA alloc_size_props = {
    553       .sType =
    554          VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA,
    555       .pNext = NULL,
    556       .allocationSize = 0,
    557    };
    558    VkMemoryResourcePropertiesMESA props = {
    559       .sType = VK_STRUCTURE_TYPE_MEMORY_RESOURCE_PROPERTIES_MESA,
    560       .pNext =
    561          dev->instance->experimental.memoryResourceAllocationSize == VK_TRUE
    562             ? &alloc_size_props
    563             : NULL,
    564       .memoryTypeBits = 0,
    565    };
    566    result = vn_call_vkGetMemoryResourcePropertiesMESA(dev->instance, device,
    567                                                       bo->res_id, &props);
    568    vn_renderer_bo_unref(dev->renderer, bo);
    569    if (result != VK_SUCCESS)
    570       return result;
    571 
    572    *out_alloc_size = alloc_size_props.allocationSize;
    573    *out_mem_type_bits = props.memoryTypeBits;
    574 
    575    return VK_SUCCESS;
    576 }
    577 
    578 VkResult
    579 vn_GetMemoryFdPropertiesKHR(VkDevice device,
    580                             VkExternalMemoryHandleTypeFlagBits handleType,
    581                             int fd,
    582                             VkMemoryFdPropertiesKHR *pMemoryFdProperties)
    583 {
    584    struct vn_device *dev = vn_device_from_handle(device);
    585    uint64_t alloc_size = 0;
    586    uint32_t mem_type_bits = 0;
    587    VkResult result = VK_SUCCESS;
    588 
    589    if (handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)
    590       return vn_error(dev->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
    591 
    592    result =
    593       vn_get_memory_dma_buf_properties(dev, fd, &alloc_size, &mem_type_bits);
    594    if (result != VK_SUCCESS)
    595       return vn_error(dev->instance, result);
    596 
    597    pMemoryFdProperties->memoryTypeBits = mem_type_bits;
    598 
    599    return VK_SUCCESS;
    600 }
    601