From cf8e324fe51a6266e765ab6910b5480f42a08c0b Mon Sep 17 00:00:00 2001 From: Aaron Ruby Date: Mon, 27 May 2024 15:37:53 -0400 Subject: [PATCH] gfxstream: Switch to using scanout path with native DRM images for Linux WSI Reviewed-by: Aaron Ruby Acked-by: Yonggang Luo Acked-by: Adam Jackson Part-of: --- .../guest/vulkan/gfxstream_vk_wsi.cpp | 4 +- .../guest/vulkan_enc/ResourceTracker.cpp | 196 ++++++++---------- .../guest/vulkan_enc/ResourceTracker.h | 4 +- src/gfxstream/guest/vulkan_enc/vk_struct_id.h | 7 + 4 files changed, 99 insertions(+), 112 deletions(-) diff --git a/src/gfxstream/guest/vulkan/gfxstream_vk_wsi.cpp b/src/gfxstream/guest/vulkan/gfxstream_vk_wsi.cpp index be212ac35fe..339826a9823 100644 --- a/src/gfxstream/guest/vulkan/gfxstream_vk_wsi.cpp +++ b/src/gfxstream/guest/vulkan/gfxstream_vk_wsi.cpp @@ -33,8 +33,8 @@ VkResult gfxstream_vk_wsi_init(struct gfxstream_vk_physical_device* physical_dev // Allow guest-side modifier code paths physical_device->wsi_device.supports_modifiers = true; - // For DRM, uses the buffer-blit path for WSI images - physical_device->wsi_device.supports_scanout = false; + // Support wsi_image_create_info::scanout + physical_device->wsi_device.supports_scanout = true; physical_device->vk.wsi_device = &physical_device->wsi_device; diff --git a/src/gfxstream/guest/vulkan_enc/ResourceTracker.cpp b/src/gfxstream/guest/vulkan_enc/ResourceTracker.cpp index 2fcda238753..5ac32ff2345 100644 --- a/src/gfxstream/guest/vulkan_enc/ResourceTracker.cpp +++ b/src/gfxstream/guest/vulkan_enc/ResourceTracker.cpp @@ -728,14 +728,6 @@ void ResourceTracker::transformImageMemoryRequirementsForGuestLocked(VkImage ima auto height = info.createInfo.extent.height; reqs->size = width * height * 4; } -#elif defined(__linux__) && !defined(VK_USE_PLATFORM_ANDROID_KHR) - auto it = info_VkImage.find(image); - if (it == info_VkImage.end()) return; - auto& info = it->second; - if (info.isWsiImage) { - static const uint32_t kColorBufferBpp = 4; - reqs->size = kColorBufferBpp * info.createInfo.extent.width * info.createInfo.extent.height; - } #else // Bypass "unused parameter" checks. (void)image; @@ -2907,24 +2899,6 @@ static uint32_t getVirglFormat(VkFormat vkFormat) { return virglFormat; } -static bool getVirtGpuFormatParams(const VkFormat vkFormat, uint32_t* virglFormat, uint32_t* target, - uint32_t* bind, uint32_t* bpp) { - *virglFormat = getVirglFormat(vkFormat); - switch (*virglFormat) { - case VIRGL_FORMAT_R8G8B8A8_UNORM: - case VIRGL_FORMAT_B8G8R8A8_UNORM: - *target = PIPE_TEXTURE_2D; - *bind = VIRGL_BIND_RENDER_TARGET; - *bpp = 4; - break; - default: - /* Format not recognized */ - return false; - } - - return true; -} - CoherentMemoryPtr ResourceTracker::createCoherentMemory( VkDevice device, VkDeviceMemory mem, const VkMemoryAllocateInfo& hostAllocationInfo, VkEncoder* enc, VkResult& res) { @@ -3777,25 +3751,17 @@ VkResult ResourceTracker::on_vkAllocateMemory(void* context, VkResult input_resu #endif VirtGpuResourcePtr colorBufferBlob = nullptr; -#if defined(__linux__) && !defined(VK_USE_PLATFORM_ANDROID_KHR) +#if defined(LINUX_GUEST_BUILD) if (exportDmabuf) { VirtGpuDevice* instance = VirtGpuDevice::getInstance(); - // // TODO: any special action for VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA? Can mark - // special state if needed. - // // const wsi_memory_allocate_info* wsiAllocateInfoPtr = - // vk_find_struct(pAllocateInfo); bool hasDedicatedImage = dedicatedAllocInfoPtr && (dedicatedAllocInfoPtr->image != VK_NULL_HANDLE); bool hasDedicatedBuffer = dedicatedAllocInfoPtr && (dedicatedAllocInfoPtr->buffer != VK_NULL_HANDLE); - if (!hasDedicatedImage && !hasDedicatedBuffer) { - mesa_loge( - "dma-buf exportable memory requires dedicated Image or Buffer information.\n"); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } if (hasDedicatedImage) { VkImageCreateInfo imageCreateInfo; + bool isDmaBufImage = false; { AutoLock lock(mLock); @@ -3804,67 +3770,62 @@ VkResult ResourceTracker::on_vkAllocateMemory(void* context, VkResult input_resu const auto& imageInfo = it->second; imageCreateInfo = imageInfo.createInfo; + isDmaBufImage = imageInfo.isDmaBufImage; } - uint32_t virglFormat = 0; - uint32_t target = 0; - uint32_t bind = 0; - uint32_t bpp = 0; - if (!gfxstream::vk::getVirtGpuFormatParams(imageCreateInfo.format, &virglFormat, - &target, &bind, &bpp)) { - mesa_loge("%s: Unsupported VK format for VirtGpu resource, vkFormat: 0x%x", - __func__, imageCreateInfo.format); - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - const uint32_t stride = imageCreateInfo.extent.width * bpp; - colorBufferBlob = instance->createResource(imageCreateInfo.extent.width, - imageCreateInfo.extent.height, stride, - virglFormat, target, bind); - if (!colorBufferBlob) { - mesa_loge("%s: Failed to create colorBuffer resource for Image memory\n", __func__); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - if (0 != colorBufferBlob->wait()) { - mesa_loge("%s: Failed to wait for colorBuffer resource for Image memory\n", - __func__); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - } + // TODO (b/326956485): Support DRM format modifiers for dmabuf memory + // For now, can only externalize memory for linear images + if (isDmaBufImage) { + const VkImageSubresource imageSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .arrayLayer = 0, + }; + VkSubresourceLayout subResourceLayout; + enc->vkGetImageSubresourceLayout(device, dedicatedAllocInfoPtr->image, + &imageSubresource, &subResourceLayout, + true /* do lock */); + if (!subResourceLayout.rowPitch) { + mesa_loge("%s: Failed to query stride for VirtGpu resource creation."); + return VK_ERROR_INITIALIZATION_FAILED; + } - if (hasDedicatedBuffer) { - VkBufferCreateInfo bufferCreateInfo; - { - AutoLock lock(mLock); - - auto it = info_VkBuffer.find(dedicatedAllocInfoPtr->buffer); - if (it == info_VkBuffer.end()) return VK_ERROR_INITIALIZATION_FAILED; - const auto& bufferInfo = it->second; - bufferCreateInfo = bufferInfo.createInfo; - } - const VkFormat vkFormat = VK_FORMAT_R8G8B8A8_UNORM; - uint32_t virglFormat = 0; - uint32_t target = 0; - uint32_t bind = 0; - uint32_t bpp = 0; - if (!gfxstream::vk::getVirtGpuFormatParams(vkFormat, &virglFormat, &target, &bind, - &bpp)) { - mesa_loge("%s: Unexpected error getting VirtGpu format params for vkFormat: 0x%x", - __func__, vkFormat); - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - - colorBufferBlob = instance->createResource(bufferCreateInfo.size / bpp, 1, virglFormat, - target, bind, bpp); - if (!colorBufferBlob) { - mesa_loge("%s: Failed to create colorBuffer resource for Buffer memory\n", - __func__); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - if (0 != colorBufferBlob->wait()) { - mesa_loge("%s: Failed to wait for colorBuffer resource for Buffer memory\n", - __func__); - return VK_ERROR_OUT_OF_DEVICE_MEMORY; + uint32_t virglFormat = gfxstream::vk::getVirglFormat(imageCreateInfo.format); + if (!virglFormat) { + mesa_loge("Unsupported VK format for VirtGpu resource, vkFormat: 0x%x", + imageCreateInfo.format); + return VK_ERROR_FORMAT_NOT_SUPPORTED; + } + const uint32_t target = PIPE_TEXTURE_2D; + uint32_t bind = VIRGL_BIND_RENDER_TARGET; + if (VK_IMAGE_TILING_LINEAR == imageCreateInfo.tiling) { + bind |= VIRGL_BIND_LINEAR; + } + colorBufferBlob = instance->createResource( + imageCreateInfo.extent.width, imageCreateInfo.extent.height, + subResourceLayout.rowPitch, virglFormat, target, bind); + if (!colorBufferBlob) { + mesa_loge("Failed to create colorBuffer resource for Image memory"); + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } + if (!colorBufferBlob->wait()) { + mesa_loge("Failed to wait for colorBuffer resource for Image memory"); + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } + } else { + mesa_logw( + "The VkMemoryDedicatedAllocateInfo::image associated with VkDeviceMemory " + "allocation cannot be used to create exportable resource " + "(VkExportMemoryAllocateInfo).\n"); } + } else if (hasDedicatedBuffer) { + mesa_logw( + "VkDeviceMemory allocated with VkMemoryDedicatedAllocateInfo::buffer cannot be " + "exported (VkExportMemoryAllocateInfo)"); + } else { + mesa_logw( + "VkDeviceMemory is not exportable (VkExportMemoryAllocateInfo). Requires " + "VkMemoryDedicatedAllocateInfo::image to create external resource."); } } @@ -4136,20 +4097,31 @@ VkResult ResourceTracker::on_vkCreateImage(void* context, VkResult, VkDevice dev vk_append_struct(&structChainIter, &localExtImgCi); } - bool isWsiImage = false; - -#if defined(__linux__) && !defined(VK_USE_PLATFORM_ANDROID_KHR) +#if defined(LINUX_GUEST_BUILD) + bool isDmaBufImage = false; if (extImgCiPtr && (extImgCiPtr->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) { - // Assumes that handleType with DMA_BUF_BIT indicates creation of a - // image for WSI use; no other external dma_buf usage is supported - isWsiImage = true; - // Must be linear. Otherwise querying stride and other properties - // can be implementation-dependent. - localCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; - if (gfxstream::vk::getVirglFormat(localCreateInfo.format) < 0) { - localCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + const wsi_image_create_info* wsiImageCi = + vk_find_struct(pCreateInfo); + if (wsiImageCi) { + if (!wsiImageCi->scanout) { + mesa_logd( + "gfxstream only supports native DRM image scanout path for Linux WSI " + "(wsi_image_create_info::scanout)"); + return VK_ERROR_INITIALIZATION_FAILED; + } + // Linux WSI creates swapchain images with VK_IMAGE_CREATE_ALIAS_BIT. Vulkan spec + // states: "If the pNext chain includes a VkExternalMemoryImageCreateInfo or + // VkExternalMemoryImageCreateInfoNV structure whose handleTypes member is not 0, it is + // as if VK_IMAGE_CREATE_ALIAS_BIT is set." To avoid flag mismatches on host driver, + // remove the VK_IMAGE_CREATE_ALIAS_BIT here. + localCreateInfo.flags &= ~VK_IMAGE_CREATE_ALIAS_BIT; + // TODO (b/326956485): DRM format modifiers to support client/compositor awareness + // For now, override WSI images to use linear tiling, as compositor will default to + // DRM_FORMAT_MOD_LINEAR. + localCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; } + isDmaBufImage = true; } #endif @@ -4324,19 +4296,25 @@ VkResult ResourceTracker::on_vkCreateImage(void* context, VkResult, VkDevice dev } #endif - info.isWsiImage = isWsiImage; - // Delete `protocolVersion` check goldfish drivers are gone. -#if defined(VK_USE_PLATFORM_ANDROID_KHR) || defined(__linux__) +#if defined(VK_USE_PLATFORM_ANDROID_KHR) if (mCaps.vulkanCapset.colorBufferMemoryIndex == 0xFFFFFFFF) { mCaps.vulkanCapset.colorBufferMemoryIndex = getColorBufferMemoryIndex(context, device); } - if (isWsiImage || - (extImgCiPtr && (extImgCiPtr->handleTypes & + if ((extImgCiPtr && (extImgCiPtr->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID))) { updateMemoryTypeBits(&memReqs.memoryTypeBits, mCaps.vulkanCapset.colorBufferMemoryIndex); } #endif +#if defined(LINUX_GUEST_BUILD) + if (mCaps.vulkanCapset.colorBufferMemoryIndex == 0xFFFFFFFF) { + mCaps.vulkanCapset.colorBufferMemoryIndex = getColorBufferMemoryIndex(context, device); + } + info.isDmaBufImage = isDmaBufImage; + if (info.isDmaBufImage) { + updateMemoryTypeBits(&memReqs.memoryTypeBits, mCaps.vulkanCapset.colorBufferMemoryIndex); + } +#endif if (info.baseRequirementsKnown) { transformImageMemoryRequirementsForGuestLocked(*pImage, &memReqs); diff --git a/src/gfxstream/guest/vulkan_enc/ResourceTracker.h b/src/gfxstream/guest/vulkan_enc/ResourceTracker.h index ac22849eaee..2040a574792 100644 --- a/src/gfxstream/guest/vulkan_enc/ResourceTracker.h +++ b/src/gfxstream/guest/vulkan_enc/ResourceTracker.h @@ -781,7 +781,9 @@ class ResourceTracker { #ifdef VK_USE_PLATFORM_FUCHSIA bool isSysmemBackedMemory = false; #endif - bool isWsiImage = false; +#ifdef LINUX_GUEST_BUILD + bool isDmaBufImage = false; +#endif }; struct VkBuffer_Info { diff --git a/src/gfxstream/guest/vulkan_enc/vk_struct_id.h b/src/gfxstream/guest/vulkan_enc/vk_struct_id.h index f75fbc69db4..5d43282ab0d 100644 --- a/src/gfxstream/guest/vulkan_enc/vk_struct_id.h +++ b/src/gfxstream/guest/vulkan_enc/vk_struct_id.h @@ -20,6 +20,10 @@ #include "vk_android_native_buffer_gfxstream.h" #include "vulkan_gfxstream.h" +#if defined(LINUX_GUEST_BUILD) +#include "vulkan/wsi/wsi_common.h" +#endif + // anonymous namespace { @@ -125,6 +129,9 @@ REGISTER_VK_STRUCT_ID(VkDeviceCreateInfo, VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO); REGISTER_VK_STRUCT_ID(VkPhysicalDeviceGroupProperties, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES); REGISTER_VK_STRUCT_ID(VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT); +#if defined(LINUX_GUEST_BUILD) +REGISTER_VK_STRUCT_ID(wsi_image_create_info, VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA); +#endif #undef REGISTER_VK_STRUCT_ID