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
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;

View File

@@ -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<wsi_memory_allocate_info>(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<RecursiveLock> 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<RecursiveLock> 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<wsi_image_create_info>(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);

View File

@@ -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 {

View File

@@ -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