weston/libweston/renderer-vulkan/vulkan-pixel-format.c

244 lines
8 KiB
C
Raw Permalink Normal View History

/*
* 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 <vulkan/vulkan.h>
#include <stdint.h>
#include "pixel-formats.h"
#include "shared/xalloc.h"
#include "vulkan-renderer-internal.h"
#include <xf86drm.h>
#include <drm_fourcc.h>
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;
}