render/egl: Apply color representation to dmabuf import

When importing a dmabuf to a new EGLImage, add the option to apply
color-representation metadata to specify the color encoding and range.
To get this information from the wlr_surface to the new EGLImage, I
store it in wlr_dmabuf_v1_buffer.  This seems reasonable because we can
currently only apply color representation to dmabufs anyway.

Note that this currently won't update if color-representation is changed
on a surface which has already been rendered (so already has an
EGLImage).  It only works when color-representation is set before the
first render.  To fix this I think we'll need some mechanism to
re-import the dmabuf if color-repr is changed.
This commit is contained in:
David Turner 2025-04-29 14:56:47 +01:00
parent 8638735489
commit eeccea7a20
5 changed files with 67 additions and 4 deletions

View file

@ -3,6 +3,8 @@
#include <wlr/render/egl.h>
struct wlr_color_representation_v1_state;
struct wlr_egl {
EGLDisplay display;
EGLContext context;
@ -74,7 +76,8 @@ void wlr_egl_destroy(struct wlr_egl *egl);
* of the dmabuf with wlr_egl_check_import_dmabuf once first.
*/
EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl,
struct wlr_dmabuf_attributes *attributes, bool *external_only);
struct wlr_dmabuf_attributes *attributes, bool *external_only,
const struct wlr_color_representation_v1_state *color_repr);
/**
* Get DMA-BUF formats suitable for sampling usage.

View file

@ -13,6 +13,7 @@
#include <sys/stat.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/render/color.h>
#include <wlr/render/dmabuf.h>
#include <wlr/render/drm_format_set.h>
@ -23,6 +24,7 @@ struct wlr_dmabuf_v1_buffer {
struct wl_resource *resource; // can be NULL if the client destroyed it
struct wlr_dmabuf_attributes attributes;
struct wlr_color_representation_v1_state color_repr;
struct {
struct wl_listener release;

View file

@ -6,6 +6,7 @@
#include <unistd.h>
#include <gbm.h>
#include <wlr/render/egl.h>
#include <wlr/types/wlr_color_representation_v1.h>
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include <xf86drm.h>
@ -733,7 +734,8 @@ bool wlr_egl_restore_context(struct wlr_egl_context *context) {
}
EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl,
struct wlr_dmabuf_attributes *attributes, bool *external_only) {
struct wlr_dmabuf_attributes *attributes, bool *external_only,
const struct wlr_color_representation_v1_state *color_repr) {
if (!egl->exts.KHR_image_base || !egl->exts.EXT_image_dma_buf_import) {
wlr_log(WLR_ERROR, "dmabuf import extension not present");
return NULL;
@ -747,7 +749,7 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl,
}
unsigned int atti = 0;
EGLint attribs[50];
EGLint attribs[54];
attribs[atti++] = EGL_WIDTH;
attribs[atti++] = attributes->width;
attribs[atti++] = EGL_HEIGHT;
@ -805,6 +807,39 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl,
}
}
// Add color representation metadata, if provided
if (color_repr != NULL) {
switch (color_repr->coefficients) {
case WLR_COLOR_ENCODING_BT601:
attribs[atti++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
attribs[atti++] = EGL_ITU_REC601_EXT;
break;
case WLR_COLOR_ENCODING_BT709:
attribs[atti++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
attribs[atti++] = EGL_ITU_REC709_EXT;
break;
case WLR_COLOR_ENCODING_BT2020:
attribs[atti++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
attribs[atti++] = EGL_ITU_REC2020_EXT;
break;
default:
break;
}
switch (color_repr->range) {
case WLR_COLOR_RANGE_FULL:
attribs[atti++] = EGL_SAMPLE_RANGE_HINT_EXT;
attribs[atti++] = EGL_YUV_FULL_RANGE_EXT;
break;
case WLR_COLOR_RANGE_LIMITED:
attribs[atti++] = EGL_SAMPLE_RANGE_HINT_EXT;
attribs[atti++] = EGL_YUV_NARROW_RANGE_EXT;
break;
default:
break;
}
}
// Our clients don't expect our usage to trash the buffer contents
attribs[atti++] = EGL_IMAGE_PRESERVED_KHR;
attribs[atti++] = EGL_TRUE;

View file

@ -12,6 +12,8 @@
#include <wlr/render/egl.h>
#include <wlr/render/interface.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_color_representation_v1.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/util/box.h>
#include <wlr/util/log.h>
#include <xf86drm.h>
@ -143,8 +145,16 @@ struct wlr_gles2_buffer *gles2_buffer_get_or_create(struct wlr_gles2_renderer *r
goto error_buffer;
}
// Try to fetch color representation if present
const struct wlr_color_representation_v1_state *color_repr = NULL;
struct wlr_dmabuf_v1_buffer *dmabuf_v1_buffer =
wlr_dmabuf_v1_buffer_try_from_buffer(wlr_buffer);
if (dmabuf_v1_buffer != NULL) {
color_repr = &dmabuf_v1_buffer->color_repr;
}
buffer->image = wlr_egl_create_image_from_dmabuf(renderer->egl,
&dmabuf, &buffer->external_only);
&dmabuf, &buffer->external_only, color_repr);
if (buffer->image == EGL_NO_IMAGE_KHR) {
goto error_buffer;
}

View file

@ -4,7 +4,9 @@
#include <wayland-server-core.h>
#include <wlr/render/interface.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_color_representation_v1.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_output.h>
#include <wlr/util/log.h>
@ -199,6 +201,17 @@ static void surface_finalize_pending(struct wlr_surface *surface) {
}
if (pending->buffer != NULL) {
// If buffer is a dmabuf, copy color representation from surface
struct wlr_dmabuf_v1_buffer *dmabuf_buffer =
wlr_dmabuf_v1_buffer_try_from_buffer(pending->buffer);
if (dmabuf_buffer != NULL) {
const struct wlr_color_representation_v1_state *surface_color_repr =
wlr_color_representation_v1_get_surface_state(surface);
if (surface_color_repr != NULL) {
dmabuf_buffer->color_repr = *surface_color_repr;
}
}
pending->buffer_width = pending->buffer->width;
pending->buffer_height = pending->buffer->height;
} else {