Path: blob/21.2-virgl/src/virtio/vulkan/vn_device_memory.c
4560 views
/*1* Copyright 2019 Google LLC2* SPDX-License-Identifier: MIT3*4* based in part on anv and radv which are:5* Copyright © 2015 Intel Corporation6* Copyright © 2016 Red Hat.7* Copyright © 2016 Bas Nieuwenhuizen8*/910#include "vn_device_memory.h"1112#include "venus-protocol/vn_protocol_driver_device_memory.h"13#include "venus-protocol/vn_protocol_driver_transport.h"1415#include "vn_android.h"16#include "vn_buffer.h"17#include "vn_device.h"18#include "vn_image.h"1920/* device memory commands */2122static VkResult23vn_device_memory_simple_alloc(struct vn_device *dev,24uint32_t mem_type_index,25VkDeviceSize size,26struct vn_device_memory **out_mem)27{28const VkAllocationCallbacks *alloc = &dev->base.base.alloc;2930struct vn_device_memory *mem =31vk_zalloc(alloc, sizeof(*mem), VN_DEFAULT_ALIGN,32VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);33if (!mem)34return VK_ERROR_OUT_OF_HOST_MEMORY;3536vn_object_base_init(&mem->base, VK_OBJECT_TYPE_DEVICE_MEMORY, &dev->base);37mem->size = size;3839VkDeviceMemory mem_handle = vn_device_memory_to_handle(mem);40VkResult result = vn_call_vkAllocateMemory(41dev->instance, vn_device_to_handle(dev),42&(const VkMemoryAllocateInfo){43.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,44.allocationSize = size,45.memoryTypeIndex = mem_type_index,46},47NULL, &mem_handle);48if (result != VK_SUCCESS) {49vk_free(alloc, mem);50return result;51}5253const VkPhysicalDeviceMemoryProperties *mem_props =54&dev->physical_device->memory_properties.memoryProperties;55const VkMemoryType *mem_type = &mem_props->memoryTypes[mem_type_index];56result = vn_renderer_bo_create_from_device_memory(57dev->renderer, mem->size, mem->base.id, mem_type->propertyFlags, 0,58&mem->base_bo);59if (result != VK_SUCCESS) {60vn_async_vkFreeMemory(dev->instance, vn_device_to_handle(dev),61mem_handle, NULL);62vk_free(alloc, mem);63return result;64}65vn_instance_roundtrip(dev->instance);6667*out_mem = mem;6869return VK_SUCCESS;70}7172static void73vn_device_memory_simple_free(struct vn_device *dev,74struct vn_device_memory *mem)75{76const VkAllocationCallbacks *alloc = &dev->base.base.alloc;7778if (mem->base_bo)79vn_renderer_bo_unref(dev->renderer, mem->base_bo);8081vn_async_vkFreeMemory(dev->instance, vn_device_to_handle(dev),82vn_device_memory_to_handle(mem), NULL);83vn_object_base_fini(&mem->base);84vk_free(alloc, mem);85}8687void88vn_device_memory_pool_fini(struct vn_device *dev, uint32_t mem_type_index)89{90struct vn_device_memory_pool *pool = &dev->memory_pools[mem_type_index];91if (pool->memory)92vn_device_memory_simple_free(dev, pool->memory);93mtx_destroy(&pool->mutex);94}9596static VkResult97vn_device_memory_pool_grow_locked(struct vn_device *dev,98uint32_t mem_type_index,99VkDeviceSize size)100{101struct vn_device_memory *mem;102VkResult result =103vn_device_memory_simple_alloc(dev, mem_type_index, size, &mem);104if (result != VK_SUCCESS)105return result;106107struct vn_device_memory_pool *pool = &dev->memory_pools[mem_type_index];108if (pool->memory) {109const bool bo_destroyed =110vn_renderer_bo_unref(dev->renderer, pool->memory->base_bo);111pool->memory->base_bo = NULL;112113/* we use pool->memory's base_bo to keep it alive */114if (bo_destroyed)115vn_device_memory_simple_free(dev, pool->memory);116}117118pool->memory = mem;119pool->used = 0;120121return VK_SUCCESS;122}123124static VkResult125vn_device_memory_pool_alloc(struct vn_device *dev,126uint32_t mem_type_index,127VkDeviceSize size,128struct vn_device_memory **base_mem,129struct vn_renderer_bo **base_bo,130VkDeviceSize *base_offset)131{132const VkDeviceSize pool_size = 16 * 1024 * 1024;133/* XXX We don't know the alignment requirement. We should probably use 64K134* because some GPUs have 64K pages.135*/136const VkDeviceSize pool_align = 4096;137struct vn_device_memory_pool *pool = &dev->memory_pools[mem_type_index];138139assert(size <= pool_size);140141mtx_lock(&pool->mutex);142143if (!pool->memory || pool->used + size > pool_size) {144VkResult result =145vn_device_memory_pool_grow_locked(dev, mem_type_index, pool_size);146if (result != VK_SUCCESS) {147mtx_unlock(&pool->mutex);148return result;149}150}151152/* we use base_bo to keep base_mem alive */153*base_mem = pool->memory;154*base_bo = vn_renderer_bo_ref(dev->renderer, pool->memory->base_bo);155156*base_offset = pool->used;157pool->used += align64(size, pool_align);158159mtx_unlock(&pool->mutex);160161return VK_SUCCESS;162}163164static void165vn_device_memory_pool_free(struct vn_device *dev,166struct vn_device_memory *base_mem,167struct vn_renderer_bo *base_bo)168{169/* we use base_bo to keep base_mem alive */170if (vn_renderer_bo_unref(dev->renderer, base_bo))171vn_device_memory_simple_free(dev, base_mem);172}173174static bool175vn_device_memory_should_suballocate(const VkMemoryAllocateInfo *alloc_info,176const VkMemoryType *mem_type)177{178/* We should not support suballocations because apps can do better. But179* each BO takes up a KVM memslot currently and some CTS tests exhausts180* them. This might not be needed on newer (host) kernels where there are181* many more KVM memslots.182*/183184/* consider host-visible memory only */185if (!(mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))186return false;187188/* reject larger allocations */189if (alloc_info->allocationSize > 64 * 1024)190return false;191192/* reject if there is any pnext struct other than193* VkMemoryDedicatedAllocateInfo, or if dedicated allocation is required194*/195if (alloc_info->pNext) {196const VkMemoryDedicatedAllocateInfo *dedicated = alloc_info->pNext;197if (dedicated->sType !=198VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO ||199dedicated->pNext)200return false;201202const struct vn_image *img = vn_image_from_handle(dedicated->image);203if (img) {204for (uint32_t i = 0; i < ARRAY_SIZE(img->dedicated_requirements);205i++) {206if (img->dedicated_requirements[i].requiresDedicatedAllocation)207return false;208}209}210211const struct vn_buffer *buf = vn_buffer_from_handle(dedicated->buffer);212if (buf && buf->dedicated_requirements.requiresDedicatedAllocation)213return false;214}215216return true;217}218219VkResult220vn_device_memory_import_dma_buf(struct vn_device *dev,221struct vn_device_memory *mem,222const VkMemoryAllocateInfo *alloc_info,223int fd)224{225VkDevice device = vn_device_to_handle(dev);226VkDeviceMemory memory = vn_device_memory_to_handle(mem);227const VkPhysicalDeviceMemoryProperties *mem_props =228&dev->physical_device->memory_properties.memoryProperties;229const VkMemoryType *mem_type =230&mem_props->memoryTypes[alloc_info->memoryTypeIndex];231struct vn_renderer_bo *bo;232VkResult result = VK_SUCCESS;233234result = vn_renderer_bo_create_from_dma_buf(dev->renderer,235alloc_info->allocationSize, fd,236mem_type->propertyFlags, &bo);237if (result != VK_SUCCESS)238return result;239240vn_instance_roundtrip(dev->instance);241242/* XXX fix VkImportMemoryResourceInfoMESA to support memory planes */243const VkImportMemoryResourceInfoMESA import_memory_resource_info = {244.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_RESOURCE_INFO_MESA,245.pNext = alloc_info->pNext,246.resourceId = bo->res_id,247};248const VkMemoryAllocateInfo memory_allocate_info = {249.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,250.pNext = &import_memory_resource_info,251.allocationSize = alloc_info->allocationSize,252.memoryTypeIndex = alloc_info->memoryTypeIndex,253};254result = vn_call_vkAllocateMemory(dev->instance, device,255&memory_allocate_info, NULL, &memory);256if (result != VK_SUCCESS) {257vn_renderer_bo_unref(dev->renderer, bo);258return result;259}260261/* need to close import fd on success to avoid fd leak */262close(fd);263mem->base_bo = bo;264265return VK_SUCCESS;266}267268static VkResult269vn_device_memory_alloc(struct vn_device *dev,270struct vn_device_memory *mem,271const VkMemoryAllocateInfo *alloc_info,272bool need_bo,273VkMemoryPropertyFlags flags,274VkExternalMemoryHandleTypeFlags external_handles)275{276VkDevice dev_handle = vn_device_to_handle(dev);277VkDeviceMemory mem_handle = vn_device_memory_to_handle(mem);278VkResult result = vn_call_vkAllocateMemory(dev->instance, dev_handle,279alloc_info, NULL, &mem_handle);280if (result != VK_SUCCESS || !need_bo)281return result;282283result = vn_renderer_bo_create_from_device_memory(284dev->renderer, mem->size, mem->base.id, flags, external_handles,285&mem->base_bo);286if (result != VK_SUCCESS) {287vn_async_vkFreeMemory(dev->instance, dev_handle, mem_handle, NULL);288return result;289}290291vn_instance_roundtrip(dev->instance);292293return VK_SUCCESS;294}295296VkResult297vn_AllocateMemory(VkDevice device,298const VkMemoryAllocateInfo *pAllocateInfo,299const VkAllocationCallbacks *pAllocator,300VkDeviceMemory *pMemory)301{302struct vn_device *dev = vn_device_from_handle(device);303const VkAllocationCallbacks *alloc =304pAllocator ? pAllocator : &dev->base.base.alloc;305306const VkPhysicalDeviceMemoryProperties *mem_props =307&dev->physical_device->memory_properties.memoryProperties;308const VkMemoryType *mem_type =309&mem_props->memoryTypes[pAllocateInfo->memoryTypeIndex];310311const VkExportMemoryAllocateInfo *export_info = NULL;312const VkImportAndroidHardwareBufferInfoANDROID *import_ahb_info = NULL;313const VkImportMemoryFdInfoKHR *import_fd_info = NULL;314bool export_ahb = false;315316vk_foreach_struct_const(pnext, pAllocateInfo->pNext) {317switch (pnext->sType) {318case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:319export_info = (void *)pnext;320if (export_info->handleTypes &321VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)322export_ahb = true;323else if (!export_info->handleTypes)324export_info = NULL;325break;326case VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID:327import_ahb_info = (void *)pnext;328break;329case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:330import_fd_info = (void *)pnext;331break;332default:333break;334}335}336337struct vn_device_memory *mem =338vk_zalloc(alloc, sizeof(*mem), VN_DEFAULT_ALIGN,339VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);340if (!mem)341return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);342343vn_object_base_init(&mem->base, VK_OBJECT_TYPE_DEVICE_MEMORY, &dev->base);344mem->size = pAllocateInfo->allocationSize;345346VkDeviceMemory mem_handle = vn_device_memory_to_handle(mem);347VkResult result;348if (import_ahb_info) {349result = vn_android_device_import_ahb(dev, mem, pAllocateInfo, alloc,350import_ahb_info->buffer);351} else if (export_ahb) {352result = vn_android_device_allocate_ahb(dev, mem, pAllocateInfo, alloc);353} else if (import_fd_info) {354result = vn_device_memory_import_dma_buf(dev, mem, pAllocateInfo,355import_fd_info->fd);356} else if (export_info) {357result = vn_device_memory_alloc(dev, mem, pAllocateInfo, true,358mem_type->propertyFlags,359export_info->handleTypes);360} else if (vn_device_memory_should_suballocate(pAllocateInfo, mem_type)) {361result = vn_device_memory_pool_alloc(362dev, pAllocateInfo->memoryTypeIndex, mem->size, &mem->base_memory,363&mem->base_bo, &mem->base_offset);364} else {365const bool need_bo =366mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;367result = vn_device_memory_alloc(dev, mem, pAllocateInfo, need_bo,368mem_type->propertyFlags, 0);369}370if (result != VK_SUCCESS) {371vk_free(alloc, mem);372return vn_error(dev->instance, result);373}374375*pMemory = mem_handle;376377return VK_SUCCESS;378}379380void381vn_FreeMemory(VkDevice device,382VkDeviceMemory memory,383const VkAllocationCallbacks *pAllocator)384{385struct vn_device *dev = vn_device_from_handle(device);386struct vn_device_memory *mem = vn_device_memory_from_handle(memory);387const VkAllocationCallbacks *alloc =388pAllocator ? pAllocator : &dev->base.base.alloc;389390if (!mem)391return;392393if (mem->base_memory) {394vn_device_memory_pool_free(dev, mem->base_memory, mem->base_bo);395} else {396if (mem->base_bo)397vn_renderer_bo_unref(dev->renderer, mem->base_bo);398vn_async_vkFreeMemory(dev->instance, device, memory, NULL);399}400401if (mem->ahb)402vn_android_release_ahb(mem->ahb);403404vn_object_base_fini(&mem->base);405vk_free(alloc, mem);406}407408uint64_t409vn_GetDeviceMemoryOpaqueCaptureAddress(410VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo)411{412struct vn_device *dev = vn_device_from_handle(device);413ASSERTED struct vn_device_memory *mem =414vn_device_memory_from_handle(pInfo->memory);415416assert(!mem->base_memory);417return vn_call_vkGetDeviceMemoryOpaqueCaptureAddress(dev->instance, device,418pInfo);419}420421VkResult422vn_MapMemory(VkDevice device,423VkDeviceMemory memory,424VkDeviceSize offset,425VkDeviceSize size,426VkMemoryMapFlags flags,427void **ppData)428{429struct vn_device *dev = vn_device_from_handle(device);430struct vn_device_memory *mem = vn_device_memory_from_handle(memory);431432void *ptr = vn_renderer_bo_map(dev->renderer, mem->base_bo);433if (!ptr)434return vn_error(dev->instance, VK_ERROR_MEMORY_MAP_FAILED);435436mem->map_end = size == VK_WHOLE_SIZE ? mem->size : offset + size;437438*ppData = ptr + mem->base_offset + offset;439440return VK_SUCCESS;441}442443void444vn_UnmapMemory(VkDevice device, VkDeviceMemory memory)445{446}447448VkResult449vn_FlushMappedMemoryRanges(VkDevice device,450uint32_t memoryRangeCount,451const VkMappedMemoryRange *pMemoryRanges)452{453struct vn_device *dev = vn_device_from_handle(device);454455for (uint32_t i = 0; i < memoryRangeCount; i++) {456const VkMappedMemoryRange *range = &pMemoryRanges[i];457struct vn_device_memory *mem =458vn_device_memory_from_handle(range->memory);459460const VkDeviceSize size = range->size == VK_WHOLE_SIZE461? mem->map_end - range->offset462: range->size;463vn_renderer_bo_flush(dev->renderer, mem->base_bo,464mem->base_offset + range->offset, size);465}466467return VK_SUCCESS;468}469470VkResult471vn_InvalidateMappedMemoryRanges(VkDevice device,472uint32_t memoryRangeCount,473const VkMappedMemoryRange *pMemoryRanges)474{475struct vn_device *dev = vn_device_from_handle(device);476477for (uint32_t i = 0; i < memoryRangeCount; i++) {478const VkMappedMemoryRange *range = &pMemoryRanges[i];479struct vn_device_memory *mem =480vn_device_memory_from_handle(range->memory);481482const VkDeviceSize size = range->size == VK_WHOLE_SIZE483? mem->map_end - range->offset484: range->size;485vn_renderer_bo_invalidate(dev->renderer, mem->base_bo,486mem->base_offset + range->offset, size);487}488489return VK_SUCCESS;490}491492void493vn_GetDeviceMemoryCommitment(VkDevice device,494VkDeviceMemory memory,495VkDeviceSize *pCommittedMemoryInBytes)496{497struct vn_device *dev = vn_device_from_handle(device);498ASSERTED struct vn_device_memory *mem =499vn_device_memory_from_handle(memory);500501assert(!mem->base_memory);502vn_call_vkGetDeviceMemoryCommitment(dev->instance, device, memory,503pCommittedMemoryInBytes);504}505506VkResult507vn_GetMemoryFdKHR(VkDevice device,508const VkMemoryGetFdInfoKHR *pGetFdInfo,509int *pFd)510{511struct vn_device *dev = vn_device_from_handle(device);512struct vn_device_memory *mem =513vn_device_memory_from_handle(pGetFdInfo->memory);514515/* At the moment, we support only the below handle types. */516assert(pGetFdInfo->handleType &517(VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |518VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT));519assert(!mem->base_memory && mem->base_bo);520*pFd = vn_renderer_bo_export_dma_buf(dev->renderer, mem->base_bo);521if (*pFd < 0)522return vn_error(dev->instance, VK_ERROR_TOO_MANY_OBJECTS);523524return VK_SUCCESS;525}526527VkResult528vn_get_memory_dma_buf_properties(struct vn_device *dev,529int fd,530uint64_t *out_alloc_size,531uint32_t *out_mem_type_bits)532{533VkDevice device = vn_device_to_handle(dev);534struct vn_renderer_bo *bo = NULL;535VkResult result = VK_SUCCESS;536537result = vn_renderer_bo_create_from_dma_buf(dev->renderer, 0 /* size */,538fd, 0 /* flags */, &bo);539if (result != VK_SUCCESS)540return result;541542vn_instance_roundtrip(dev->instance);543544VkMemoryResourceAllocationSizeProperties100000MESA alloc_size_props = {545.sType =546VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA,547.pNext = NULL,548.allocationSize = 0,549};550VkMemoryResourcePropertiesMESA props = {551.sType = VK_STRUCTURE_TYPE_MEMORY_RESOURCE_PROPERTIES_MESA,552.pNext =553dev->instance->experimental.memoryResourceAllocationSize == VK_TRUE554? &alloc_size_props555: NULL,556.memoryTypeBits = 0,557};558result = vn_call_vkGetMemoryResourcePropertiesMESA(dev->instance, device,559bo->res_id, &props);560vn_renderer_bo_unref(dev->renderer, bo);561if (result != VK_SUCCESS)562return result;563564*out_alloc_size = alloc_size_props.allocationSize;565*out_mem_type_bits = props.memoryTypeBits;566567return VK_SUCCESS;568}569570VkResult571vn_GetMemoryFdPropertiesKHR(VkDevice device,572VkExternalMemoryHandleTypeFlagBits handleType,573int fd,574VkMemoryFdPropertiesKHR *pMemoryFdProperties)575{576struct vn_device *dev = vn_device_from_handle(device);577uint64_t alloc_size = 0;578uint32_t mem_type_bits = 0;579VkResult result = VK_SUCCESS;580581if (handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)582return vn_error(dev->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);583584result =585vn_get_memory_dma_buf_properties(dev, fd, &alloc_size, &mem_type_bits);586if (result != VK_SUCCESS)587return vn_error(dev->instance, result);588589pMemoryFdProperties->memoryTypeBits = mem_type_bits;590591return VK_SUCCESS;592}593594595