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:
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user