/* * Copyright © 2025 Erico Nunes * * Based on wlroots' vulkan pixel_format.c * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "config.h" #include #include #include "pixel-formats.h" #include "shared/xalloc.h" #include "vulkan-renderer-internal.h" #include #include static const VkImageUsageFlags image_tex_usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; static const VkFormatFeatureFlags format_tex_features = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; static bool query_modifier_usage_support(struct vulkan_renderer *vr, VkFormat vk_format, VkImageUsageFlags usage, const VkDrmFormatModifierPropertiesEXT *m) { VkResult result; assert(vulkan_device_has(vr, EXTENSION_EXT_IMAGE_DRM_FORMAT_MODIFIER)); VkPhysicalDeviceImageFormatInfo2 pdev_image_format_info = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, .type = VK_IMAGE_TYPE_2D, .format = vk_format, .usage = usage, .flags = 0, .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, }; VkPhysicalDeviceExternalImageFormatInfo pdev_ext_image_format_info = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, }; pnext(&pdev_image_format_info, &pdev_ext_image_format_info); VkPhysicalDeviceImageDrmFormatModifierInfoEXT pdev_image_drm_format_mod_info = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT, .drmFormatModifier = m->drmFormatModifier, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, }; pnext(&pdev_image_format_info, &pdev_image_drm_format_mod_info); VkImageFormatListCreateInfoKHR image_format_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR, .pViewFormats = &vk_format, .viewFormatCount = 1, }; pnext(&pdev_image_format_info, &image_format_info); VkImageFormatProperties2 image_format_props = { .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, }; VkExternalImageFormatProperties ext_image_format_props = { .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, }; pnext(&image_format_props, &ext_image_format_props); const VkExternalMemoryProperties *ext_mem_props = &ext_image_format_props.externalMemoryProperties; result = vkGetPhysicalDeviceImageFormatProperties2(vr->phys_dev, &pdev_image_format_info, &image_format_props); if (result != VK_SUCCESS && result != VK_ERROR_FORMAT_NOT_SUPPORTED) return false; if (!(ext_mem_props->externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT)) return false; return true; } static bool query_dmabuf_support(struct vulkan_renderer *vr, VkFormat vk_format, VkImageFormatProperties *out) { VkResult result; assert(vulkan_device_has(vr, EXTENSION_KHR_IMAGE_FORMAT_LIST)); VkPhysicalDeviceImageFormatInfo2 pdev_image_format_info = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, .type = VK_IMAGE_TYPE_2D, .format = vk_format, .tiling = VK_IMAGE_TILING_OPTIMAL, .usage = image_tex_usage, .flags = 0, }; VkImageFormatListCreateInfoKHR image_format_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR, .pViewFormats = &vk_format, .viewFormatCount = 1, }; pnext(&pdev_image_format_info, &image_format_info); VkImageFormatProperties2 image_format_props = { image_format_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, }; result = vkGetPhysicalDeviceImageFormatProperties2(vr->phys_dev, &pdev_image_format_info, &image_format_props); if (result != VK_SUCCESS) { if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) { weston_log("unsupported dmabuf format 0x%08x\n", vk_format); } else { weston_log("failed to get dmabuf format properties 0x%08x\n", vk_format); } return false; } *out = image_format_props.imageFormatProperties; return true; } static void query_dmabuf_modifier_support(struct vulkan_renderer *vr, const struct pixel_format_info *format, struct weston_drm_format *fmt) { if (!vulkan_device_has(vr, EXTENSION_EXT_IMAGE_DRM_FORMAT_MODIFIER)) { uint64_t modifier = DRM_FORMAT_MOD_INVALID; int ret = weston_drm_format_add_modifier(fmt, modifier); assert(ret == 0); return; } VkDrmFormatModifierPropertiesListEXT drm_format_mod_props = { drm_format_mod_props.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT, }; VkFormatProperties2 format_props = { .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, }; pnext(&format_props, &drm_format_mod_props); vkGetPhysicalDeviceFormatProperties2(vr->phys_dev, format->vulkan_format, &format_props); size_t modifier_count = drm_format_mod_props.drmFormatModifierCount; drm_format_mod_props.drmFormatModifierCount = modifier_count; drm_format_mod_props.pDrmFormatModifierProperties = xzalloc(modifier_count * sizeof(*drm_format_mod_props.pDrmFormatModifierProperties)); vkGetPhysicalDeviceFormatProperties2(vr->phys_dev, format->vulkan_format, &format_props); for (uint32_t i = 0; i < drm_format_mod_props.drmFormatModifierCount; ++i) { VkDrmFormatModifierPropertiesEXT m = drm_format_mod_props.pDrmFormatModifierProperties[i]; // check that specific modifier for texture usage if ((m.drmFormatModifierTilingFeatures & format_tex_features) != format_tex_features) continue; if (!query_modifier_usage_support(vr, format->vulkan_format, image_tex_usage, &m)) continue; int ret = weston_drm_format_add_modifier(fmt, m.drmFormatModifier); assert(ret == 0); } free(drm_format_mod_props.pDrmFormatModifierProperties); } bool vulkan_renderer_query_dmabuf_format(struct vulkan_renderer *vr, const struct pixel_format_info *format) { VkFormatProperties2 format_props = { .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, }; vkGetPhysicalDeviceFormatProperties2(vr->phys_dev, format->vulkan_format, &format_props); struct weston_drm_format *fmt = NULL; // dmabuf texture properties if ((format_props.formatProperties.optimalTilingFeatures & format_tex_features) != format_tex_features) return false; VkImageFormatProperties iformat_props; if (!query_dmabuf_support(vr, format->vulkan_format, &iformat_props)) return false; fmt = weston_drm_format_array_add_format(&vr->supported_formats, format->format); assert(fmt); query_dmabuf_modifier_support(vr, format, fmt); return true; } static const VkFormatFeatureFlags format_shm_tex_features = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; bool vulkan_renderer_query_shm_format(struct vulkan_renderer *vr, const struct pixel_format_info *format) { assert(vulkan_instance_has(vr, EXTENSION_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2)); VkFormatProperties2 format_props = { .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, }; vkGetPhysicalDeviceFormatProperties2(vr->phys_dev, format->vulkan_format, &format_props); if ((format_props.formatProperties.optimalTilingFeatures & format_shm_tex_features) != format_shm_tex_features) return false; return true; }