mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-24 21:55:58 +01:00
4d68d3759b
In query_modifier_support, the calloc for either or both of render_mods and texture_mods may fail, in which case both are freed for convenience. However, if one is non-NULL, vulkan_format_props_finish will try to free it again. NULL them to avoid double-free.
591 lines
17 KiB
C
591 lines
17 KiB
C
#include <drm_fourcc.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <vulkan/vulkan.h>
|
|
#include <wlr/util/log.h>
|
|
#include <xf86drm.h>
|
|
#include "render/pixel_format.h"
|
|
#include "render/vulkan.h"
|
|
|
|
static const struct wlr_vk_format formats[] = {
|
|
// Vulkan non-packed 8-bits-per-channel formats have an inverted channel
|
|
// order compared to the DRM formats, because DRM format channel order
|
|
// is little-endian while Vulkan format channel order is in memory byte
|
|
// order.
|
|
{
|
|
.drm = DRM_FORMAT_R8,
|
|
.vk = VK_FORMAT_R8_UNORM,
|
|
.vk_srgb = VK_FORMAT_R8_SRGB,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_GR88,
|
|
.vk = VK_FORMAT_R8G8_UNORM,
|
|
.vk_srgb = VK_FORMAT_R8G8_SRGB,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_RGB888,
|
|
.vk = VK_FORMAT_B8G8R8_UNORM,
|
|
.vk_srgb = VK_FORMAT_B8G8R8_SRGB,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_BGR888,
|
|
.vk = VK_FORMAT_R8G8B8_UNORM,
|
|
.vk_srgb = VK_FORMAT_R8G8B8_SRGB,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_XRGB8888,
|
|
.vk = VK_FORMAT_B8G8R8A8_UNORM,
|
|
.vk_srgb = VK_FORMAT_B8G8R8A8_SRGB,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_XBGR8888,
|
|
.vk = VK_FORMAT_R8G8B8A8_UNORM,
|
|
.vk_srgb = VK_FORMAT_R8G8B8A8_SRGB,
|
|
},
|
|
// The Vulkan _SRGB formats correspond to unpremultiplied alpha, but
|
|
// the Wayland protocol specifies premultiplied alpha on electrical values
|
|
{
|
|
.drm = DRM_FORMAT_ARGB8888,
|
|
.vk = VK_FORMAT_B8G8R8A8_UNORM,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_ABGR8888,
|
|
.vk = VK_FORMAT_R8G8B8A8_UNORM,
|
|
},
|
|
// Vulkan packed formats have the same channel order as DRM formats on
|
|
// little endian systems.
|
|
#if WLR_LITTLE_ENDIAN
|
|
{
|
|
.drm = DRM_FORMAT_RGBA4444,
|
|
.vk = VK_FORMAT_R4G4B4A4_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_RGBX4444,
|
|
.vk = VK_FORMAT_R4G4B4A4_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_BGRA4444,
|
|
.vk = VK_FORMAT_B4G4R4A4_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_BGRX4444,
|
|
.vk = VK_FORMAT_B4G4R4A4_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_RGB565,
|
|
.vk = VK_FORMAT_R5G6B5_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_BGR565,
|
|
.vk = VK_FORMAT_B5G6R5_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_RGBA5551,
|
|
.vk = VK_FORMAT_R5G5B5A1_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_RGBX5551,
|
|
.vk = VK_FORMAT_R5G5B5A1_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_BGRA5551,
|
|
.vk = VK_FORMAT_B5G5R5A1_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_BGRX5551,
|
|
.vk = VK_FORMAT_B5G5R5A1_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_ARGB1555,
|
|
.vk = VK_FORMAT_A1R5G5B5_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_XRGB1555,
|
|
.vk = VK_FORMAT_A1R5G5B5_UNORM_PACK16,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_ARGB2101010,
|
|
.vk = VK_FORMAT_A2R10G10B10_UNORM_PACK32,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_XRGB2101010,
|
|
.vk = VK_FORMAT_A2R10G10B10_UNORM_PACK32,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_ABGR2101010,
|
|
.vk = VK_FORMAT_A2B10G10R10_UNORM_PACK32,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_XBGR2101010,
|
|
.vk = VK_FORMAT_A2B10G10R10_UNORM_PACK32,
|
|
},
|
|
#endif
|
|
|
|
// Vulkan 16-bits-per-channel formats have an inverted channel order
|
|
// compared to DRM formats, just like the 8-bits-per-channel ones.
|
|
// On little endian systems the memory representation of each channel
|
|
// matches the DRM formats'.
|
|
#if WLR_LITTLE_ENDIAN
|
|
{
|
|
.drm = DRM_FORMAT_ABGR16161616,
|
|
.vk = VK_FORMAT_R16G16B16A16_UNORM,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_XBGR16161616,
|
|
.vk = VK_FORMAT_R16G16B16A16_UNORM,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_ABGR16161616F,
|
|
.vk = VK_FORMAT_R16G16B16A16_SFLOAT,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_XBGR16161616F,
|
|
.vk = VK_FORMAT_R16G16B16A16_SFLOAT,
|
|
},
|
|
#endif
|
|
|
|
// YCbCr formats
|
|
// R -> V, G -> Y, B -> U
|
|
// 420 -> 2x2 subsampled, 422 -> 2x1 subsampled, 444 -> non-subsampled
|
|
{
|
|
.drm = DRM_FORMAT_UYVY,
|
|
.vk = VK_FORMAT_B8G8R8G8_422_UNORM,
|
|
.is_ycbcr = true,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_YUYV,
|
|
.vk = VK_FORMAT_G8B8G8R8_422_UNORM,
|
|
.is_ycbcr = true,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_NV12,
|
|
.vk = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
|
|
.is_ycbcr = true,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_NV16,
|
|
.vk = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
|
|
.is_ycbcr = true,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_YUV420,
|
|
.vk = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
|
|
.is_ycbcr = true,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_YUV422,
|
|
.vk = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
|
|
.is_ycbcr = true,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_YUV444,
|
|
.vk = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
|
|
.is_ycbcr = true,
|
|
},
|
|
// 3PACK16 formats split the memory in three 16-bit words, so they have an
|
|
// inverted channel order compared to DRM formats.
|
|
#if WLR_LITTLE_ENDIAN
|
|
{
|
|
.drm = DRM_FORMAT_P010,
|
|
.vk = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
|
|
.is_ycbcr = true,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_P210,
|
|
.vk = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
|
|
.is_ycbcr = true,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_P012,
|
|
.vk = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
|
|
.is_ycbcr = true,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_P016,
|
|
.vk = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
|
|
.is_ycbcr = true,
|
|
},
|
|
{
|
|
.drm = DRM_FORMAT_Q410,
|
|
.vk = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
|
|
.is_ycbcr = true,
|
|
},
|
|
#endif
|
|
// TODO: add DRM_FORMAT_NV24/VK_FORMAT_G8_B8R8_2PLANE_444_UNORM (requires
|
|
// Vulkan 1.3 or VK_EXT_ycbcr_2plane_444_formats)
|
|
};
|
|
|
|
const struct wlr_vk_format *vulkan_get_format_list(size_t *len) {
|
|
*len = sizeof(formats) / sizeof(formats[0]);
|
|
return formats;
|
|
}
|
|
|
|
const struct wlr_vk_format *vulkan_get_format_from_drm(uint32_t drm_format) {
|
|
for (unsigned i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) {
|
|
if (formats[i].drm == drm_format) {
|
|
return &formats[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const VkImageUsageFlags vulkan_render_usage =
|
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
const VkImageUsageFlags vulkan_shm_tex_usage =
|
|
VK_IMAGE_USAGE_SAMPLED_BIT |
|
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
const VkImageUsageFlags vulkan_dma_tex_usage =
|
|
VK_IMAGE_USAGE_SAMPLED_BIT |
|
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
|
|
static const VkFormatFeatureFlags render_features =
|
|
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
|
|
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
|
|
static const VkFormatFeatureFlags shm_tex_features =
|
|
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
|
|
VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
|
|
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
|
|
// NOTE: we don't strictly require this, we could create a NEAREST
|
|
// sampler for formats that need it, in case this ever makes problems.
|
|
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
|
|
static const VkFormatFeatureFlags dma_tex_features =
|
|
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
|
|
// NOTE: we don't strictly require this, we could create a NEAREST
|
|
// sampler for formats that need it, in case this ever makes problems.
|
|
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
|
|
static const VkFormatFeatureFlags ycbcr_tex_features =
|
|
VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT |
|
|
VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT;
|
|
|
|
// vk_format_variant should be set to 0=VK_FORMAT_UNDEFINED when not used
|
|
static bool query_modifier_usage_support(struct wlr_vk_device *dev, VkFormat vk_format,
|
|
VkFormat vk_format_variant, VkImageUsageFlags usage,
|
|
const VkDrmFormatModifierPropertiesEXT *m,
|
|
struct wlr_vk_format_modifier_props *out, const char **errmsg) {
|
|
VkResult res;
|
|
*errmsg = NULL;
|
|
|
|
VkFormat view_formats[2] = {
|
|
vk_format,
|
|
vk_format_variant,
|
|
};
|
|
VkImageFormatListCreateInfoKHR listi = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
|
|
.pViewFormats = view_formats,
|
|
.viewFormatCount = vk_format_variant ? 2 : 1,
|
|
};
|
|
VkPhysicalDeviceImageDrmFormatModifierInfoEXT modi = {
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
|
|
.drmFormatModifier = m->drmFormatModifier,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
.pNext = &listi,
|
|
};
|
|
VkPhysicalDeviceExternalImageFormatInfo efmti = {
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
|
|
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
|
|
.pNext = &modi,
|
|
};
|
|
VkPhysicalDeviceImageFormatInfo2 fmti = {
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
|
|
.type = VK_IMAGE_TYPE_2D,
|
|
.format = vk_format,
|
|
.usage = usage,
|
|
.flags = vk_format_variant ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0,
|
|
.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
|
|
.pNext = &efmti,
|
|
};
|
|
|
|
VkExternalImageFormatProperties efmtp = {
|
|
.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
|
|
};
|
|
VkImageFormatProperties2 ifmtp = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
|
|
.pNext = &efmtp,
|
|
};
|
|
const VkExternalMemoryProperties *emp = &efmtp.externalMemoryProperties;
|
|
|
|
res = vkGetPhysicalDeviceImageFormatProperties2(dev->phdev, &fmti, &ifmtp);
|
|
if (res != VK_SUCCESS) {
|
|
if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
|
|
*errmsg = "unsupported format";
|
|
} else {
|
|
wlr_vk_error("vkGetPhysicalDeviceImageFormatProperties2", res);
|
|
*errmsg = "failed to get format properties";
|
|
}
|
|
return false;
|
|
} else if (!(emp->externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT)) {
|
|
*errmsg = "import not supported";
|
|
return false;
|
|
}
|
|
|
|
VkExtent3D me = ifmtp.imageFormatProperties.maxExtent;
|
|
*out = (struct wlr_vk_format_modifier_props){
|
|
.props = *m,
|
|
.max_extent.width = me.width,
|
|
.max_extent.height = me.height,
|
|
};
|
|
return true;
|
|
}
|
|
|
|
static bool query_shm_support(struct wlr_vk_device *dev, VkFormat vk_format,
|
|
VkFormat vk_format_variant, VkImageFormatProperties *out,
|
|
const char **errmsg) {
|
|
VkResult res;
|
|
*errmsg = NULL;
|
|
|
|
VkFormat view_formats[2] = {
|
|
vk_format,
|
|
vk_format_variant,
|
|
};
|
|
VkImageFormatListCreateInfoKHR listi = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
|
|
.pViewFormats = view_formats,
|
|
.viewFormatCount = vk_format_variant ? 2 : 1,
|
|
.pNext = NULL,
|
|
};
|
|
VkPhysicalDeviceImageFormatInfo2 fmti = {
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
|
|
.type = VK_IMAGE_TYPE_2D,
|
|
.format = vk_format,
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
.usage = vulkan_shm_tex_usage,
|
|
.flags = vk_format_variant ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0,
|
|
.pNext = &listi,
|
|
};
|
|
VkImageFormatProperties2 ifmtp = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
|
|
};
|
|
|
|
res = vkGetPhysicalDeviceImageFormatProperties2(dev->phdev, &fmti, &ifmtp);
|
|
if (res != VK_SUCCESS) {
|
|
if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
|
|
*errmsg = "unsupported format";
|
|
} else {
|
|
wlr_vk_error("vkGetPhysicalDeviceImageFormatProperties2", res);
|
|
*errmsg = "failed to get format properties";
|
|
}
|
|
return false;
|
|
}
|
|
|
|
*out = ifmtp.imageFormatProperties;
|
|
return true;
|
|
}
|
|
|
|
static bool query_modifier_support(struct wlr_vk_device *dev,
|
|
struct wlr_vk_format_props *props, size_t modifier_count) {
|
|
VkDrmFormatModifierPropertiesListEXT modp = {
|
|
.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
|
|
.drmFormatModifierCount = modifier_count,
|
|
};
|
|
VkFormatProperties2 fmtp = {
|
|
.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
|
|
.pNext = &modp,
|
|
};
|
|
|
|
modp.pDrmFormatModifierProperties =
|
|
calloc(modifier_count, sizeof(*modp.pDrmFormatModifierProperties));
|
|
if (!modp.pDrmFormatModifierProperties) {
|
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
|
return false;
|
|
}
|
|
|
|
vkGetPhysicalDeviceFormatProperties2(dev->phdev, props->format.vk, &fmtp);
|
|
|
|
props->dmabuf.render_mods =
|
|
calloc(modp.drmFormatModifierCount, sizeof(*props->dmabuf.render_mods));
|
|
props->dmabuf.texture_mods =
|
|
calloc(modp.drmFormatModifierCount, sizeof(*props->dmabuf.texture_mods));
|
|
if (!props->dmabuf.render_mods || !props->dmabuf.texture_mods) {
|
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
|
free(modp.pDrmFormatModifierProperties);
|
|
free(props->dmabuf.render_mods);
|
|
free(props->dmabuf.texture_mods);
|
|
props->dmabuf.render_mods = NULL;
|
|
props->dmabuf.texture_mods = NULL;
|
|
return false;
|
|
}
|
|
|
|
bool found = false;
|
|
for (uint32_t i = 0; i < modp.drmFormatModifierCount; ++i) {
|
|
VkDrmFormatModifierPropertiesEXT m = modp.pDrmFormatModifierProperties[i];
|
|
char render_status[256], texture_status[256];
|
|
|
|
// check that specific modifier for render usage
|
|
const char *errmsg = "unknown error";
|
|
if ((m.drmFormatModifierTilingFeatures & render_features) == render_features &&
|
|
!props->format.is_ycbcr) {
|
|
struct wlr_vk_format_modifier_props p = {0};
|
|
bool supported = false;
|
|
if (query_modifier_usage_support(dev, props->format.vk,
|
|
props->format.vk_srgb, vulkan_render_usage, &m, &p, &errmsg)) {
|
|
supported = true;
|
|
p.has_mutable_srgb = props->format.vk_srgb != 0;
|
|
}
|
|
if (!supported && props->format.vk_srgb) {
|
|
supported = query_modifier_usage_support(dev, props->format.vk,
|
|
0, vulkan_render_usage, &m, &p, &errmsg);
|
|
}
|
|
|
|
if (supported) {
|
|
props->dmabuf.render_mods[props->dmabuf.render_mod_count++] = p;
|
|
wlr_drm_format_set_add(&dev->dmabuf_render_formats,
|
|
props->format.drm, m.drmFormatModifier);
|
|
found = true;
|
|
}
|
|
} else {
|
|
errmsg = "missing required features";
|
|
}
|
|
if (errmsg != NULL) {
|
|
snprintf(render_status, sizeof(render_status), "✗ render (%s)", errmsg);
|
|
} else {
|
|
snprintf(render_status, sizeof(render_status), "✓ render");
|
|
}
|
|
|
|
// check that specific modifier for texture usage
|
|
errmsg = "unknown error";
|
|
VkFormatFeatureFlags features = dma_tex_features;
|
|
if (props->format.is_ycbcr) {
|
|
features |= ycbcr_tex_features;
|
|
}
|
|
if ((m.drmFormatModifierTilingFeatures & features) == features) {
|
|
struct wlr_vk_format_modifier_props p = {0};
|
|
bool supported = false;
|
|
if (query_modifier_usage_support(dev, props->format.vk,
|
|
props->format.vk_srgb, vulkan_dma_tex_usage, &m, &p, &errmsg)) {
|
|
supported = true;
|
|
p.has_mutable_srgb = props->format.vk_srgb != 0;
|
|
}
|
|
if (!supported && props->format.vk_srgb) {
|
|
supported = query_modifier_usage_support(dev, props->format.vk,
|
|
0, vulkan_dma_tex_usage, &m, &p, &errmsg);
|
|
}
|
|
|
|
if (supported) {
|
|
props->dmabuf.texture_mods[props->dmabuf.texture_mod_count++] = p;
|
|
wlr_drm_format_set_add(&dev->dmabuf_texture_formats,
|
|
props->format.drm, m.drmFormatModifier);
|
|
found = true;
|
|
}
|
|
} else {
|
|
errmsg = "missing required features";
|
|
}
|
|
if (errmsg != NULL) {
|
|
snprintf(texture_status, sizeof(texture_status), "✗ texture (%s)", errmsg);
|
|
} else {
|
|
snprintf(texture_status, sizeof(texture_status), "✓ texture");
|
|
}
|
|
|
|
char *modifier_name = drmGetFormatModifierName(m.drmFormatModifier);
|
|
wlr_log(WLR_DEBUG, " DMA-BUF modifier %s "
|
|
"(0x%016"PRIX64", %"PRIu32" planes): %s %s",
|
|
modifier_name ? modifier_name : "<unknown>", m.drmFormatModifier,
|
|
m.drmFormatModifierPlaneCount, texture_status, render_status);
|
|
free(modifier_name);
|
|
}
|
|
|
|
free(modp.pDrmFormatModifierProperties);
|
|
return found;
|
|
}
|
|
|
|
void vulkan_format_props_query(struct wlr_vk_device *dev,
|
|
const struct wlr_vk_format *format) {
|
|
if (format->is_ycbcr && !dev->sampler_ycbcr_conversion) {
|
|
return;
|
|
}
|
|
|
|
char *format_name = drmGetFormatName(format->drm);
|
|
wlr_log(WLR_DEBUG, " %s (0x%08"PRIX32")",
|
|
format_name ? format_name : "<unknown>", format->drm);
|
|
free(format_name);
|
|
|
|
VkDrmFormatModifierPropertiesListEXT modp = {
|
|
.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
|
|
};
|
|
VkFormatProperties2 fmtp = {
|
|
.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
|
|
.pNext = &modp,
|
|
};
|
|
|
|
vkGetPhysicalDeviceFormatProperties2(dev->phdev, format->vk, &fmtp);
|
|
|
|
bool add_fmt_props = false;
|
|
struct wlr_vk_format_props props = {0};
|
|
props.format = *format;
|
|
|
|
const struct wlr_pixel_format_info *format_info = drm_get_pixel_format_info(format->drm);
|
|
|
|
// shm texture properties
|
|
char shm_texture_status[256];
|
|
const char *errmsg = "unknown error";
|
|
if ((fmtp.formatProperties.optimalTilingFeatures & shm_tex_features) == shm_tex_features &&
|
|
!format->is_ycbcr && format_info != NULL) {
|
|
VkImageFormatProperties ifmtp;
|
|
bool supported = false, has_mutable_srgb = false;
|
|
if (query_shm_support(dev, format->vk, format->vk_srgb, &ifmtp, &errmsg)) {
|
|
supported = true;
|
|
has_mutable_srgb = format->vk_srgb != 0;
|
|
}
|
|
if (!supported && format->vk_srgb) {
|
|
supported = query_shm_support(dev, format->vk, 0, &ifmtp, &errmsg);
|
|
}
|
|
|
|
if (supported) {
|
|
props.shm.max_extent.width = ifmtp.maxExtent.width;
|
|
props.shm.max_extent.height = ifmtp.maxExtent.height;
|
|
props.shm.features = fmtp.formatProperties.optimalTilingFeatures;
|
|
props.shm.has_mutable_srgb = has_mutable_srgb;
|
|
|
|
dev->shm_formats[dev->shm_format_count] = format->drm;
|
|
++dev->shm_format_count;
|
|
|
|
add_fmt_props = true;
|
|
}
|
|
} else {
|
|
errmsg = "missing required features";
|
|
}
|
|
|
|
if (errmsg != NULL) {
|
|
snprintf(shm_texture_status, sizeof(shm_texture_status), "✗ texture (%s)", errmsg);
|
|
} else {
|
|
snprintf(shm_texture_status, sizeof(shm_texture_status), "✓ texture");
|
|
}
|
|
wlr_log(WLR_DEBUG, " Shared memory: %s", shm_texture_status);
|
|
|
|
if (modp.drmFormatModifierCount > 0) {
|
|
add_fmt_props |= query_modifier_support(dev, &props,
|
|
modp.drmFormatModifierCount);
|
|
}
|
|
|
|
if (add_fmt_props) {
|
|
dev->format_props[dev->format_prop_count] = props;
|
|
++dev->format_prop_count;
|
|
} else {
|
|
vulkan_format_props_finish(&props);
|
|
}
|
|
}
|
|
|
|
void vulkan_format_props_finish(struct wlr_vk_format_props *props) {
|
|
free(props->dmabuf.texture_mods);
|
|
free(props->dmabuf.render_mods);
|
|
}
|
|
|
|
const struct wlr_vk_format_modifier_props *vulkan_format_props_find_modifier(
|
|
const struct wlr_vk_format_props *props, uint64_t mod, bool render) {
|
|
uint32_t len;
|
|
const struct wlr_vk_format_modifier_props *mods;
|
|
if (render) {
|
|
len = props->dmabuf.render_mod_count;
|
|
mods = props->dmabuf.render_mods;
|
|
} else {
|
|
len = props->dmabuf.texture_mod_count;
|
|
mods = props->dmabuf.texture_mods;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
|
if (mods[i].props.drmFormatModifier == mod) {
|
|
return &mods[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|