diff --git a/src/virtio/vulkan/vn_device_memory.c b/src/virtio/vulkan/vn_device_memory.c index 2d9c9b92c33..62125cfb2ce 100644 --- a/src/virtio/vulkan/vn_device_memory.c +++ b/src/virtio/vulkan/vn_device_memory.c @@ -189,9 +189,16 @@ vn_device_memory_pool_suballocate(struct vn_device *dev, } static bool -vn_device_memory_should_suballocate(const VkMemoryAllocateInfo *alloc_info, +vn_device_memory_should_suballocate(const struct vn_device *dev, + const VkMemoryAllocateInfo *alloc_info, const VkMemoryPropertyFlags flags) { + const struct vn_instance *instance = dev->physical_device->instance; + const struct vn_renderer_info *renderer = &instance->renderer->info; + + if (renderer->has_guest_vram) + return false; + /* We should not support suballocations because apps can do better. But * each BO takes up a KVM memslot currently and some CTS tests exhausts * them. This might not be needed on newer (host) kernels where there are @@ -285,15 +292,71 @@ vn_device_memory_import_dma_buf(struct vn_device *dev, } static VkResult -vn_device_memory_alloc(struct vn_device *dev, - struct vn_device_memory *mem, - const VkMemoryAllocateInfo *alloc_info, - VkExternalMemoryHandleTypeFlags external_handles) +vn_device_memory_alloc_guest_vram( + struct vn_device *dev, + struct vn_device_memory *mem, + const VkMemoryAllocateInfo *alloc_info, + VkExternalMemoryHandleTypeFlags external_handles) { VkDevice dev_handle = vn_device_to_handle(dev); VkDeviceMemory mem_handle = vn_device_memory_to_handle(mem); - VkResult result = vn_call_vkAllocateMemory(dev->instance, dev_handle, - alloc_info, NULL, &mem_handle); + VkResult result = VK_SUCCESS; + + result = vn_renderer_bo_create_from_device_memory( + dev->renderer, mem->size, 0, mem->flags, external_handles, + &mem->base_bo); + if (result != VK_SUCCESS) { + return result; + } + + const VkImportMemoryResourceInfoMESA import_memory_resource_info = { + .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_RESOURCE_INFO_MESA, + .pNext = alloc_info->pNext, + .resourceId = mem->base_bo->res_id, + }; + + const VkMemoryAllocateInfo memory_allocate_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &import_memory_resource_info, + .allocationSize = alloc_info->allocationSize, + .memoryTypeIndex = alloc_info->memoryTypeIndex, + }; + + vn_instance_roundtrip(dev->instance); + + result = vn_call_vkAllocateMemory( + dev->instance, dev_handle, &memory_allocate_info, NULL, &mem_handle); + if (result != VK_SUCCESS) { + vn_renderer_bo_unref(dev->renderer, mem->base_bo); + return result; + } + + result = + vn_instance_submit_roundtrip(dev->instance, &mem->bo_roundtrip_seqno); + if (result != VK_SUCCESS) { + vn_renderer_bo_unref(dev->renderer, mem->base_bo); + vn_async_vkFreeMemory(dev->instance, dev_handle, mem_handle, NULL); + return result; + } + + mem->bo_roundtrip_seqno_valid = true; + + return VK_SUCCESS; +} + +static VkResult +vn_device_memory_alloc_generic( + struct vn_device *dev, + struct vn_device_memory *mem, + const VkMemoryAllocateInfo *alloc_info, + VkExternalMemoryHandleTypeFlags external_handles) +{ + VkDevice dev_handle = vn_device_to_handle(dev); + VkDeviceMemory mem_handle = vn_device_memory_to_handle(mem); + VkResult result = VK_SUCCESS; + + result = vn_call_vkAllocateMemory(dev->instance, dev_handle, alloc_info, + NULL, &mem_handle); if (result != VK_SUCCESS || !external_handles) return result; @@ -318,6 +381,24 @@ vn_device_memory_alloc(struct vn_device *dev, return VK_SUCCESS; } +static VkResult +vn_device_memory_alloc(struct vn_device *dev, + struct vn_device_memory *mem, + const VkMemoryAllocateInfo *alloc_info, + VkExternalMemoryHandleTypeFlags external_handles) +{ + const struct vn_instance *instance = dev->physical_device->instance; + const struct vn_renderer_info *renderer_info = &instance->renderer->info; + + if (renderer_info->has_guest_vram) { + return vn_device_memory_alloc_guest_vram(dev, mem, alloc_info, + external_handles); + } + + return vn_device_memory_alloc_generic(dev, mem, alloc_info, + external_handles); +} + VkResult vn_AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, @@ -382,7 +463,8 @@ vn_AllocateMemory(VkDevice device, } else if (export_info) { result = vn_device_memory_alloc(dev, mem, pAllocateInfo, export_info->handleTypes); - } else if (vn_device_memory_should_suballocate(pAllocateInfo, mem_flags)) { + } else if (vn_device_memory_should_suballocate(dev, pAllocateInfo, + mem_flags)) { result = vn_device_memory_pool_suballocate( dev, mem, pAllocateInfo->memoryTypeIndex); } else { diff --git a/src/virtio/vulkan/vn_renderer.h b/src/virtio/vulkan/vn_renderer.h index e34f14cbef0..5bf4d1217a8 100644 --- a/src/virtio/vulkan/vn_renderer.h +++ b/src/virtio/vulkan/vn_renderer.h @@ -56,6 +56,7 @@ struct vn_renderer_info { bool has_cache_management; bool has_external_sync; bool has_implicit_fencing; + bool has_guest_vram; uint32_t max_sync_queue_count; diff --git a/src/virtio/vulkan/vn_renderer_virtgpu.c b/src/virtio/vulkan/vn_renderer_virtgpu.c index bf1d5f3b1e8..25ccec4b8af 100644 --- a/src/virtio/vulkan/vn_renderer_virtgpu.c +++ b/src/virtio/vulkan/vn_renderer_virtgpu.c @@ -41,6 +41,15 @@ struct drm_virtgpu_context_init { #define VIRTGPU_PARAM_MAX_SYNC_QUEUE_COUNT 100 #endif /* VIRTGPU_PARAM_MAX_SYNC_QUEUE_COUNT */ +#ifndef VIRTGPU_PARAM_GUEST_VRAM +/* All guest allocations happen via virtgpu dedicated heap. */ +#define VIRTGPU_PARAM_GUEST_VRAM 9 +#endif + +#ifndef VIRTGPU_BLOB_MEM_GUEST_VRAM +#define VIRTGPU_BLOB_MEM_GUEST_VRAM 0x0004 +#endif + /* XXX comment these out to really use kernel uapi */ #define SIMULATE_BO_SIZE_FIX 1 //#define SIMULATE_CONTEXT_INIT 1 @@ -104,6 +113,7 @@ struct virtgpu { } capset; uint32_t shmem_blob_mem; + uint32_t bo_blob_mem; /* note that we use gem_handle instead of res_id to index because * res_id is monotonically increasing by default (see @@ -1175,8 +1185,8 @@ virtgpu_bo_create_from_dma_buf(struct vn_renderer *renderer, uint32_t blob_flags; size_t mmap_size; if (info.blob_mem) { - /* must be VIRTGPU_BLOB_MEM_HOST3D */ - if (info.blob_mem != VIRTGPU_BLOB_MEM_HOST3D) + /* must be VIRTGPU_BLOB_MEM_HOST3D or VIRTGPU_BLOB_MEM_GUEST_VRAM */ + if (info.blob_mem != gpu->bo_blob_mem) goto fail; /* blob_flags is not passed to the kernel and is only for internal use @@ -1254,7 +1264,7 @@ virtgpu_bo_create_from_device_memory( uint32_t res_id; uint32_t gem_handle = virtgpu_ioctl_resource_create_blob( - gpu, VIRTGPU_BLOB_MEM_HOST3D, blob_flags, size, mem_id, &res_id); + gpu, gpu->bo_blob_mem, blob_flags, size, mem_id, &res_id); if (!gem_handle) return VK_ERROR_OUT_OF_DEVICE_MEMORY; @@ -1398,6 +1408,9 @@ virtgpu_init_renderer_info(struct virtgpu *gpu) info->vk_mesa_venus_protocol_spec_version = capset->vk_mesa_venus_protocol_spec_version; info->supports_blob_id_0 = capset->supports_blob_id_0; + + if (gpu->bo_blob_mem == VIRTGPU_BLOB_MEM_GUEST_VRAM) + info->has_guest_vram = true; } static void @@ -1487,8 +1500,8 @@ virtgpu_init_params(struct virtgpu *gpu) { const uint64_t required_params[] = { VIRTGPU_PARAM_3D_FEATURES, VIRTGPU_PARAM_CAPSET_QUERY_FIX, - VIRTGPU_PARAM_RESOURCE_BLOB, VIRTGPU_PARAM_HOST_VISIBLE, - VIRTGPU_PARAM_CROSS_DEVICE, VIRTGPU_PARAM_CONTEXT_INIT, + VIRTGPU_PARAM_RESOURCE_BLOB, VIRTGPU_PARAM_CROSS_DEVICE, + VIRTGPU_PARAM_CONTEXT_INIT, }; uint64_t val; for (uint32_t i = 0; i < ARRAY_SIZE(required_params); i++) { @@ -1502,6 +1515,23 @@ virtgpu_init_params(struct virtgpu *gpu) } } + val = virtgpu_ioctl_getparam(gpu, VIRTGPU_PARAM_HOST_VISIBLE); + if (val) { + gpu->bo_blob_mem = VIRTGPU_BLOB_MEM_HOST3D; + } else { + val = virtgpu_ioctl_getparam(gpu, VIRTGPU_PARAM_GUEST_VRAM); + if (val) { + gpu->bo_blob_mem = VIRTGPU_BLOB_MEM_GUEST_VRAM; + } + } + + if (!val) { + vn_log(gpu->instance, + "one of required kernel params (%d or %d) is missing", + (int)VIRTGPU_PARAM_HOST_VISIBLE, (int)VIRTGPU_PARAM_GUEST_VRAM); + return VK_ERROR_INITIALIZATION_FAILED; + } + val = virtgpu_ioctl_getparam(gpu, VIRTGPU_PARAM_MAX_SYNC_QUEUE_COUNT); if (!val) { if (VN_DEBUG(INIT))