gfxstream: Full emulation support for VK_EXT_image_drm_format_modifier

- Fix the checks for emulation (based on presence of the extension
on the host)
- Add flag in gfxstream_vk_physical_device, otherwise the real device
extensions are not properly filtered when communicating with the host.
- The "function" version of the check in ResourceTracker can eventually
just check the flag once mesa and gfxstream objects are combined
- Remove the duplicate getPhysicalDeviceFormatProperties2 impl, this is
covered by the ResourceTracker impl
- Add ResourceTracker impl for getImageDrmFormatModifierPropertiesEXT
- Remove isDmaBufImage flag from VkImage_info, and clean up all the code
associated with this flag. In on_vkCreateImage, all required info is
avaialble from the extMemImageCi::handleType. In on_vkAllocateMemory,
this is all associated with the tiling of the dedicatedImage for the
allocation

Reviewed-By: Gurchetan Singh <gurchetansingh@google.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33944>
This commit is contained in:
Aaron Ruby 2025-03-06 14:17:04 -05:00 committed by Marge Bot
parent 4197081329
commit 2e15763686
5 changed files with 272 additions and 208 deletions

View file

@ -18,6 +18,7 @@ RESOURCE_TRACKER_ENTRIES = [
"vkGetImageMemoryRequirements",
"vkGetImageMemoryRequirements2",
"vkGetImageMemoryRequirements2KHR",
"vkGetImageDrmFormatModifierPropertiesEXT",
"vkBindImageMemory",
"vkBindImageMemory2",
"vkBindImageMemory2KHR",
@ -52,6 +53,8 @@ RESOURCE_TRACKER_ENTRIES = [
"vkDestroySamplerYcbcrConversionKHR",
"vkUpdateDescriptorSetWithTemplate",
"vkUpdateDescriptorSetWithTemplateKHR",
"vkGetPhysicalDeviceFormatProperties2",
"vkGetPhysicalDeviceFormatProperties2KHR",
"vkGetPhysicalDeviceImageFormatProperties2",
"vkGetPhysicalDeviceImageFormatProperties2KHR",
"vkBeginCommandBuffer",
@ -128,7 +131,6 @@ HANDWRITTEN_ENTRY_POINTS = [
# TODO: Make a codegen module (use deepcopy as reference) to make this more robust
"vkAllocateMemory",
"vkUpdateDescriptorSets",
"vkGetPhysicalDeviceFormatProperties2",
]
# Handles that need to be translated to/from their corresponding gfxstream object types

View file

@ -137,12 +137,20 @@ static std::vector<const char*> filteredInstanceExtensionNames(uint32_t count,
return retList;
}
static std::vector<const char*> filteredDeviceExtensionNames(uint32_t count,
const char* const* extNames) {
static std::vector<const char*> filteredDeviceExtensionNames(
gfxstream_vk_physical_device* physical_device, uint32_t count, const char* const* extNames) {
std::vector<const char*> retList;
for (uint32_t i = 0; i < count; ++i) {
auto extName = extNames[i];
if (!isGuestOnlyDeviceExtension(extName)) {
// VK_EXT_image_drm_format_modifier
if (!strncmp(extName, VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
VK_MAX_EXTENSION_NAME_SIZE)) {
if (physical_device->doImageDrmFormatModifierEmulation) {
// If emulated, drop this exension from the filtered list
} else {
retList.push_back(extName);
}
} else if (!isGuestOnlyDeviceExtension(extName)) {
retList.push_back(extName);
}
}
@ -162,7 +170,7 @@ static void get_device_extensions(VkPhysicalDevice physDevInternal,
result = resources->on_vkEnumerateDeviceExtensionProperties(
vkEnc, VK_SUCCESS, physDevInternal, NULL, &numDeviceExts, extProps.data());
if (VK_SUCCESS == result) {
// device extensions from gfxstream
// device extensions from the host's physical device
for (uint32_t i = 0; i < numDeviceExts; i++) {
for (uint32_t j = 0; j < VK_DEVICE_EXTENSION_COUNT; j++) {
if (0 == strncmp(extProps[i].extensionName,
@ -190,6 +198,15 @@ static VkResult gfxstream_vk_physical_device_init(
struct vk_device_extension_table supported_extensions = {};
get_device_extensions(internal_object, &supported_extensions);
// VK_EXT_image_drm_format_modifier support is either emulated, or passthrough using
// host functionality
if (!supported_extensions.EXT_image_drm_format_modifier) {
physical_device->doImageDrmFormatModifierEmulation = true;
supported_extensions.EXT_image_drm_format_modifier = true;
} else {
physical_device->doImageDrmFormatModifierEmulation = false;
}
struct vk_physical_device_dispatch_table dispatch_table;
memset(&dispatch_table, 0, sizeof(struct vk_physical_device_dispatch_table));
vk_physical_device_dispatch_table_from_entrypoints(
@ -461,7 +478,8 @@ VkResult gfxstream_vk_CreateDevice(VkPhysicalDevice physicalDevice,
VkDeviceCreateInfo localCreateInfo = *pCreateInfo;
std::vector<const char*> filteredExts = filteredDeviceExtensionNames(
localCreateInfo.enabledExtensionCount, localCreateInfo.ppEnabledExtensionNames);
gfxstream_physicalDevice, localCreateInfo.enabledExtensionCount,
localCreateInfo.ppEnabledExtensionNames);
localCreateInfo.enabledExtensionCount = static_cast<uint32_t>(filteredExts.size());
localCreateInfo.ppEnabledExtensionNames = filteredExts.data();
@ -745,29 +763,3 @@ void gfxstream_vk_UpdateDescriptorSets(VkDevice device, uint32_t descriptorWrite
internal_pDescriptorWrites.data(), descriptorCopyCount, pDescriptorCopies);
}
}
void gfxstream_vk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,
VkFormat format,
VkFormatProperties2* pFormatProperties) {
MESA_TRACE_SCOPE("vkGetPhysicalDeviceFormatProperties2");
VK_FROM_HANDLE(gfxstream_vk_physical_device, gfxstream_physicalDevice, physicalDevice);
{
auto vkEnc = gfxstream::vk::ResourceTracker::getThreadLocalEncoder();
vkEnc->vkGetPhysicalDeviceFormatProperties2(gfxstream_physicalDevice->internal_object,
format, pFormatProperties, true /* do lock */);
}
VkDrmFormatModifierPropertiesListEXT* drmFmtMod =
vk_find_struct(pFormatProperties, DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT);
if (drmFmtMod) {
drmFmtMod->drmFormatModifierCount = 1;
if (drmFmtMod->pDrmFormatModifierProperties) {
drmFmtMod->pDrmFormatModifierProperties[0] = {
.drmFormatModifier = 0,
.drmFormatModifierPlaneCount = 1,
.drmFormatModifierTilingFeatures =
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT};
}
}
}

View file

@ -1301,12 +1301,6 @@ void ResourceTracker::setInstanceInfo(VkInstance instance, uint32_t enabledExten
std::lock_guard<std::recursive_mutex> lock(mLock);
auto& info = info_VkInstance[instance];
info.highestApiVersion = apiVersion;
if (!ppEnabledExtensionNames) return;
for (uint32_t i = 0; i < enabledExtensionCount; ++i) {
info.enabledExtensions.insert(ppEnabledExtensionNames[i]);
}
}
void ResourceTracker::setDeviceInfo(VkDevice device, VkPhysicalDevice physdev,
@ -1337,12 +1331,6 @@ void ResourceTracker::setDeviceInfo(VkDevice device, VkPhysicalDevice physdev,
}
extensionCreateInfo = extensionCreateInfo->pNext;
}
if (!ppEnabledExtensionNames) return;
for (uint32_t i = 0; i < enabledExtensionCount; ++i) {
info.enabledExtensions.insert(ppEnabledExtensionNames[i]);
}
}
void ResourceTracker::setDeviceMemoryInfo(VkDevice device, VkDeviceMemory memory,
@ -1794,7 +1782,10 @@ VkResult ResourceTracker::on_vkEnumerateDeviceExtensionProperties(
"VK_EXT_device_memory_report",
#endif
#ifdef LINUX_GUEST_BUILD
// Required by Zink
"VK_KHR_imageless_framebuffer",
// Will be emulated on guest if not available on host
"VK_EXT_image_drm_format_modifier",
#endif
// Vulkan 1.3
"VK_KHR_synchronization2",
@ -1899,9 +1890,6 @@ VkResult ResourceTracker::on_vkEnumerateDeviceExtensionProperties(
#ifdef LINUX_GUEST_BUILD
filteredExts.push_back(VkExtensionProperties{"VK_KHR_external_memory_fd", 1});
filteredExts.push_back(VkExtensionProperties{"VK_EXT_external_memory_dma_buf", 1});
// In case the host doesn't support format modifiers, they are emulated
// on guest side.
filteredExts.push_back(VkExtensionProperties{"VK_EXT_image_drm_format_modifier", 1});
#endif
}
@ -3398,8 +3386,7 @@ VkResult ResourceTracker::on_vkAllocateMemory(void* context, VkResult input_resu
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
#endif // VK_USE_PLATFORM_FUCHSIA
exportDmabuf =
exportAllocateInfoPtr->handleTypes & (VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
(exportAllocateInfoPtr->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
} else if (importAhbInfoPtr) {
importAhb = true;
} else if (importBufferCollectionInfoPtr) {
@ -3412,8 +3399,7 @@ VkResult ResourceTracker::on_vkAllocateMemory(void* context, VkResult input_resu
vk_find_struct_const(pAllocateInfo, IMPORT_MEMORY_FD_INFO_KHR);
if (importFdInfoPtr) {
importDmabuf =
(importFdInfoPtr->handleType & (VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT));
(importFdInfoPtr->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
}
bool isImport = importAhb || importBufferCollection || importVmo || importDmabuf;
@ -3814,7 +3800,6 @@ VkResult ResourceTracker::on_vkAllocateMemory(void* context, VkResult input_resu
if (hasDedicatedImage) {
VkImageCreateInfo imageCreateInfo;
bool isDmaBufImage = false;
{
std::lock_guard<std::recursive_mutex> lock(mLock);
@ -3823,98 +3808,94 @@ VkResult ResourceTracker::on_vkAllocateMemory(void* context, VkResult input_resu
const auto& imageInfo = it->second;
imageCreateInfo = imageInfo.createInfo;
isDmaBufImage = imageInfo.isDmaBufImage;
}
if (isDmaBufImage) {
const VkImageSubresource imageSubresource = {
.aspectMask = exportAllocateInfoPtr->handleTypes &
VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT
? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT
: VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.arrayLayer = 0,
};
VkSubresourceLayout subResourceLayout;
enc->vkGetImageSubresourceLayout(device, dedicatedAllocInfoPtr->image,
&imageSubresource, &subResourceLayout,
true /* do lock */);
// Need to query the stride of the underyling image resource
// (VkSubresourceLayout::rowPitch) In most cases, the application will have created the
// VkImage w/ VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, in which case the aspectMask to
// query is the PLANE_0_BIT resource. Otherwise, query the more generic COLOR_BIT.
// Note: For VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, the image may actually be emulated
// with VK_IMAGE_TILING_LINEAR.
const VkImageSubresource imageSubresource = {
.aspectMask = (imageCreateInfo.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
? VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT
: 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("Failed to query stride for VirtGpu resource creation.");
return VK_ERROR_INITIALIZATION_FAILED;
}
if (!subResourceLayout.rowPitch) {
mesa_loge("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;
}
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;
}
if (mCaps.vulkanCapset.alwaysBlob) {
struct gfxstreamResourceCreate3d create3d = {};
struct VirtGpuExecBuffer exec = {};
struct gfxstreamPlaceholderCommandVk placeholderCmd = {};
struct VirtGpuCreateBlob createBlob = {};
create3d.hdr.opCode = GFXSTREAM_RESOURCE_CREATE_3D;
create3d.bind = bind;
create3d.target = target;
create3d.format = virglFormat;
create3d.width = imageCreateInfo.extent.width;
create3d.height = imageCreateInfo.extent.height;
create3d.blobId = ++mAtomicId;
createBlob.blobCmd = reinterpret_cast<uint8_t*>(&create3d);
createBlob.blobCmdSize = sizeof(create3d);
createBlob.blobMem = kBlobMemHost3d;
createBlob.flags = kBlobFlagShareable | kBlobFlagCrossDevice;
createBlob.blobId = create3d.blobId;
createBlob.size = finalAllocInfo.allocationSize;
bufferBlob = instance->createBlob(createBlob);
if (!bufferBlob) return VK_ERROR_OUT_OF_DEVICE_MEMORY;
placeholderCmd.hdr.opCode = GFXSTREAM_PLACEHOLDER_COMMAND_VK;
exec.command = static_cast<void*>(&placeholderCmd);
exec.command_size = sizeof(placeholderCmd);
exec.flags = kRingIdx;
exec.ring_idx = 1;
if (instance->execBuffer(exec, bufferBlob.get())) {
mesa_loge("Failed to execbuffer placeholder command.");
return VK_ERROR_OUT_OF_HOST_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;
}
if (mCaps.vulkanCapset.alwaysBlob) {
struct gfxstreamResourceCreate3d create3d = {};
struct VirtGpuExecBuffer exec = {};
struct gfxstreamPlaceholderCommandVk placeholderCmd = {};
struct VirtGpuCreateBlob createBlob = {};
create3d.hdr.opCode = GFXSTREAM_RESOURCE_CREATE_3D;
create3d.bind = bind;
create3d.target = target;
create3d.format = virglFormat;
create3d.width = imageCreateInfo.extent.width;
create3d.height = imageCreateInfo.extent.height;
create3d.blobId = ++mAtomicId;
createBlob.blobCmd = reinterpret_cast<uint8_t*>(&create3d);
createBlob.blobCmdSize = sizeof(create3d);
createBlob.blobMem = kBlobMemHost3d;
createBlob.flags = kBlobFlagShareable | kBlobFlagCrossDevice;
createBlob.blobId = create3d.blobId;
createBlob.size = finalAllocInfo.allocationSize;
bufferBlob = instance->createBlob(createBlob);
if (!bufferBlob) return VK_ERROR_OUT_OF_DEVICE_MEMORY;
placeholderCmd.hdr.opCode = GFXSTREAM_PLACEHOLDER_COMMAND_VK;
exec.command = static_cast<void*>(&placeholderCmd);
exec.command_size = sizeof(placeholderCmd);
exec.flags = kRingIdx;
exec.ring_idx = 1;
if (instance->execBuffer(exec, bufferBlob.get())) {
mesa_loge("Failed to execbuffer placeholder command.");
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
if (bufferBlob->wait()) {
mesa_loge("Failed to wait for blob.");
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
} else {
bufferBlob = instance->createResource(
imageCreateInfo.extent.width, imageCreateInfo.extent.height,
subResourceLayout.rowPitch,
subResourceLayout.rowPitch * imageCreateInfo.extent.height, virglFormat,
target, bind);
if (!bufferBlob) {
mesa_loge("Failed to create colorBuffer resource for Image memory");
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
}
if (bufferBlob->wait()) {
mesa_loge("Failed to wait for colorBuffer resource for Image memory");
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
}
if (bufferBlob->wait()) {
mesa_loge("Failed to wait for blob.");
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
} else {
mesa_logw(
"The VkMemoryDedicatedAllocateInfo::image associated with VkDeviceMemory "
"allocation cannot be used to create exportable resource "
"(VkExportMemoryAllocateInfo).\n");
bufferBlob = instance->createResource(
imageCreateInfo.extent.width, imageCreateInfo.extent.height,
subResourceLayout.rowPitch,
subResourceLayout.rowPitch * imageCreateInfo.extent.height, virglFormat, target,
bind);
if (!bufferBlob) {
mesa_loge("Failed to create colorBuffer resource for Image memory");
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
}
if (bufferBlob->wait()) {
mesa_loge("Failed to wait for colorBuffer resource for Image memory");
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
}
}
} else if (hasDedicatedBuffer) {
uint32_t virglFormat = VIRGL_FORMAT_R8_UNORM;
@ -4268,10 +4249,10 @@ VkResult ResourceTracker::on_vkCreateImage(void* context, VkResult, VkDevice dev
}
#if defined(LINUX_GUEST_BUILD)
bool isDmaBufImage = false;
VkImageDrmFormatModifierExplicitCreateInfoEXT localDrmFormatModifierInfo;
VkImageDrmFormatModifierListCreateInfoEXT localDrmFormatModifierList;
// If the VkImage will be bound to guest-dmabuf memory
if (extImgCiPtr &&
(extImgCiPtr->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) {
const wsi_image_create_info* wsiImageCi =
@ -4289,9 +4270,35 @@ VkResult ResourceTracker::on_vkCreateImage(void* context, VkResult, VkDevice dev
vk_find_struct_const(pCreateInfo, IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
const VkImageDrmFormatModifierListCreateInfoEXT* drmFmtModList =
vk_find_struct_const(pCreateInfo, IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
if (drmFmtMod || drmFmtModList) {
if (getHostDeviceExtensionIndex(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME) !=
-1) {
if ((pCreateInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) &&
(drmFmtMod || drmFmtModList)) {
VkPhysicalDevice physicalDevice;
{
std::lock_guard<std::recursive_mutex> lock(mLock);
auto it = info_VkDevice.find(device);
if (it == info_VkDevice.end()) return VK_ERROR_UNKNOWN;
physicalDevice = it->second.physdev;
}
if (doImageDrmFormatModifierEmulation(physicalDevice)) {
bool canUseLinearModifier =
(drmFmtMod && drmFmtMod->drmFormatModifier == DRM_FORMAT_MOD_LINEAR) ||
std::any_of(
drmFmtModList->pDrmFormatModifiers,
drmFmtModList->pDrmFormatModifiers + drmFmtModList->drmFormatModifierCount,
[](const uint64_t mod) { return mod == DRM_FORMAT_MOD_LINEAR; });
// host doesn't support DRM format modifiers, try emulating
if (canUseLinearModifier) {
mesa_logd(
"vkCreateImage: emulating DRM_FORMAT_MOD_LINEAR with "
"VK_IMAGE_TILING_LINEAR");
localCreateInfo.tiling = VK_IMAGE_TILING_LINEAR;
} else {
mesa_loge(
"Host does not support DRM format modifiers; DRM_FORMAT_MOD_LINEAR must be "
"provided, as it is the only format modifier that can be emulated");
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
} else {
// host supports DRM format modifiers => forward the struct
if (drmFmtMod) {
localDrmFormatModifierInfo = vk_make_orphan_copy(*drmFmtMod);
@ -4301,24 +4308,8 @@ VkResult ResourceTracker::on_vkCreateImage(void* context, VkResult, VkDevice dev
localDrmFormatModifierList = vk_make_orphan_copy(*drmFmtModList);
vk_append_struct(&structChainIter, &localDrmFormatModifierList);
}
} else {
bool canUseLinearModifier =
(drmFmtMod && drmFmtMod->drmFormatModifier == DRM_FORMAT_MOD_LINEAR) ||
std::any_of(
drmFmtModList->pDrmFormatModifiers,
drmFmtModList->pDrmFormatModifiers + drmFmtModList->drmFormatModifierCount,
[](const uint64_t mod) { return mod == DRM_FORMAT_MOD_LINEAR; });
// host doesn't support DRM format modifiers, try emulating
if (canUseLinearModifier) {
mesa_logd("emulating DRM_FORMAT_MOD_LINEAR with VK_IMAGE_TILING_LINEAR");
localCreateInfo.tiling = VK_IMAGE_TILING_LINEAR;
} else {
return VK_ERROR_VALIDATION_FAILED_EXT;
}
}
}
isDmaBufImage = true;
}
#endif
@ -4507,8 +4498,8 @@ VkResult ResourceTracker::on_vkCreateImage(void* context, VkResult, VkDevice dev
if (mCaps.vulkanCapset.colorBufferMemoryIndex == 0xFFFFFFFF) {
mCaps.vulkanCapset.colorBufferMemoryIndex = getColorBufferMemoryIndex(context, device);
}
info.isDmaBufImage = isDmaBufImage;
if (info.isDmaBufImage) {
if (extImgCiPtr &&
(extImgCiPtr->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) {
updateMemoryTypeBits(&memReqs.memoryTypeBits, mCaps.vulkanCapset.colorBufferMemoryIndex);
}
#endif
@ -5357,6 +5348,31 @@ void ResourceTracker::on_vkGetImageMemoryRequirements2KHR(
transformImageMemoryRequirements2ForGuest(pInfo->image, pMemoryRequirements);
}
VkResult ResourceTracker::on_vkGetImageDrmFormatModifierPropertiesEXT(
void* context, VkResult, VkDevice device, VkImage image,
VkImageDrmFormatModifierPropertiesEXT* pProperties) {
#ifdef LINUX_GUEST_BUILD
auto it = info_VkDevice.find(device);
if (it == info_VkDevice.end()) return VK_ERROR_UNKNOWN;
if (doImageDrmFormatModifierEmulation(it->second.physdev)) {
// This is the only format modifier that will be used in emulation
pProperties->drmFormatModifier = DRM_FORMAT_MOD_LINEAR;
return VK_SUCCESS;
} else {
// Passthrough to host
VkEncoder* enc = (VkEncoder*)context;
return enc->vkGetImageDrmFormatModifierPropertiesEXT(device, image, pProperties,
true /* do lock */);
}
#else
(void)context;
(void)device;
(void)image;
(void)pProperties;
return VK_ERROR_INCOMPATIBLE_DRIVER;
#endif
}
VkResult ResourceTracker::on_vkBindImageMemory(void* context, VkResult, VkDevice device,
VkImage image, VkDeviceMemory memory,
VkDeviceSize memoryOffset) {
@ -6673,6 +6689,49 @@ void ResourceTracker::on_vkUpdateDescriptorSetWithTemplateKHR(
pData);
}
#ifdef LINUX_GUEST_BUILD
static void fillEmulatedDrmFormatModPropsList(
const VkFormatProperties* pFormatProperties,
VkDrmFormatModifierPropertiesListEXT* emulatedDrmFmtModPropsList) {
mesa_logd(
"VkDrmFormatModifierPropertiesListEXT: emulating DRM_FORMAT_MOD_LINEAR with linear tiling "
"features");
emulatedDrmFmtModPropsList->drmFormatModifierCount = 1;
if (emulatedDrmFmtModPropsList->pDrmFormatModifierProperties) {
emulatedDrmFmtModPropsList->pDrmFormatModifierProperties[0] = {
.drmFormatModifier = DRM_FORMAT_MOD_LINEAR,
.drmFormatModifierPlaneCount = 1,
.drmFormatModifierTilingFeatures = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT,
};
};
}
#endif
void ResourceTracker::on_vkGetPhysicalDeviceFormatProperties2(
void* context, VkPhysicalDevice physicalDevice, VkFormat format,
VkFormatProperties2* pFormatProperties) {
VkEncoder* enc = (VkEncoder*)context;
enc->vkGetPhysicalDeviceFormatProperties2(physicalDevice, format, pFormatProperties,
true /* do lock */);
#ifdef LINUX_GUEST_BUILD
VkDrmFormatModifierPropertiesListEXT* emulatedDrmFmtModPropsList =
vk_find_struct(pFormatProperties, DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT);
if (emulatedDrmFmtModPropsList && doImageDrmFormatModifierEmulation(physicalDevice)) {
fillEmulatedDrmFormatModPropsList(&pFormatProperties->formatProperties,
emulatedDrmFmtModPropsList);
}
#endif
}
void ResourceTracker::on_vkGetPhysicalDeviceFormatProperties2KHR(
void* context, VkPhysicalDevice physicalDevice, VkFormat format,
VkFormatProperties2* pFormatProperties) {
on_vkGetPhysicalDeviceFormatProperties2(context, physicalDevice, format, pFormatProperties);
}
VkResult ResourceTracker::on_vkGetPhysicalDeviceImageFormatProperties2_common(
bool isKhr, void* context, VkResult input_result, VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
@ -6728,20 +6787,27 @@ VkResult ResourceTracker::on_vkGetPhysicalDeviceImageFormatProperties2_common(
const VkPhysicalDeviceImageDrmFormatModifierInfoEXT* drmFmtMod =
vk_find_struct_const(pImageFormatInfo, PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT);
VkDrmFormatModifierPropertiesListEXT* emulatedDrmFmtModPropsList = nullptr;
if (drmFmtMod &&
getHostDeviceExtensionIndex(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME) == -1) {
if (drmFmtMod->drmFormatModifier != DRM_FORMAT_MOD_LINEAR) {
return VK_ERROR_FORMAT_NOT_SUPPORTED;
if (drmFmtMod) {
if (doImageDrmFormatModifierEmulation(physicalDevice)) {
emulatedDrmFmtModPropsList =
vk_find_struct(pImageFormatProperties, DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT);
if (drmFmtMod->drmFormatModifier == DRM_FORMAT_MOD_LINEAR) {
// Remove the drmFmtMod from the localImageFormatInfo
vk_filter_struct(&localImageFormatInfo,
PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT);
mesa_logd(
"getPhysicalDeviceImageFormatProperties2: emulating DRM_FORMAT_MOD_LINEAR with "
"VK_IMAGE_TILING_LINEAR");
localImageFormatInfo.tiling = VK_IMAGE_TILING_LINEAR;
localImageFormatInfo.usage &=
~(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
} else {
return VK_ERROR_FORMAT_NOT_SUPPORTED;
}
} else {
// Host supports DRM format modifiers => leave the input unchanged.
}
mesa_logd("emulating DRM_FORMAT_MOD_LINEAR with VK_IMAGE_TILING_OPTIMAL");
emulatedDrmFmtModPropsList =
vk_find_struct(pImageFormatProperties, DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT);
localImageFormatInfo.tiling = VK_IMAGE_TILING_LINEAR;
localImageFormatInfo.usage &=
~(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
pImageFormatInfo = &localImageFormatInfo;
// Leave drmFormatMod in the input; it should be ignored when
// tiling is not VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT
}
#endif // LINUX_GUEST_BUILD
@ -6762,23 +6828,19 @@ VkResult ResourceTracker::on_vkGetPhysicalDeviceImageFormatProperties2_common(
VkFormatProperties formatProperties;
enc->vkGetPhysicalDeviceFormatProperties(physicalDevice, localImageFormatInfo.format,
&formatProperties, true /* do lock */);
emulatedDrmFmtModPropsList->drmFormatModifierCount = 1;
if (emulatedDrmFmtModPropsList->pDrmFormatModifierProperties) {
emulatedDrmFmtModPropsList->pDrmFormatModifierProperties[0] = {
.drmFormatModifier = DRM_FORMAT_MOD_LINEAR,
.drmFormatModifierPlaneCount = 1,
.drmFormatModifierTilingFeatures = formatProperties.linearTilingFeatures,
};
}
fillEmulatedDrmFormatModPropsList(&formatProperties, emulatedDrmFmtModPropsList);
}
if (ext_img_info &&
ext_img_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
ext_img_properties->externalMemoryProperties.externalMemoryFeatures |=
VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
ext_img_properties->externalMemoryProperties.exportFromImportedHandleTypes =
ext_img_properties->externalMemoryProperties.compatibleHandleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
if (ext_img_properties) {
if (ext_img_info) {
if (ext_img_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
ext_img_properties->externalMemoryProperties = {
.externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT,
.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
};
}
}
}
#endif // LINUX_GUEST_BUILD
@ -7442,23 +7504,19 @@ uint32_t ResourceTracker::getApiVersionFromDevice(VkDevice device) {
return api;
}
bool ResourceTracker::hasInstanceExtension(VkInstance instance, const std::string& name) {
#ifdef LINUX_GUEST_BUILD
bool ResourceTracker::doImageDrmFormatModifierEmulation(VkPhysicalDevice physicalDevice) {
std::lock_guard<std::recursive_mutex> lock(mLock);
auto it = info_VkInstance.find(instance);
if (it == info_VkInstance.end()) return false;
bool hostSupportsImageDrmFormatModifiers =
getHostDeviceExtensionIndex(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME) != -1;
return it->second.enabledExtensions.find(name) != it->second.enabledExtensions.end();
}
bool ResourceTracker::hasDeviceExtension(VkDevice device, const std::string& name) {
std::lock_guard<std::recursive_mutex> lock(mLock);
auto it = info_VkDevice.find(device);
if (it == info_VkDevice.end()) return false;
return it->second.enabledExtensions.find(name) != it->second.enabledExtensions.end();
// If the host device supports the extension, then this gets passed through for
// all functionality relating to the extension. If it doesn't, then this is emulated
// in the guest-side driver
return !hostSupportsImageDrmFormatModifiers;
}
#endif
VkDevice ResourceTracker::getDevice(VkCommandBuffer commandBuffer) const {
struct goldfish_VkCommandBuffer* cb = as_goldfish_VkCommandBuffer(commandBuffer);

View file

@ -220,6 +220,9 @@ class ResourceTracker {
void on_vkGetImageMemoryRequirements2KHR(void* context, VkDevice device,
const VkImageMemoryRequirementsInfo2* pInfo,
VkMemoryRequirements2* pMemoryRequirements);
VkResult on_vkGetImageDrmFormatModifierPropertiesEXT(
void* context, VkResult input_result, VkDevice device, VkImage image,
VkImageDrmFormatModifierPropertiesEXT* pProperties);
VkResult on_vkBindImageMemory(void* context, VkResult input_result, VkDevice device,
VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset);
@ -451,6 +454,14 @@ class ResourceTracker {
VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const void* pData);
void on_vkGetPhysicalDeviceFormatProperties2(void* context, VkPhysicalDevice physicalDevice,
VkFormat format,
VkFormatProperties2* pFormatProperties);
void on_vkGetPhysicalDeviceFormatProperties2KHR(void* context, VkPhysicalDevice physicalDevice,
VkFormat format,
VkFormatProperties2* pFormatProperties);
VkResult on_vkGetPhysicalDeviceImageFormatProperties2(
void* context, VkResult input_result, VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
@ -556,13 +567,18 @@ class ResourceTracker {
uint32_t getStreamFeatures() const;
uint32_t getApiVersionFromInstance(VkInstance instance);
uint32_t getApiVersionFromDevice(VkDevice device);
bool hasInstanceExtension(VkInstance instance, const std::string& name);
bool hasDeviceExtension(VkDevice instance, const std::string& name);
VkDevice getDevice(VkCommandBuffer commandBuffer) const;
void addToCommandPool(VkCommandPool commandPool, uint32_t commandBufferCount,
VkCommandBuffer* pCommandBuffers);
void resetCommandPoolStagingInfo(VkCommandPool commandPool);
#ifdef LINUX_GUEST_BUILD
// TODO: This information is tracked in
// gfxstream_vk_physical_device::doImageDrmFormatModifierEmulation, but mesa objects need to be
// combined with gfxstream objects
bool doImageDrmFormatModifierEmulation(VkPhysicalDevice physicalDevice);
#endif
#ifdef __GNUC__
#define ALWAYS_INLINE_GFXSTREAM
#elif
@ -733,7 +749,6 @@ class ResourceTracker {
struct VkInstance_Info {
uint32_t highestApiVersion;
std::set<std::string> enabledExtensions;
// Fodder for vkEnumeratePhysicalDevices.
std::vector<VkPhysicalDevice> physicalDevices;
};
@ -743,7 +758,6 @@ class ResourceTracker {
VkPhysicalDeviceProperties props;
VkPhysicalDeviceMemoryProperties memProps;
uint32_t apiVersion;
std::set<std::string> enabledExtensions;
std::vector<std::pair<PFN_vkDeviceMemoryReportCallbackEXT, void*>>
deviceMemoryReportCallbacks;
};
@ -800,9 +814,6 @@ class ResourceTracker {
#endif
#ifdef VK_USE_PLATFORM_FUCHSIA
bool isSysmemBackedMemory = false;
#endif
#ifdef LINUX_GUEST_BUILD
bool isDmaBufImage = false;
#endif
};

View file

@ -71,6 +71,7 @@ struct gfxstream_vk_physical_device {
struct wsi_device wsi_device;
const struct vk_sync_type* sync_types[2];
struct gfxstream_vk_instance* instance;
bool doImageDrmFormatModifierEmulation;
VkPhysicalDevice internal_object;
};