From 6e8bac217ffc6b9422176bcb24128ba4e5c48825 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Thu, 21 May 2026 21:47:28 -0700 Subject: [PATCH] window-actor: Add format-aware paint_to_content variant meta_window_actor_paint_to_content() always allocates its destination texture via cogl_texture_2d_new_with_size() (RGBA_8888_PRE internal format) and paints with the actor's own color state, so callers cannot ask for an HDR snapshot of a window even on PQ outputs. The shell's ScreenshotWindow D-Bus method runs into exactly this and emits an 8-bit sRGB PNG when capturing a single window on an HDR display. Add meta_window_actor_paint_to_content_full(), accepting an explicit CoglPixelFormat and ClutterColorState. Refactor the internal create_framebuffer_from_window_actor() helper to thread those through: * format == COGL_PIXEL_FORMAT_ANY keeps the existing cogl_texture_2d_new_with_size() behaviour; any other format goes through cogl_texture_2d_new_with_format() so callers can request COGL_PIXEL_FORMAT_RGBA_FP_16161616. * color_state == NULL keeps inheriting the actor's color state (existing behaviour); callers asking for HDR pass a BT.2020 / PQ ClutterColorState so the framebuffer paint is encoded for HDR. The existing meta_window_actor_get_image() and meta_window_actor_paint_to_content() entry points are unchanged at the call site: they now pass COGL_PIXEL_FORMAT_ANY and NULL through to the shared helper. v2: Amend formatting, rename function per suggestion. Assisted-By: Claude Opus 4.7 Part-of: --- src/compositor/meta-window-actor.c | 72 +++++++++++++++++++++++++----- src/meta/meta-window-actor.h | 7 +++ 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index f09659b8ea1..fc4bda6e31a 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -1627,9 +1627,11 @@ meta_window_actor_notify_damaged (MetaWindowActor *window_actor) } static CoglFramebuffer * -create_framebuffer_from_window_actor (MetaWindowActor *self, - MtkRectangle *clip, - GError **error) +create_framebuffer_from_window_actor (MetaWindowActor *self, + MtkRectangle *clip, + CoglPixelFormat format, + ClutterColorState *color_state, + GError **error) { MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); ClutterActor *actor = CLUTTER_ACTOR (self); @@ -1645,12 +1647,24 @@ create_framebuffer_from_window_actor (MetaWindowActor *self, CoglColor clear_color; ClutterPaintContext *paint_context; float resource_scale; + int tex_width, tex_height; resource_scale = clutter_actor_get_resource_scale (actor); - texture = cogl_texture_2d_new_with_size (cogl_context, - (int) (clip->width * resource_scale), - (int) (clip->height * resource_scale)); + tex_width = (int) (clip->width * resource_scale); + tex_height = (int) (clip->height * resource_scale); + + if (format != COGL_PIXEL_FORMAT_ANY) + { + texture = cogl_texture_2d_new_with_format (cogl_context, + tex_width, tex_height, + format); + } + else + { + texture = cogl_texture_2d_new_with_size (cogl_context, + tex_width, tex_height); + } if (!texture) return NULL; @@ -1673,10 +1687,13 @@ create_framebuffer_from_window_actor (MetaWindowActor *self, 0, 1.0); cogl_framebuffer_translate (framebuffer, -clip->x, -clip->y, 0); + if (!color_state) + color_state = clutter_actor_get_color_state (actor); + paint_context = clutter_paint_context_new_for_framebuffer (framebuffer, NULL, CLUTTER_PAINT_FLAG_NONE, - clutter_actor_get_color_state (actor)); + color_state); clutter_actor_paint (actor, paint_context); clutter_paint_context_destroy (paint_context); @@ -1775,6 +1792,8 @@ meta_window_actor_get_image (MetaWindowActor *self, framebuffer = create_framebuffer_from_window_actor (self, &framebuffer_clip, + COGL_PIXEL_FORMAT_ANY, + NULL, NULL); if (!framebuffer) goto out; @@ -1802,20 +1821,27 @@ out: } /** - * meta_window_actor_paint_to_content: + * meta_window_actor_paint_to_content_full: * @self: A #MetaWindowActor * @clip: (nullable): A clipping rectangle, in actor coordinates, to help * prevent extra processing. * In the case that the clipping rectangle is partially or fully * outside the bounds of the actor, the rectangle will be clipped. + * @format: pixel format for the offscreen texture, or %COGL_PIXEL_FORMAT_ANY + * to keep the default (8-bit RGBA). + * @color_state: (nullable): destination color state for the paint, or %NULL + * to inherit the actor's color state. Pass a BT.2020 / PQ #ClutterColorState + * together with %COGL_PIXEL_FORMAT_RGBA_FP_16161616 to retain HDR data. * @error: A #GError to catch exceptional errors or %NULL. * * Returns: (nullable) (transfer full): a new #ClutterContent */ ClutterContent * -meta_window_actor_paint_to_content (MetaWindowActor *self, - MtkRectangle *clip, - GError **error) +meta_window_actor_paint_to_content_full (MetaWindowActor *self, + MtkRectangle *clip, + CoglPixelFormat format, + ClutterColorState *color_state, + GError **error) { MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); ClutterActor *actor = CLUTTER_ACTOR (self); @@ -1855,6 +1881,8 @@ meta_window_actor_paint_to_content (MetaWindowActor *self, framebuffer = create_framebuffer_from_window_actor (self, &framebuffer_clip, + format, + color_state, error); if (!framebuffer) goto out; @@ -1869,6 +1897,28 @@ out: return content; } +/** + * meta_window_actor_paint_to_content: + * @self: A #MetaWindowActor + * @clip: (nullable): A clipping rectangle, in actor coordinates, to help + * prevent extra processing. + * In the case that the clipping rectangle is partially or fully + * outside the bounds of the actor, the rectangle will be clipped. + * @error: A #GError to catch exceptional errors or %NULL. + * + * Returns: (nullable) (transfer full): a new #ClutterContent + */ +ClutterContent * +meta_window_actor_paint_to_content (MetaWindowActor *self, + MtkRectangle *clip, + GError **error) +{ + return meta_window_actor_paint_to_content_full (self, clip, + COGL_PIXEL_FORMAT_ANY, + NULL, + error); +} + void meta_window_actor_set_tied_to_drag (MetaWindowActor *window_actor, gboolean tied_to_drag) diff --git a/src/meta/meta-window-actor.h b/src/meta/meta-window-actor.h index 0138d4592b7..55a1fc52ad9 100644 --- a/src/meta/meta-window-actor.h +++ b/src/meta/meta-window-actor.h @@ -55,6 +55,13 @@ ClutterContent * meta_window_actor_paint_to_content (MetaWindowActor *self, MtkRectangle *clip, GError **error); +META_EXPORT +ClutterContent * meta_window_actor_paint_to_content_full (MetaWindowActor *self, + MtkRectangle *clip, + CoglPixelFormat format, + ClutterColorState *color_state, + GError **error); + META_EXPORT void meta_window_actor_freeze (MetaWindowActor *self); -- GitLab