gfxstream: Switch to using scanout path with native DRM images for Linux WSI

Reviewed-by: Aaron Ruby <aruby@blackberry.com>
Acked-by: Yonggang Luo <luoyonggang@gmail.com>
Acked-by: Adam Jackson <ajax@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27246>
This commit is contained in:
Aaron Ruby
2024-05-27 15:37:53 -04:00
committed by Marge Bot
parent 6b92e632da
commit cf8e324fe5
4 changed files with 99 additions and 112 deletions

View File

@@ -33,8 +33,8 @@ VkResult gfxstream_vk_wsi_init(struct gfxstream_vk_physical_device* physical_dev
// Allow guest-side modifier code paths // Allow guest-side modifier code paths
physical_device->wsi_device.supports_modifiers = true; physical_device->wsi_device.supports_modifiers = true;
// For DRM, uses the buffer-blit path for WSI images // Support wsi_image_create_info::scanout
physical_device->wsi_device.supports_scanout = false; physical_device->wsi_device.supports_scanout = true;
physical_device->vk.wsi_device = &physical_device->wsi_device; physical_device->vk.wsi_device = &physical_device->wsi_device;

View File

@@ -728,14 +728,6 @@ void ResourceTracker::transformImageMemoryRequirementsForGuestLocked(VkImage ima
auto height = info.createInfo.extent.height; auto height = info.createInfo.extent.height;
reqs->size = width * height * 4; 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 #else
// Bypass "unused parameter" checks. // Bypass "unused parameter" checks.
(void)image; (void)image;
@@ -2907,24 +2899,6 @@ static uint32_t getVirglFormat(VkFormat vkFormat) {
return virglFormat; 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( CoherentMemoryPtr ResourceTracker::createCoherentMemory(
VkDevice device, VkDeviceMemory mem, const VkMemoryAllocateInfo& hostAllocationInfo, VkDevice device, VkDeviceMemory mem, const VkMemoryAllocateInfo& hostAllocationInfo,
VkEncoder* enc, VkResult& res) { VkEncoder* enc, VkResult& res) {
@@ -3777,25 +3751,17 @@ VkResult ResourceTracker::on_vkAllocateMemory(void* context, VkResult input_resu
#endif #endif
VirtGpuResourcePtr colorBufferBlob = nullptr; VirtGpuResourcePtr colorBufferBlob = nullptr;
#if defined(__linux__) && !defined(VK_USE_PLATFORM_ANDROID_KHR) #if defined(LINUX_GUEST_BUILD)
if (exportDmabuf) { if (exportDmabuf) {
VirtGpuDevice* instance = VirtGpuDevice::getInstance(); 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<wsi_memory_allocate_info>(pAllocateInfo);
bool hasDedicatedImage = bool hasDedicatedImage =
dedicatedAllocInfoPtr && (dedicatedAllocInfoPtr->image != VK_NULL_HANDLE); dedicatedAllocInfoPtr && (dedicatedAllocInfoPtr->image != VK_NULL_HANDLE);
bool hasDedicatedBuffer = bool hasDedicatedBuffer =
dedicatedAllocInfoPtr && (dedicatedAllocInfoPtr->buffer != VK_NULL_HANDLE); 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) { if (hasDedicatedImage) {
VkImageCreateInfo imageCreateInfo; VkImageCreateInfo imageCreateInfo;
bool isDmaBufImage = false;
{ {
AutoLock<RecursiveLock> lock(mLock); AutoLock<RecursiveLock> lock(mLock);
@@ -3804,67 +3770,62 @@ VkResult ResourceTracker::on_vkAllocateMemory(void* context, VkResult input_resu
const auto& imageInfo = it->second; const auto& imageInfo = it->second;
imageCreateInfo = imageInfo.createInfo; imageCreateInfo = imageInfo.createInfo;
isDmaBufImage = imageInfo.isDmaBufImage;
} }
uint32_t virglFormat = 0; // TODO (b/326956485): Support DRM format modifiers for dmabuf memory
uint32_t target = 0; // For now, can only externalize memory for linear images
uint32_t bind = 0; if (isDmaBufImage) {
uint32_t bpp = 0; const VkImageSubresource imageSubresource = {
if (!gfxstream::vk::getVirtGpuFormatParams(imageCreateInfo.format, &virglFormat, .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
&target, &bind, &bpp)) { .mipLevel = 0,
mesa_loge("%s: Unsupported VK format for VirtGpu resource, vkFormat: 0x%x", .arrayLayer = 0,
__func__, imageCreateInfo.format); };
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;
}
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; return VK_ERROR_FORMAT_NOT_SUPPORTED;
} }
const uint32_t stride = imageCreateInfo.extent.width * bpp; const uint32_t target = PIPE_TEXTURE_2D;
colorBufferBlob = instance->createResource(imageCreateInfo.extent.width, uint32_t bind = VIRGL_BIND_RENDER_TARGET;
imageCreateInfo.extent.height, stride, if (VK_IMAGE_TILING_LINEAR == imageCreateInfo.tiling) {
virglFormat, target, bind); bind |= VIRGL_BIND_LINEAR;
}
colorBufferBlob = instance->createResource(
imageCreateInfo.extent.width, imageCreateInfo.extent.height,
subResourceLayout.rowPitch, virglFormat, target, bind);
if (!colorBufferBlob) { if (!colorBufferBlob) {
mesa_loge("%s: Failed to create colorBuffer resource for Image memory\n", __func__); mesa_loge("Failed to create colorBuffer resource for Image memory");
return VK_ERROR_OUT_OF_DEVICE_MEMORY; return VK_ERROR_OUT_OF_DEVICE_MEMORY;
} }
if (0 != colorBufferBlob->wait()) { if (!colorBufferBlob->wait()) {
mesa_loge("%s: Failed to wait for colorBuffer resource for Image memory\n", mesa_loge("Failed to wait for colorBuffer resource for Image memory");
__func__);
return VK_ERROR_OUT_OF_DEVICE_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) {
if (hasDedicatedBuffer) { mesa_logw(
VkBufferCreateInfo bufferCreateInfo; "VkDeviceMemory allocated with VkMemoryDedicatedAllocateInfo::buffer cannot be "
{ "exported (VkExportMemoryAllocateInfo)");
AutoLock<RecursiveLock> lock(mLock); } else {
mesa_logw(
auto it = info_VkBuffer.find(dedicatedAllocInfoPtr->buffer); "VkDeviceMemory is not exportable (VkExportMemoryAllocateInfo). Requires "
if (it == info_VkBuffer.end()) return VK_ERROR_INITIALIZATION_FAILED; "VkMemoryDedicatedAllocateInfo::image to create external resource.");
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;
}
} }
} }
@@ -4136,20 +4097,31 @@ VkResult ResourceTracker::on_vkCreateImage(void* context, VkResult, VkDevice dev
vk_append_struct(&structChainIter, &localExtImgCi); vk_append_struct(&structChainIter, &localExtImgCi);
} }
bool isWsiImage = false; #if defined(LINUX_GUEST_BUILD)
bool isDmaBufImage = false;
#if defined(__linux__) && !defined(VK_USE_PLATFORM_ANDROID_KHR)
if (extImgCiPtr && if (extImgCiPtr &&
(extImgCiPtr->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) { (extImgCiPtr->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) {
// Assumes that handleType with DMA_BUF_BIT indicates creation of a const wsi_image_create_info* wsiImageCi =
// image for WSI use; no other external dma_buf usage is supported vk_find_struct<wsi_image_create_info>(pCreateInfo);
isWsiImage = true; if (wsiImageCi) {
// Must be linear. Otherwise querying stride and other properties if (!wsiImageCi->scanout) {
// can be implementation-dependent. mesa_logd(
localCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; "gfxstream only supports native DRM image scanout path for Linux WSI "
if (gfxstream::vk::getVirglFormat(localCreateInfo.format) < 0) { "(wsi_image_create_info::scanout)");
localCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; 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 #endif
@@ -4324,19 +4296,25 @@ VkResult ResourceTracker::on_vkCreateImage(void* context, VkResult, VkDevice dev
} }
#endif #endif
info.isWsiImage = isWsiImage;
// Delete `protocolVersion` check goldfish drivers are gone. // 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) { if (mCaps.vulkanCapset.colorBufferMemoryIndex == 0xFFFFFFFF) {
mCaps.vulkanCapset.colorBufferMemoryIndex = getColorBufferMemoryIndex(context, device); mCaps.vulkanCapset.colorBufferMemoryIndex = getColorBufferMemoryIndex(context, device);
} }
if (isWsiImage || if ((extImgCiPtr && (extImgCiPtr->handleTypes &
(extImgCiPtr && (extImgCiPtr->handleTypes &
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID))) { VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID))) {
updateMemoryTypeBits(&memReqs.memoryTypeBits, mCaps.vulkanCapset.colorBufferMemoryIndex); updateMemoryTypeBits(&memReqs.memoryTypeBits, mCaps.vulkanCapset.colorBufferMemoryIndex);
} }
#endif #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) { if (info.baseRequirementsKnown) {
transformImageMemoryRequirementsForGuestLocked(*pImage, &memReqs); transformImageMemoryRequirementsForGuestLocked(*pImage, &memReqs);

View File

@@ -781,7 +781,9 @@ class ResourceTracker {
#ifdef VK_USE_PLATFORM_FUCHSIA #ifdef VK_USE_PLATFORM_FUCHSIA
bool isSysmemBackedMemory = false; bool isSysmemBackedMemory = false;
#endif #endif
bool isWsiImage = false; #ifdef LINUX_GUEST_BUILD
bool isDmaBufImage = false;
#endif
}; };
struct VkBuffer_Info { struct VkBuffer_Info {

View File

@@ -20,6 +20,10 @@
#include "vk_android_native_buffer_gfxstream.h" #include "vk_android_native_buffer_gfxstream.h"
#include "vulkan_gfxstream.h" #include "vulkan_gfxstream.h"
#if defined(LINUX_GUEST_BUILD)
#include "vulkan/wsi/wsi_common.h"
#endif
// anonymous // anonymous
namespace { namespace {
@@ -125,6 +129,9 @@ REGISTER_VK_STRUCT_ID(VkDeviceCreateInfo, VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);
REGISTER_VK_STRUCT_ID(VkPhysicalDeviceGroupProperties, REGISTER_VK_STRUCT_ID(VkPhysicalDeviceGroupProperties,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES); VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES);
REGISTER_VK_STRUCT_ID(VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT); 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 #undef REGISTER_VK_STRUCT_ID