wsi/display: Expose HDR10 colorspace based on EDID

Uses libdisplay-info to parse the edid, grab the metadata and see
if HDR10 is supported by the display.

Reviewed-by: Emma Anholt <emma@anholt.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35461>
This commit is contained in:
Joshua Ashton 2022-11-14 11:49:41 +00:00 committed by Marge Bot
parent 2c870bbe20
commit 13137393f6
2 changed files with 122 additions and 6 deletions

View file

@ -55,7 +55,7 @@ if with_platform_wayland
vulkan_wsi_list += '-DVK_USE_PLATFORM_WAYLAND_KHR' vulkan_wsi_list += '-DVK_USE_PLATFORM_WAYLAND_KHR'
endif endif
if system_has_kms_drm and not with_platform_android if system_has_kms_drm and not with_platform_android
vulkan_wsi_deps += [dep_libdrm] vulkan_wsi_deps += [dep_libdrm, dep_display_info]
vulkan_wsi_list += '-DVK_USE_PLATFORM_DISPLAY_KHR' vulkan_wsi_list += '-DVK_USE_PLATFORM_DISPLAY_KHR'
endif endif
if with_xlib_lease if with_xlib_lease

View file

@ -89,6 +89,12 @@
#include "wsi_common_display.h" #include "wsi_common_display.h"
#include "wsi_common_queue.h" #include "wsi_common_queue.h"
#ifdef HAVE_LIBDISPLAY_INFO
#include "libdisplay-info/info.h"
#include "libdisplay-info/edid.h"
#include "libdisplay-info/cta.h"
#endif
#if 0 #if 0
#define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__) #define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__)
#define wsi_display_debug_code(...) __VA_ARGS__ #define wsi_display_debug_code(...) __VA_ARGS__
@ -149,6 +155,11 @@ enum colorspace_enum {
COLORSPACE_ENUM_MAX, COLORSPACE_ENUM_MAX,
}; };
typedef struct wsi_display_connector_metadata {
VkHdrMetadataEXT hdr_metadata;
bool supports_st2084;
} wsi_display_connector_metadata;
typedef struct wsi_display_connector { typedef struct wsi_display_connector {
struct list_head list; struct list_head list;
struct wsi_display *wsi; struct wsi_display *wsi;
@ -170,6 +181,7 @@ typedef struct wsi_display_connector {
#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
xcb_randr_output_t output; xcb_randr_output_t output;
#endif #endif
struct wsi_display_connector_metadata metadata;
} wsi_display_connector; } wsi_display_connector;
struct wsi_display { struct wsi_display {
@ -198,6 +210,65 @@ struct wsi_display {
uint64_t color_outcome_serial_counter; uint64_t color_outcome_serial_counter;
}; };
static void
wsi_display_parse_edid(struct wsi_display_connector *connector, drmModePropertyBlobRes *blob)
{
#ifdef HAVE_LIBDISPLAY_INFO
struct wsi_display_connector_metadata *metadata = &connector->metadata;
struct di_info *info = di_info_parse_edid(blob->data, blob->length);
if (!info) {
fprintf(stderr, "wsi_display_parse_edid: Failed to parse edid. Reason: %s\n", di_info_get_failure_msg(info));
return;
}
const struct di_edid *edid = di_info_get_edid(info);
const struct di_edid_chromaticity_coords *chroma = di_edid_get_chromaticity_coords(edid);
const struct di_cta_hdr_static_metadata_block *hdr_static_metadata = NULL;
const struct di_cta_colorimetry_block *colorimetry = NULL;
const struct di_edid_cta *cta = NULL;
const struct di_edid_ext * const *exts = di_edid_get_extensions(edid);
for (; *exts != NULL; exts++) {
if ((cta = di_edid_ext_get_cta(*exts)))
break;
}
if (cta) {
const struct di_cta_data_block * const * blocks = di_edid_cta_get_data_blocks(cta);
for (; *blocks != NULL; blocks++) {
if (!hdr_static_metadata && (hdr_static_metadata = di_cta_data_block_get_hdr_static_metadata(*blocks)))
continue;
if (!colorimetry && (colorimetry = di_cta_data_block_get_colorimetry(*blocks)))
continue;
}
}
if (chroma) {
metadata->hdr_metadata.displayPrimaryRed = (VkXYColorEXT){ chroma->red_x, chroma->red_y };
metadata->hdr_metadata.displayPrimaryGreen = (VkXYColorEXT){ chroma->green_x, chroma->green_y };
metadata->hdr_metadata.displayPrimaryBlue = (VkXYColorEXT){ chroma->blue_x, chroma->blue_y };
metadata->hdr_metadata.whitePoint = (VkXYColorEXT){ chroma->white_x, chroma->white_y };
}
if (hdr_static_metadata) {
metadata->hdr_metadata.maxFrameAverageLightLevel = hdr_static_metadata->desired_content_max_frame_avg_luminance;
metadata->hdr_metadata.minLuminance = hdr_static_metadata->desired_content_min_luminance;
metadata->hdr_metadata.maxLuminance = hdr_static_metadata->desired_content_max_luminance;
/* To be filled in by the app based on the scene, default to desired_content_max_luminance. */
metadata->hdr_metadata.maxContentLightLevel = hdr_static_metadata->desired_content_max_luminance;
}
metadata->supports_st2084 =
chroma &&
colorimetry && colorimetry->bt2020_rgb &&
hdr_static_metadata && hdr_static_metadata->eotfs && hdr_static_metadata->eotfs->pq;
di_info_destroy(info);
#endif
}
/** /**
* Creates the mapping from our property enums to the KMS property ID for that * Creates the mapping from our property enums to the KMS property ID for that
* property associated with the object. * property associated with the object.
@ -295,6 +366,14 @@ find_properties(struct wsi_display_connector *connector, int fd, uint32_t type)
#undef COLORSPACE_ENUM #undef COLORSPACE_ENUM
} }
if (!strcmp(prop->name, "EDID")) {
drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd, props->prop_values[p]);
if (blob) {
wsi_display_parse_edid(connector, blob);
drmModeFreePropertyBlob(blob);
}
}
drmModeFreeProperty(prop); drmModeFreeProperty(prop);
} }
@ -1243,6 +1322,20 @@ static const struct wsi_display_surface_format
}, },
.drm_format = DRM_FORMAT_XRGB8888 .drm_format = DRM_FORMAT_XRGB8888
}, },
{
.surface_format = {
.format = VK_FORMAT_A2B10G10R10_UNORM_PACK32,
.colorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT,
},
.drm_format = DRM_FORMAT_XBGR2101010
},
{
.surface_format = {
.format = VK_FORMAT_A2R10G10B10_UNORM_PACK32,
.colorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT,
},
.drm_format = DRM_FORMAT_XRGB2101010
},
}; };
static void static void
@ -1263,6 +1356,21 @@ get_sorted_vk_formats(struct wsi_device *wsi_device, VkSurfaceFormatKHR *sorted_
} }
} }
static bool
surface_format_supported(VkIcdSurfaceBase *icd_surface, VkSurfaceFormatKHR surface_format)
{
VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) icd_surface;
wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode);
if (surface_format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
return true;
if (surface_format.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT)
return mode->connector->metadata.supports_st2084;
return false;
}
static VkResult static VkResult
wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface, wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface,
struct wsi_device *wsi_device, struct wsi_device *wsi_device,
@ -1276,10 +1384,12 @@ wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface,
get_sorted_vk_formats(wsi_device, sorted_formats); get_sorted_vk_formats(wsi_device, sorted_formats);
for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) { for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
if (surface_format_supported(icd_surface, sorted_formats[i])) {
vk_outarray_append_typed(VkSurfaceFormatKHR, &out, f) { vk_outarray_append_typed(VkSurfaceFormatKHR, &out, f) {
*f = sorted_formats[i]; *f = sorted_formats[i];
} }
} }
}
return vk_outarray_status(&out); return vk_outarray_status(&out);
} }
@ -1298,11 +1408,13 @@ wsi_display_surface_get_formats2(VkIcdSurfaceBase *surface,
get_sorted_vk_formats(wsi_device, sorted_formats); get_sorted_vk_formats(wsi_device, sorted_formats);
for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) { for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
if (surface_format_supported(surface, sorted_formats[i])) {
vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, f) { vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, f) {
assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR); assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
f->surfaceFormat = sorted_formats[i]; f->surfaceFormat = sorted_formats[i];
} }
} }
}
return vk_outarray_status(&out); return vk_outarray_status(&out);
} }
@ -2798,6 +2910,10 @@ wsi_display_surface_create_swapchain(
chain->surface = surface; chain->surface = surface;
/* Default HDR metadata when the HDR10/ST2084 colorspace is used
* to the metadata provided by the EDID. */
chain->hdr_metadata = display_mode->connector->metadata.hdr_metadata;
p_atomic_inc(&display_mode->connector->refcount); p_atomic_inc(&display_mode->connector->refcount);
for (uint32_t image = 0; image < chain->base.image_count; image++) { for (uint32_t image = 0; image < chain->base.image_count; image++) {