Module: Mesa Branch: master Commit: 34f37fb780e1c7e29d524658b0af84ed03d514a0 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=34f37fb780e1c7e29d524658b0af84ed03d514a0
Author: Yiwei Zhang <[email protected]> Date: Mon Apr 12 01:33:05 2021 +0000 venus: implement VK_ANDROID_native_buffer v7 1. Android native buffer import 2. vkGetSwapchainGrallocUsage2ANDROID 3. vkAcquireImageANDROID 4. vkQueueSignalReleaseImageANDROID 5. not advertise shared presentable image support Signed-off-by: Yiwei Zhang <[email protected]> Reviewed-by: Chia-I Wu <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10259> --- src/virtio/vulkan/meson.build | 2 + src/virtio/vulkan/vn_android.c | 261 +++++++++++++++++++++++++++++++++++++++++ src/virtio/vulkan/vn_android.h | 30 +++++ src/virtio/vulkan/vn_device.c | 64 +++++++--- src/virtio/vulkan/vn_image.c | 13 ++ src/virtio/vulkan/vn_image.h | 2 + 6 files changed, 354 insertions(+), 18 deletions(-) diff --git a/src/virtio/vulkan/meson.build b/src/virtio/vulkan/meson.build index 2de33de0722..69ecfa4901f 100644 --- a/src/virtio/vulkan/meson.build +++ b/src/virtio/vulkan/meson.build @@ -86,6 +86,8 @@ endif if with_platform_android libvn_files += files('vn_android.c') + vn_deps += dep_android + vn_flags += '-DVK_USE_PLATFORM_ANDROID_KHR' endif libvulkan_virtio = shared_library( diff --git a/src/virtio/vulkan/vn_android.c b/src/virtio/vulkan/vn_android.c index 7f44e97ca44..5948440b921 100644 --- a/src/virtio/vulkan/vn_android.c +++ b/src/virtio/vulkan/vn_android.c @@ -1,13 +1,27 @@ /* * Copyright 2021 Google LLC * SPDX-License-Identifier: MIT + * + * based in part on anv and radv which are: + * Copyright © 2015 Intel Corporation + * Copyright © 2016 Red Hat + * Copyright © 2016 Bas Nieuwenhuizen */ +#include "vn_android.h" #include "vn_common.h" #include <hardware/hwvulkan.h> +#include <vndk/hardware_buffer.h> #include <vulkan/vk_icd.h> +#include "util/libsync.h" +#include "util/os_file.h" + +#include "vn_device.h" +#include "vn_image.h" +#include "vn_queue.h" + static int vn_hal_open(const struct hw_module_t *mod, const char *id, @@ -62,3 +76,250 @@ vn_hal_open(const struct hw_module_t *mod, *dev = &vn_hal_dev.common; return 0; } + +VkResult +vn_GetSwapchainGrallocUsage2ANDROID( + VkDevice device, + VkFormat format, + VkImageUsageFlags imageUsage, + VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, + uint64_t *grallocConsumerUsage, + uint64_t *grallocProducerUsage) +{ + struct vn_device *dev = vn_device_from_handle(device); + *grallocConsumerUsage = 0; + *grallocProducerUsage = 0; + + if (swapchainImageUsage & VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID) + return vn_error(dev->instance, VK_ERROR_INITIALIZATION_FAILED); + + if (VN_DEBUG(WSI)) + vn_log(dev->instance, "format=%d, imageUsage=0x%x", format, imageUsage); + + if (imageUsage & (VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) + *grallocProducerUsage |= AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER; + + if (imageUsage & + (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) + *grallocConsumerUsage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; + + return VK_SUCCESS; +} + +VkResult +vn_image_from_anb(struct vn_device *dev, + const VkImageCreateInfo *image_info, + const VkNativeBufferANDROID *anb_info, + const VkAllocationCallbacks *alloc, + struct vn_image **out_img) +{ + /* If anb_info->handle points to a classic resouce created from + * virtio_gpu_cmd_resource_create_3d, anb_info->stride is the stride of the + * guest shadow storage other than the host gpu storage. + * + * We also need to pass the correct stride to vn_CreateImage, which will be + * done via VkImageDrmFormatModifierExplicitCreateInfoEXT and will require + * VK_EXT_image_drm_format_modifier support in the host driver. The struct + * also needs a modifier, which can only be encoded in anb_info->handle. + * + * Given above, until gralloc gets fixed to set stride correctly and to + * encode modifier in the native handle, we will have to make assumptions. + * (e.g. In CrOS, there's a VIRTGPU_RESOURCE_INFO_TYPE_EXTENDED kernel hack + * for that) + */ + VkResult result = VK_SUCCESS; + VkDevice device = vn_device_to_handle(dev); + VkDeviceMemory memory = VK_NULL_HANDLE; + VkImage image = VK_NULL_HANDLE; + struct vn_image *img = NULL; + uint32_t mem_type_bits = 0; + int dma_buf_fd = -1; + int dup_fd = -1; + + /* encoder will strip the Android specific pNext structs */ + result = vn_image_create(dev, image_info, alloc, &img); + if (result != VK_SUCCESS) + goto fail; + + image = vn_image_to_handle(img); + VkMemoryRequirements mem_req; + vn_GetImageMemoryRequirements(device, image, &mem_req); + if (!mem_req.memoryTypeBits) { + result = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto fail; + } + + if (anb_info->handle->numFds != 1) { + if (VN_DEBUG(WSI)) + vn_log(dev->instance, "handle->numFds is %d, expected 1", + anb_info->handle->numFds); + result = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto fail; + } + + dma_buf_fd = anb_info->handle->data[0]; + if (dma_buf_fd < 0) { + result = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto fail; + } + + VkMemoryFdPropertiesKHR fd_prop = { + .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR, + .pNext = NULL, + .memoryTypeBits = 0, + }; + result = vn_GetMemoryFdPropertiesKHR( + device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, dma_buf_fd, + &fd_prop); + if (result != VK_SUCCESS) + goto fail; + + if (!fd_prop.memoryTypeBits) { + result = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto fail; + } + + if (VN_DEBUG(WSI)) + vn_log(dev->instance, "memoryTypeBits = img(0x%X) & fd(0x%X)", + mem_req.memoryTypeBits, fd_prop.memoryTypeBits); + + mem_type_bits = mem_req.memoryTypeBits & fd_prop.memoryTypeBits; + if (!mem_type_bits) { + result = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto fail; + } + + dup_fd = os_dupfd_cloexec(dma_buf_fd); + if (dup_fd < 0) { + result = (errno == EMFILE) ? VK_ERROR_TOO_MANY_OBJECTS + : VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + const VkImportMemoryFdInfoKHR import_fd_info = { + .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, + .pNext = NULL, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + .fd = dup_fd, + }; + const VkMemoryAllocateInfo memory_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &import_fd_info, + .allocationSize = mem_req.size, + .memoryTypeIndex = ffs(mem_type_bits) - 1, + }; + result = vn_AllocateMemory(device, &memory_info, alloc, &memory); + if (result != VK_SUCCESS) { + /* only need to close the dup_fd on import failure */ + close(dup_fd); + goto fail; + } + + result = vn_BindImageMemory(device, image, memory, 0); + if (result != VK_SUCCESS) + goto fail; + + /* Android WSI image owns the memory */ + img->private_memory = memory; + *out_img = img; + + return VK_SUCCESS; + +fail: + if (image != VK_NULL_HANDLE) + vn_DestroyImage(device, image, alloc); + if (memory != VK_NULL_HANDLE) + vn_FreeMemory(device, memory, alloc); + return vn_error(dev->instance, result); +} + +VkResult +vn_AcquireImageANDROID(VkDevice device, + UNUSED VkImage image, + int nativeFenceFd, + VkSemaphore semaphore, + VkFence fence) +{ + /* At this moment, out semaphore and fence are filled with already signaled + * payloads, and the native fence fd is waited inside until signaled. + */ + struct vn_device *dev = vn_device_from_handle(device); + struct vn_semaphore *sem = vn_semaphore_from_handle(semaphore); + struct vn_fence *fen = vn_fence_from_handle(fence); + + if (nativeFenceFd >= 0) { + int ret = sync_wait(nativeFenceFd, INT32_MAX); + /* Android loader expects the ICD to always close the fd */ + close(nativeFenceFd); + if (ret) + return vn_error(dev->instance, VK_ERROR_SURFACE_LOST_KHR); + } + + if (sem) + vn_semaphore_signal_wsi(dev, sem); + + if (fen) + vn_fence_signal_wsi(dev, fen); + + return VK_SUCCESS; +} + +VkResult +vn_QueueSignalReleaseImageANDROID(VkQueue queue, + uint32_t waitSemaphoreCount, + const VkSemaphore *pWaitSemaphores, + VkImage image, + int *pNativeFenceFd) +{ + /* At this moment, the wait semaphores are converted to a VkFence via an + * empty submit. The VkFence is then waited inside until signaled, and the + * out native fence fd is set to -1. + */ + VkResult result = VK_SUCCESS; + struct vn_queue *que = vn_queue_from_handle(queue); + const VkAllocationCallbacks *alloc = &que->device->base.base.alloc; + VkDevice device = vn_device_to_handle(que->device); + VkPipelineStageFlags local_stage_masks[8]; + VkPipelineStageFlags *stage_masks = local_stage_masks; + + if (waitSemaphoreCount == 0) + goto out; + + if (waitSemaphoreCount > ARRAY_SIZE(local_stage_masks)) { + stage_masks = + vk_alloc(alloc, sizeof(VkPipelineStageFlags) * waitSemaphoreCount, + VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!stage_masks) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + } + + for (uint32_t i = 0; i < waitSemaphoreCount; i++) + stage_masks[i] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + + const VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = NULL, + .waitSemaphoreCount = waitSemaphoreCount, + .pWaitSemaphores = pWaitSemaphores, + .pWaitDstStageMask = stage_masks, + .commandBufferCount = 0, + .pCommandBuffers = NULL, + .signalSemaphoreCount = 0, + .pSignalSemaphores = NULL, + }; + result = vn_QueueSubmit(queue, 1, &submit_info, que->wait_fence); + if (result != VK_SUCCESS) + goto out; + + result = + vn_WaitForFences(device, 1, &que->wait_fence, VK_TRUE, UINT64_MAX); + vn_ResetFences(device, 1, &que->wait_fence); + +out: + *pNativeFenceFd = -1; + return result; +} diff --git a/src/virtio/vulkan/vn_android.h b/src/virtio/vulkan/vn_android.h new file mode 100644 index 00000000000..f18ce7f2694 --- /dev/null +++ b/src/virtio/vulkan/vn_android.h @@ -0,0 +1,30 @@ +/* + * Copyright 2021 Google LLC + * SPDX-License-Identifier: MIT + * + * based in part on anv and radv which are: + * Copyright © 2015 Intel Corporation + * Copyright © 2016 Red Hat + * Copyright © 2016 Bas Nieuwenhuizen + */ + +#ifndef VN_ANDROID_H +#define VN_ANDROID_H + +#include <vulkan/vk_android_native_buffer.h> +#include <vulkan/vulkan.h> + +/* venus implements VK_ANDROID_native_buffer up to spec version 7 */ +#define VN_ANDROID_NATIVE_BUFFER_SPEC_VERSION 7 + +struct vn_device; +struct vn_image; + +VkResult +vn_image_from_anb(struct vn_device *dev, + const VkImageCreateInfo *image_info, + const VkNativeBufferANDROID *anb_info, + const VkAllocationCallbacks *alloc, + struct vn_image **out_img); + +#endif /* VN_ANDROID_H */ diff --git a/src/virtio/vulkan/vn_device.c b/src/virtio/vulkan/vn_device.c index ba57cadad5a..a45c72a2e85 100644 --- a/src/virtio/vulkan/vn_device.c +++ b/src/virtio/vulkan/vn_device.c @@ -20,6 +20,7 @@ #include "venus-protocol/vn_protocol_driver_instance.h" #include "venus-protocol/vn_protocol_driver_transport.h" +#include "vn_android.h" #include "vn_device_memory.h" #include "vn_icd.h" #include "vn_queue.h" @@ -1413,6 +1414,9 @@ vn_physical_device_get_supported_extensions( .KHR_incremental_present = true, .KHR_swapchain = true, .KHR_swapchain_mutable_format = true, +#endif +#ifdef ANDROID + .ANDROID_native_buffer = true, #endif }; @@ -1535,6 +1539,13 @@ vn_physical_device_init_extensions(struct vn_physical_device *physical_dev) if (supported.extensions[i]) { physical_dev->base.base.supported_extensions.extensions[i] = true; physical_dev->extension_spec_versions[i] = props->specVersion; +#ifdef ANDROID + /* override VK_ANDROID_native_buffer spec version */ + if (!strcmp(props->extensionName, + VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME)) + physical_dev->extension_spec_versions[i] = + VN_ANDROID_NATIVE_BUFFER_SPEC_VERSION; +#endif continue; } @@ -2380,12 +2391,13 @@ vn_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDevicePCIBusInfoPropertiesEXT *pci_bus_info; VkPhysicalDeviceTransformFeedbackPropertiesEXT *transform_feedback; + VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties; } u; u.pnext = (VkBaseOutStructure *)pProperties; while (u.pnext) { void *saved = u.pnext->pNext; - switch (u.pnext->sType) { + switch ((int32_t)u.pnext->sType) { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2: memcpy(u.pnext, &physical_dev->properties, sizeof(physical_dev->properties)); @@ -2576,6 +2588,9 @@ vn_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, &physical_dev->transform_feedback_properties, sizeof(physical_dev->transform_feedback_properties)); break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID: + u.presentation_properties->sharedImage = VK_FALSE; + break; default: break; } @@ -2908,52 +2923,65 @@ find_extension_names(const char *const *exts, return false; } -static const char ** +static bool merge_extension_names(const char *const *exts, uint32_t ext_count, const char *const *extra_exts, uint32_t extra_count, + const char *const *block_exts, + uint32_t block_count, const VkAllocationCallbacks *alloc, - uint32_t *merged_count) + const char *const **out_exts, + uint32_t *out_count) { const char **merged = vk_alloc(alloc, sizeof(*merged) * (ext_count + extra_count), VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (!merged) - return NULL; - - memcpy(merged, exts, sizeof(*exts) * ext_count); + return false; - uint32_t count = ext_count; + uint32_t count = 0; + for (uint32_t i = 0; i < ext_count; i++) { + if (!find_extension_names(block_exts, block_count, exts[i])) + merged[count++] = exts[i]; + } for (uint32_t i = 0; i < extra_count; i++) { if (!find_extension_names(exts, ext_count, extra_exts[i])) merged[count++] = extra_exts[i]; } - *merged_count = count; - return merged; + *out_exts = merged; + *out_count = count; + return true; } static const VkDeviceCreateInfo * -vn_device_fix_create_info(const struct vn_physical_device *physical_dev, +vn_device_fix_create_info(const struct vn_device *dev, const VkDeviceCreateInfo *dev_info, const VkAllocationCallbacks *alloc, VkDeviceCreateInfo *local_info) { + /* extra_exts and block_exts must not overlap */ const char *extra_exts[8]; + const char *block_exts[8]; uint32_t extra_count = 0; + uint32_t block_count = 0; - if (physical_dev->wsi_device.supports_modifiers) + if (dev->physical_device->wsi_device.supports_modifiers) extra_exts[extra_count++] = "VK_EXT_image_drm_format_modifier"; - if (!extra_count) + if (dev->base.base.enabled_extensions.ANDROID_native_buffer) + block_exts[block_count++] = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME; + + if (!extra_count && (!block_count || !dev_info->enabledExtensionCount)) return dev_info; *local_info = *dev_info; - local_info->ppEnabledExtensionNames = merge_extension_names( - dev_info->ppEnabledExtensionNames, dev_info->enabledExtensionCount, - extra_exts, extra_count, alloc, &local_info->enabledExtensionCount); - if (!local_info->ppEnabledExtensionNames) + if (!merge_extension_names(dev_info->ppEnabledExtensionNames, + dev_info->enabledExtensionCount, extra_exts, + extra_count, block_exts, block_count, alloc, + &local_info->ppEnabledExtensionNames, + &local_info->enabledExtensionCount)) return NULL; return local_info; @@ -2992,8 +3020,8 @@ vn_CreateDevice(VkPhysicalDevice physicalDevice, dev->physical_device = physical_dev; VkDeviceCreateInfo local_create_info; - pCreateInfo = vn_device_fix_create_info(physical_dev, pCreateInfo, alloc, - &local_create_info); + pCreateInfo = + vn_device_fix_create_info(dev, pCreateInfo, alloc, &local_create_info); if (!pCreateInfo) { result = VK_ERROR_OUT_OF_HOST_MEMORY; goto fail; diff --git a/src/virtio/vulkan/vn_image.c b/src/virtio/vulkan/vn_image.c index df29ecfee05..6e86c8aaba9 100644 --- a/src/virtio/vulkan/vn_image.c +++ b/src/virtio/vulkan/vn_image.c @@ -15,6 +15,7 @@ #include "venus-protocol/vn_protocol_driver_sampler.h" #include "venus-protocol/vn_protocol_driver_sampler_ycbcr_conversion.h" +#include "vn_android.h" #include "vn_device.h" #include "vn_device_memory.h" @@ -153,6 +154,15 @@ vn_CreateImage(VkDevice device, } #endif +#ifdef ANDROID + const VkNativeBufferANDROID *anb_info = + vk_find_struct_const(pCreateInfo->pNext, NATIVE_BUFFER_ANDROID); + if (anb_info) { + result = vn_image_from_anb(dev, pCreateInfo, anb_info, alloc, &img); + goto out; + } +#endif + result = vn_image_create(dev, pCreateInfo, alloc, &img); out: @@ -176,6 +186,9 @@ vn_DestroyImage(VkDevice device, if (!img) return; + if (img->private_memory != VK_NULL_HANDLE) + vn_FreeMemory(device, img->private_memory, pAllocator); + vn_async_vkDestroyImage(dev->instance, device, image, NULL); vn_object_base_fini(&img->base); diff --git a/src/virtio/vulkan/vn_image.h b/src/virtio/vulkan/vn_image.h index 46f388dd98a..f134ca2640a 100644 --- a/src/virtio/vulkan/vn_image.h +++ b/src/virtio/vulkan/vn_image.h @@ -18,6 +18,8 @@ struct vn_image { VkMemoryRequirements2 memory_requirements[4]; VkMemoryDedicatedRequirements dedicated_requirements[4]; + /* For VK_ANDROID_native_buffer, the WSI image owns the memory, */ + VkDeviceMemory private_memory; }; VK_DEFINE_NONDISP_HANDLE_CASTS(vn_image, base.base, _______________________________________________ mesa-commit mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/mesa-commit
