render/vulkan: Use VK_EXT_host_image_copy for shm

When uploading shm buffers to our internal backing texture, we first
allocate suitable chunk from our staging buffer accessible from both CPU
and GPU, and then we queue a GPU-side copy from the staging buffer to
the texture. This is a lot of copying, especially on iGPUs where
everything is system memory anyway.

Instead, use VK_EXT_host_image_copy when available for formats that are
reported as having optimal device access. This allows us to copy
directly to the target texture from CPU, eliminating the queued GPU-side
copy. To keep things simple we keep this texture in GENERAL for the
entire duration for now.
This commit is contained in:
Kenny Levinsen 2026-04-17 01:08:25 +02:00
parent e8c03e9ce9
commit 9a457a3f1d
4 changed files with 199 additions and 17 deletions

View file

@ -540,8 +540,12 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
"falling back to blocking");
}
VkPhysicalDeviceHostImageCopyFeaturesEXT phdev_host_image_copy_features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT,
};
VkPhysicalDeviceSamplerYcbcrConversionFeatures phdev_sampler_ycbcr_features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES,
.pNext = &phdev_host_image_copy_features,
};
VkPhysicalDeviceFeatures2 phdev_features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
@ -553,6 +557,12 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
wlr_log(WLR_DEBUG, "Sampler YCbCr conversion %s",
dev->sampler_ycbcr_conversion ? "supported" : "not supported");
dev->host_image_copy =
check_extension(avail_ext_props, avail_extc, VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME) &&
phdev_host_image_copy_features.hostImageCopy;
wlr_log(WLR_DEBUG, "Host image copy %s",
dev->host_image_copy ? "supported" : "not supported");
const float prio = 1.f;
VkDeviceQueueCreateInfo qinfo = {
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
@ -592,9 +602,22 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
.pNext = &sync2_features,
.timelineSemaphore = VK_TRUE,
};
VkPhysicalDeviceHostImageCopyFeaturesEXT host_image_copy_features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT,
.pNext = &timeline_features,
.hostImageCopy = VK_TRUE,
};
const void *features_chain = &timeline_features;
if (dev->host_image_copy) {
extensions[extensions_len++] = VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME;
extensions[extensions_len++] = VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME;
extensions[extensions_len++] = VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME;
features_chain = &host_image_copy_features;
}
VkDeviceCreateInfo dev_info = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = &timeline_features,
.pNext = features_chain,
.queueCreateInfoCount = 1u,
.pQueueCreateInfos = &qinfo,
.enabledExtensionCount = extensions_len,
@ -637,6 +660,13 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
load_device_proc(dev, "vkImportSemaphoreFdKHR", &dev->api.vkImportSemaphoreFdKHR);
}
if (dev->host_image_copy) {
load_device_proc(dev, "vkCopyMemoryToImageEXT",
&dev->api.vkCopyMemoryToImageEXT);
load_device_proc(dev, "vkTransitionImageLayoutEXT",
&dev->api.vkTransitionImageLayoutEXT);
}
size_t max_fmts;
const struct wlr_vk_format *fmts = vulkan_get_format_list(&max_fmts);
dev->format_props = calloc(max_fmts, sizeof(*dev->format_props));