diff --git a/src/virtio/vulkan/vn_android.c b/src/virtio/vulkan/vn_android.c index 9865fbf079d..eaa82bcacf4 100644 --- a/src/virtio/vulkan/vn_android.c +++ b/src/virtio/vulkan/vn_android.c @@ -23,73 +23,6 @@ #define VN_MAX_PLANES 4 -struct vn_android_gralloc_buffer_properties { - uint32_t num_planes; - uint64_t modifier; - - /* plane order matches VkImageDrmFormatModifierExplicitCreateInfoEXT */ - uint32_t offset[4]; - uint32_t stride[4]; -}; - -static bool -vn_android_gralloc_get_buffer_properties( - buffer_handle_t handle, - struct vn_android_gralloc_buffer_properties *out_props) -{ - struct u_gralloc *gralloc = vk_android_get_ugralloc(); - struct u_gralloc_buffer_basic_info info; - - /* - * We only support (and care of) CrOS and IMapper v4 gralloc modules - * at this point. They don't need the pixel stride and HAL format - * to be provided externally to them. It allows integrating u_gralloc - * with minimal modifications at this point. - */ - struct u_gralloc_buffer_handle ugb_handle = { - .handle = handle, - .pixel_stride = 0, - .hal_format = 0, - }; - - if (u_gralloc_get_buffer_basic_info(gralloc, &ugb_handle, &info) != 0) { - vn_log(NULL, "u_gralloc_get_buffer_basic_info failed"); - return false; - } - - if (info.modifier == DRM_FORMAT_MOD_INVALID) { - vn_log(NULL, "Unexpected DRM_FORMAT_MOD_INVALID"); - return false; - } - - assert(info.num_planes <= 4); - - out_props->num_planes = info.num_planes; - for (uint32_t i = 0; i < info.num_planes; i++) { - if (!info.strides[i]) { - out_props->num_planes = i; - break; - } - out_props->stride[i] = info.strides[i]; - out_props->offset[i] = info.offsets[i]; - } - - /* YVU420 has a chroma order of CrCb. So we must swap the planes for CrCb - * to align with VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM. This is to serve - * VkImageDrmFormatModifierExplicitCreateInfoEXT explicit plane layouts. - */ - if (info.drm_fourcc == DRM_FORMAT_YVU420) { - out_props->stride[1] = info.strides[2]; - out_props->offset[1] = info.offsets[2]; - out_props->stride[2] = info.strides[1]; - out_props->offset[2] = info.offsets[1]; - } - - out_props->modifier = info.modifier; - - return true; -} - static int vn_android_gralloc_get_dma_buf_fd(const native_handle_t *handle) { @@ -114,256 +47,57 @@ vn_android_gralloc_get_dma_buf_fd(const native_handle_t *handle) return handle->data[0]; } -static const VkFormat * -vn_android_format_to_view_formats(VkFormat format, uint32_t *out_count) -{ - /* For AHB image prop query and creation, venus overrides the tiling to - * VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, which requires to chain - * VkImageFormatListCreateInfo struct in the corresponding pNext when the - * VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT is set. Those AHB images are assumed - * to be mutable no more than sRGB-ness, and the implementations can fail - * whenever going beyond. - * - * This helper provides the view formats that have sRGB variants for the - * image format that venus supports. - */ - static const VkFormat view_formats_r8g8b8a8[] = { - VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SRGB - }; - static const VkFormat view_formats_r8g8b8[] = { VK_FORMAT_R8G8B8_UNORM, - VK_FORMAT_R8G8B8_SRGB }; - - switch (format) { - case VK_FORMAT_R8G8B8A8_UNORM: - *out_count = ARRAY_SIZE(view_formats_r8g8b8a8); - return view_formats_r8g8b8a8; - break; - case VK_FORMAT_R8G8B8_UNORM: - *out_count = ARRAY_SIZE(view_formats_r8g8b8); - return view_formats_r8g8b8; - break; - default: - /* let the caller handle the fallback case */ - *out_count = 0; - return NULL; - } -} - -struct vn_android_image_builder { - VkImageCreateInfo create; - VkSubresourceLayout layouts[4]; - VkImageDrmFormatModifierExplicitCreateInfoEXT modifier; - VkExternalMemoryImageCreateInfo external; - VkImageFormatListCreateInfo list; -}; - -static VkResult -vn_android_get_image_builder(struct vn_device *dev, - const VkImageCreateInfo *create_info, - const native_handle_t *handle, - struct vn_android_image_builder *out_builder) -{ - /* Android image builder is only used by ANB or AHB. For ANB, Android - * Vulkan loader will never pass the below structs. For AHB, struct - * vn_image_create_deferred_info will never carry below either. - */ - assert(!vk_find_struct_const( - create_info->pNext, - IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT)); - assert(!vk_find_struct_const(create_info->pNext, - EXTERNAL_MEMORY_IMAGE_CREATE_INFO)); - - struct vn_android_gralloc_buffer_properties buf_props; - if (!vn_android_gralloc_get_buffer_properties(handle, &buf_props)) - return VK_ERROR_INVALID_EXTERNAL_HANDLE; - - /* fill VkImageCreateInfo */ - memset(out_builder, 0, sizeof(*out_builder)); - out_builder->create = *create_info; - out_builder->create.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; - - /* fill VkImageDrmFormatModifierExplicitCreateInfoEXT */ - for (uint32_t i = 0; i < buf_props.num_planes; i++) { - out_builder->layouts[i].offset = buf_props.offset[i]; - out_builder->layouts[i].rowPitch = buf_props.stride[i]; - } - out_builder->modifier = (VkImageDrmFormatModifierExplicitCreateInfoEXT){ - .sType = - VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT, - .pNext = out_builder->create.pNext, - .drmFormatModifier = buf_props.modifier, - .drmFormatModifierPlaneCount = buf_props.num_planes, - .pPlaneLayouts = out_builder->layouts, - }; - out_builder->create.pNext = &out_builder->modifier; - - /* fill VkExternalMemoryImageCreateInfo */ - out_builder->external = (VkExternalMemoryImageCreateInfo){ - .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, - .pNext = out_builder->create.pNext, - .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, - }; - out_builder->create.pNext = &out_builder->external; - - /* fill VkImageFormatListCreateInfo if needed */ - if ((create_info->flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) && - !vk_find_struct_const(create_info->pNext, - IMAGE_FORMAT_LIST_CREATE_INFO)) { - /* 12.3. Images - * - * If tiling is VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT and flags - * contains VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, then the pNext chain - * must include a VkImageFormatListCreateInfo structure with non-zero - * viewFormatCount. - */ - uint32_t vcount = 0; - const VkFormat *vformats = - vn_android_format_to_view_formats(create_info->format, &vcount); - if (!vformats) { - /* image builder struct persists through the image creation call */ - vformats = &out_builder->create.format; - vcount = 1; - } - out_builder->list = (VkImageFormatListCreateInfo){ - .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, - .pNext = out_builder->create.pNext, - .viewFormatCount = vcount, - .pViewFormats = vformats, - }; - out_builder->create.pNext = &out_builder->list; - } - - return VK_SUCCESS; -} - static VkResult vn_android_image_from_anb_internal(struct vn_device *dev, - const VkImageCreateInfo *create_info, - const VkNativeBufferANDROID *anb_info, + VkImageCreateInfo *create_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 - * needs host storage info which can be queried from cros gralloc. - */ - struct vn_image *img = NULL; - VkResult result; + assert(vk_find_struct_const(create_info->pNext, NATIVE_BUFFER_ANDROID)); - struct vn_android_image_builder builder; - result = vn_android_get_image_builder(dev, create_info, anb_info->handle, - &builder); + VkImageDrmFormatModifierExplicitCreateInfoEXT mod_info; + VkSubresourceLayout layouts[VN_MAX_PLANES]; + VkResult result = vk_android_get_anb_layout(create_info, &mod_info, + layouts, VN_MAX_PLANES); if (result != VK_SUCCESS) return result; + mod_info.pNext = create_info->pNext; + const VkExternalMemoryImageCreateInfo external_info = { + .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, + .pNext = &mod_info, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + + /* create_info is a already local copy from the caller */ + create_info->pNext = &external_info; + /* encoder will strip the Android specific pNext structs */ if (*out_img) { /* driver side img obj has been created for deferred init like ahb */ - img = *out_img; - result = vn_image_init_deferred(dev, &builder.create, img); - if (result != VK_SUCCESS) { - vn_log(dev->instance, "anb: vn_image_init_deferred failed"); - return result; - } - } else { - result = vn_image_create(dev, &builder.create, alloc, &img); - if (result != VK_SUCCESS) { - vn_log(dev->instance, "anb: vn_image_create failed"); - return result; - } + return vn_image_init_deferred(dev, create_info, *out_img); } - int dma_buf_fd = vn_android_gralloc_get_dma_buf_fd(anb_info->handle); - if (dma_buf_fd < 0) { - result = VK_ERROR_INVALID_EXTERNAL_HANDLE; - goto fail; - } - - uint32_t mem_type_bits = 0; - result = vn_get_memory_dma_buf_properties(dev, dma_buf_fd, &mem_type_bits); - if (result != VK_SUCCESS) - goto fail; - - const VkMemoryRequirements *mem_req = - &img->requirements[0].memory.memoryRequirements; - mem_type_bits &= mem_req->memoryTypeBits; - if (!mem_type_bits) { - vn_log(dev->instance, "anb: no compatible mem type"); - result = VK_ERROR_INVALID_EXTERNAL_HANDLE; - goto fail; - } - - int dup_fd = os_dupfd_cloexec(dma_buf_fd); - if (dup_fd < 0) { - vn_log(dev->instance, "anb: os_dupfd_cloexec failed(%d)", errno); - result = (errno == EMFILE) ? VK_ERROR_TOO_MANY_OBJECTS - : VK_ERROR_OUT_OF_HOST_MEMORY; - goto fail; - } - - const bool prefer_dedicated = - img->requirements[0].dedicated.prefersDedicatedAllocation == VK_TRUE; - const VkMemoryDedicatedAllocateInfo dedicated_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, - .image = vn_image_to_handle(img), - }; - const VkImportMemoryFdInfoKHR import_fd_info = { - .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, - .pNext = prefer_dedicated ? &dedicated_info : 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, - }; - VkDeviceMemory mem_handle; - result = vn_AllocateMemory(vn_device_to_handle(dev), &memory_info, alloc, - &mem_handle); - if (result != VK_SUCCESS) { - vn_log(dev->instance, "anb: mem import failed"); - /* only need to close the dup_fd on import failure */ - close(dup_fd); - goto fail; - } - - img->base.vk.anb_memory = mem_handle; - *out_img = img; - - return VK_SUCCESS; - -fail: - /* this handles mem free for owned import */ - vn_DestroyImage(vn_device_to_handle(dev), vn_image_to_handle(img), alloc); - return result; + return vn_image_create(dev, create_info, alloc, out_img); } VkResult vn_android_image_from_anb(struct vn_device *dev, const VkImageCreateInfo *create_info, - const VkNativeBufferANDROID *anb_info, const VkAllocationCallbacks *alloc, struct vn_image **out_img) { + VkImageCreateInfo local_create = *create_info; + local_create.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; + struct vn_image *img = NULL; - VkResult result = vn_android_image_from_anb_internal( - dev, create_info, anb_info, alloc, &img); + VkResult result = + vn_android_image_from_anb_internal(dev, &local_create, alloc, &img); if (result != VK_SUCCESS) return result; - const VkBindImageMemoryInfo bind_info = { - .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, - .image = vn_image_to_handle(img), - .memory = img->base.vk.anb_memory, - }; - result = vn_BindImageMemory2(vn_device_to_handle(dev), 1, &bind_info); + result = + vk_android_import_anb(&dev->base.vk, create_info, alloc, &img->base.vk); if (result != VK_SUCCESS) { vn_DestroyImage(vn_device_to_handle(dev), vn_image_to_handle(img), alloc); @@ -378,14 +112,28 @@ VkDeviceMemory vn_android_get_wsi_memory(struct vn_device *dev, const VkBindImageMemoryInfo *bind_info) { + struct vn_image *img = vn_image_from_handle(bind_info->image); + VkImageCreateInfo *create_info = img->base.vk.android_deferred_create_info; + assert(create_info); + const VkNativeBufferANDROID *anb_info = vk_find_struct_const(bind_info->pNext, NATIVE_BUFFER_ANDROID); assert(anb_info && anb_info->handle); - struct vn_image *img = vn_image_from_handle(bind_info->image); + /* Inject ANB into the deferred pNext chain to leverage the existing common + * Android helper vk_android_get_anb_layout, which could be refactored to + * take ANB directly instead. + */ + VkNativeBufferANDROID local_anb = *anb_info; + local_anb.pNext = create_info->pNext; + create_info->pNext = &local_anb; VkResult result = vn_android_image_from_anb_internal( - dev, img->base.vk.android_deferred_create_info, anb_info, - &dev->base.vk.alloc, &img); + dev, create_info, &dev->base.vk.alloc, &img); + if (result != VK_SUCCESS) + return VK_NULL_HANDLE; + + result = vk_android_import_anb_memory(&dev->base.vk, &img->base.vk, + anb_info, &dev->base.vk.alloc); if (result != VK_SUCCESS) return VK_NULL_HANDLE; diff --git a/src/virtio/vulkan/vn_android.h b/src/virtio/vulkan/vn_android.h index 07a5bc17983..d4e2176dce0 100644 --- a/src/virtio/vulkan/vn_android.h +++ b/src/virtio/vulkan/vn_android.h @@ -24,7 +24,6 @@ VkResult vn_android_image_from_anb(struct vn_device *dev, const VkImageCreateInfo *image_info, - const VkNativeBufferANDROID *anb_info, const VkAllocationCallbacks *alloc, struct vn_image **out_img); @@ -42,7 +41,6 @@ vn_android_device_import_ahb(struct vn_device *dev, static inline VkResult vn_android_image_from_anb(UNUSED struct vn_device *dev, UNUSED const VkImageCreateInfo *image_info, - UNUSED const VkNativeBufferANDROID *anb_info, UNUSED const VkAllocationCallbacks *alloc, UNUSED struct vn_image **out_img) { diff --git a/src/virtio/vulkan/vn_image.c b/src/virtio/vulkan/vn_image.c index 96e79f5eac9..5d4f9168e47 100644 --- a/src/virtio/vulkan/vn_image.c +++ b/src/virtio/vulkan/vn_image.c @@ -587,8 +587,7 @@ vn_CreateImage(VkDevice device, if (wsi_info) { result = vn_wsi_create_image(dev, pCreateInfo, wsi_info, alloc, &img); } else if (anb_info) { - result = - vn_android_image_from_anb(dev, pCreateInfo, anb_info, alloc, &img); + result = vn_android_image_from_anb(dev, pCreateInfo, alloc, &img); } else if (ahb_info) { result = vn_image_create_deferred(dev, pCreateInfo, alloc, &img); } else if (swapchain_info) {