Add crude color management impl for cairo

Use linear compositing with cairo if LINEAR_COMPOSITING=1 is
set in the environment.
This commit is contained in:
Matthias Clasen
2024-06-08 13:14:02 -04:00
parent 2789487bbc
commit b0b7e0637d
2 changed files with 80 additions and 5 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2016 Endless
* Copyright © 2016 Endless
* 2018 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
@@ -25,6 +25,9 @@
#include "gskdebugprivate.h"
#include "gskrendererprivate.h"
#include "gskrendernodeprivate.h"
#include "gdk/gdkcolorstate.h"
#include "gdk/gdkmemorytextureprivate.h"
#include "gdk/gdktextureprivate.h"
typedef struct {
@@ -38,7 +41,10 @@ struct _GskCairoRenderer
GdkCairoContext *cairo_context;
gboolean color_managed;
#ifdef G_ENABLE_DEBUG
ProfileTimers profile_timers;
#endif
};
struct _GskCairoRendererClass
@@ -95,6 +101,7 @@ gsk_cairo_renderer_render_texture (GskRenderer *renderer,
GskRenderNode *root,
const graphene_rect_t *viewport)
{
GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
GdkTexture *texture;
cairo_surface_t *surface;
cairo_t *cr;
@@ -118,7 +125,7 @@ gsk_cairo_renderer_render_texture (GskRenderer *renderer,
{
for (x = 0; x < width; x += MAX_IMAGE_SIZE)
{
texture = gsk_cairo_renderer_render_texture (renderer, root,
texture = gsk_cairo_renderer_render_texture (renderer, root,
&GRAPHENE_RECT_INIT (x, y,
MIN (MAX_IMAGE_SIZE, viewport->size.width - x),
MIN (MAX_IMAGE_SIZE, viewport->size.height - y)));
@@ -136,6 +143,9 @@ gsk_cairo_renderer_render_texture (GskRenderer *renderer,
}
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
if (self->color_managed)
gdk_cairo_surface_set_color_state (surface, gdk_color_state_get_srgb_linear ());
cr = cairo_create (surface);
cairo_translate (cr, - viewport->origin.x, - viewport->origin.y);
@@ -178,7 +188,65 @@ gsk_cairo_renderer_render (GskRenderer *renderer,
cairo_restore (cr);
}
gsk_cairo_renderer_do_render (renderer, cr, root);
if (!self->color_managed ||
gdk_color_state_is_linear (gdk_cairo_get_color_state (cr)))
{
gsk_cairo_renderer_do_render (renderer, cr, root);
}
else
{
GdkSurface *surface = gsk_renderer_get_surface (renderer);
cairo_surface_t *cairo_surface;
cairo_t *cr2;
GdkTexture *color_correct;
const cairo_region_t *frame_region;
cairo_rectangle_int_t extents;
guint i, n;
frame_region = gdk_draw_context_get_frame_region (GDK_DRAW_CONTEXT (self->cairo_context));
cairo_region_get_extents (frame_region, &extents);
/* We can't use cairo_push_group() here, because we'd lose the
* color profile information.
*/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
cairo_surface = gdk_surface_create_similar_surface (surface,
CAIRO_CONTENT_COLOR_ALPHA,
extents.width,
extents.height);
G_GNUC_END_IGNORE_DEPRECATIONS
gdk_cairo_surface_set_color_state (cairo_surface,
gdk_color_state_get_srgb_linear ());
cr2 = cairo_create (cairo_surface);
cairo_translate (cr2, -extents.x, -extents.y);
gdk_cairo_region (cr2, frame_region);
cairo_clip (cr2);
gsk_cairo_renderer_do_render (renderer, cr2, root);
cairo_destroy (cr2);
color_correct = gdk_texture_new_for_surface (cairo_surface);
cairo_surface_destroy (cairo_surface);
n = cairo_region_num_rectangles (frame_region);
for (i = 0; i < n; i++)
{
cairo_rectangle_int_t rect;
GdkTexture *sub;
cairo_region_get_rectangle (frame_region, i, &rect);
rect.x -= extents.x;
rect.y -= extents.y;
sub = gdk_memory_texture_new_subtexture (GDK_MEMORY_TEXTURE (color_correct),
rect.x, rect.y, rect.width, rect.height);
cairo_surface = gdk_texture_download_surface (sub, gdk_cairo_get_color_state (cr));
cairo_set_source_surface (cr, cairo_surface, rect.x + extents.x, rect.y + extents.y);
cairo_paint (cr);
cairo_surface_destroy (cairo_surface);
g_object_unref (sub);
}
g_object_unref (color_correct);
}
cairo_destroy (cr);
@@ -199,9 +267,16 @@ gsk_cairo_renderer_class_init (GskCairoRendererClass *klass)
static void
gsk_cairo_renderer_init (GskCairoRenderer *self)
{
if (g_getenv ("LINEAR_COMPOSITING"))
self->color_managed = atoi (g_getenv ("LINEAR_COMPOSITING")) != 0;
else
self->color_managed = TRUE;
#ifdef G_ENABLE_DEBUG
GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self));
self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE);
#endif
}
/**

View File

@@ -1770,7 +1770,7 @@ gsk_texture_node_draw (GskRenderNode *node,
return;
}
surface = gdk_texture_download_surface (self->texture, gdk_color_state_get_srgb ());
surface = gdk_texture_download_surface (self->texture, gdk_cairo_get_color_state (cr));
pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
@@ -1946,7 +1946,7 @@ gsk_texture_scale_node_draw (GskRenderNode *node,
cairo_surface_set_device_offset (surface2, -clip_rect.origin.x, -clip_rect.origin.y);
cr2 = cairo_create (surface2);
surface = gdk_texture_download_surface (self->texture, gdk_color_state_get_srgb ());
surface = gdk_texture_download_surface (self->texture, gdk_cairo_get_color_state (cr));
pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);