
The initial target color state is the color state of the stage view being painted to. If we're painting to an arbitrary framebuffer, it's currently hard coded to sRGB/electrical. The content color state is not set on construction, but when starting to paint, it's set to the color state of the stage itself. Whenever an actor is painted, it'll set the color state to the color state of itself. The intention is that offscreen rendering pushes a target color state that causes painting to it to not necessarily be in the stage view color state. Pass color state with offscreen framebuffer, as this avoids hard coding sRGB in the lower level bits of paint contexts. It's still practically hard coded, only that it's derived from somewhere else (e.g. the stage or window actor). Nothing is actually using this yet, but will eventually. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3433>
318 lines
9.4 KiB
C
318 lines
9.4 KiB
C
/*
|
|
* Copyright (C) 2019 Red Hat Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "clutter/clutter-paint-context-private.h"
|
|
|
|
#include "clutter/clutter-color-state.h"
|
|
#include "clutter/clutter-frame.h"
|
|
#include "clutter/clutter-stage-view-private.h"
|
|
|
|
struct _ClutterPaintContext
|
|
{
|
|
grefcount ref_count;
|
|
|
|
ClutterPaintFlag paint_flags;
|
|
|
|
GList *framebuffers;
|
|
|
|
ClutterStageView *view;
|
|
ClutterFrame *frame;
|
|
|
|
MtkRegion *redraw_clip;
|
|
GArray *clip_frusta;
|
|
|
|
GList *target_color_states;
|
|
GList *color_states;
|
|
|
|
ClutterColorState *framebuffer_color_state;
|
|
};
|
|
|
|
G_DEFINE_BOXED_TYPE (ClutterPaintContext, clutter_paint_context,
|
|
clutter_paint_context_ref,
|
|
clutter_paint_context_unref)
|
|
|
|
ClutterPaintContext *
|
|
clutter_paint_context_new_for_view (ClutterStageView *view,
|
|
const MtkRegion *redraw_clip,
|
|
GArray *clip_frusta,
|
|
ClutterPaintFlag paint_flags)
|
|
{
|
|
ClutterPaintContext *paint_context;
|
|
ClutterColorState *target_color_state;
|
|
CoglFramebuffer *framebuffer;
|
|
|
|
paint_context = g_new0 (ClutterPaintContext, 1);
|
|
g_ref_count_init (&paint_context->ref_count);
|
|
paint_context->view = view;
|
|
paint_context->redraw_clip = mtk_region_copy (redraw_clip);
|
|
paint_context->clip_frusta = g_array_ref (clip_frusta);
|
|
paint_context->paint_flags = paint_flags;
|
|
g_set_object (&paint_context->framebuffer_color_state,
|
|
clutter_stage_view_get_color_state (view));
|
|
|
|
target_color_state = paint_context->framebuffer_color_state;
|
|
clutter_paint_context_push_target_color_state (paint_context,
|
|
target_color_state);
|
|
|
|
framebuffer = clutter_stage_view_get_framebuffer (view);
|
|
clutter_paint_context_push_framebuffer (paint_context, framebuffer);
|
|
|
|
return paint_context;
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_context_new_for_framebuffer: (skip)
|
|
*/
|
|
ClutterPaintContext *
|
|
clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer,
|
|
const MtkRegion *redraw_clip,
|
|
ClutterPaintFlag paint_flags,
|
|
ClutterColorState *color_state)
|
|
{
|
|
ClutterPaintContext *paint_context;
|
|
ClutterColorState *target_color_state;
|
|
|
|
paint_context = g_new0 (ClutterPaintContext, 1);
|
|
g_ref_count_init (&paint_context->ref_count);
|
|
paint_context->paint_flags = paint_flags;
|
|
g_set_object (&paint_context->framebuffer_color_state, color_state);
|
|
|
|
target_color_state = paint_context->framebuffer_color_state;
|
|
clutter_paint_context_push_target_color_state (paint_context,
|
|
target_color_state);
|
|
|
|
if (redraw_clip)
|
|
paint_context->redraw_clip = mtk_region_copy (redraw_clip);
|
|
|
|
clutter_paint_context_push_framebuffer (paint_context, framebuffer);
|
|
|
|
return paint_context;
|
|
}
|
|
|
|
ClutterPaintContext *
|
|
clutter_paint_context_ref (ClutterPaintContext *paint_context)
|
|
{
|
|
g_ref_count_inc (&paint_context->ref_count);
|
|
return paint_context;
|
|
}
|
|
|
|
static void
|
|
clutter_paint_context_dispose (ClutterPaintContext *paint_context)
|
|
{
|
|
if (paint_context->framebuffer_color_state)
|
|
{
|
|
clutter_paint_context_pop_target_color_state (paint_context);
|
|
g_clear_object (&paint_context->framebuffer_color_state);
|
|
}
|
|
|
|
g_warn_if_fail (!paint_context->color_states);
|
|
g_warn_if_fail (!paint_context->target_color_states);
|
|
g_list_free_full (paint_context->framebuffers, g_object_unref);
|
|
paint_context->framebuffers = NULL;
|
|
g_clear_pointer (&paint_context->redraw_clip, mtk_region_unref);
|
|
g_clear_pointer (&paint_context->clip_frusta, g_array_unref);
|
|
g_clear_pointer (&paint_context->frame, clutter_frame_unref);
|
|
}
|
|
|
|
void
|
|
clutter_paint_context_unref (ClutterPaintContext *paint_context)
|
|
{
|
|
if (g_ref_count_dec (&paint_context->ref_count))
|
|
{
|
|
clutter_paint_context_dispose (paint_context);
|
|
g_free (paint_context);
|
|
}
|
|
}
|
|
|
|
void
|
|
clutter_paint_context_destroy (ClutterPaintContext *paint_context)
|
|
{
|
|
clutter_paint_context_dispose (paint_context);
|
|
clutter_paint_context_unref (paint_context);
|
|
}
|
|
|
|
void
|
|
clutter_paint_context_push_framebuffer (ClutterPaintContext *paint_context,
|
|
CoglFramebuffer *framebuffer)
|
|
{
|
|
paint_context->framebuffers = g_list_prepend (paint_context->framebuffers,
|
|
g_object_ref (framebuffer));
|
|
}
|
|
|
|
void
|
|
clutter_paint_context_pop_framebuffer (ClutterPaintContext *paint_context)
|
|
{
|
|
g_return_if_fail (paint_context->framebuffers);
|
|
|
|
g_object_unref (paint_context->framebuffers->data);
|
|
paint_context->framebuffers =
|
|
g_list_delete_link (paint_context->framebuffers,
|
|
paint_context->framebuffers);
|
|
}
|
|
|
|
const MtkRegion *
|
|
clutter_paint_context_get_redraw_clip (ClutterPaintContext *paint_context)
|
|
{
|
|
return paint_context->redraw_clip;
|
|
}
|
|
|
|
const GArray *
|
|
clutter_paint_context_get_clip_frusta (ClutterPaintContext *paint_context)
|
|
{
|
|
return paint_context->clip_frusta;
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_context_get_framebuffer:
|
|
* @paint_context: The #ClutterPaintContext
|
|
*
|
|
* Returns: (transfer none): The #CoglFramebuffer used for drawing
|
|
*/
|
|
CoglFramebuffer *
|
|
clutter_paint_context_get_framebuffer (ClutterPaintContext *paint_context)
|
|
{
|
|
g_return_val_if_fail (paint_context->framebuffers, NULL);
|
|
|
|
return paint_context->framebuffers->data;
|
|
}
|
|
|
|
CoglFramebuffer *
|
|
clutter_paint_context_get_base_framebuffer (ClutterPaintContext *paint_context)
|
|
{
|
|
return g_list_last (paint_context->framebuffers)->data;
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_context_get_stage_view: (skip)
|
|
*/
|
|
ClutterStageView *
|
|
clutter_paint_context_get_stage_view (ClutterPaintContext *paint_context)
|
|
{
|
|
return paint_context->view;
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_context_is_drawing_off_stage: (skip)
|
|
*
|
|
* Return %TRUE if the paint context is currently drawing off stage.
|
|
* This happens if there are any framebuffers pushed, and the base framebuffer
|
|
* comes from the stage view.
|
|
*/
|
|
gboolean
|
|
clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context)
|
|
{
|
|
if (g_list_length (paint_context->framebuffers) > 1)
|
|
return TRUE;
|
|
|
|
return !paint_context->view;
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_context_get_paint_flags: (skip)
|
|
*/
|
|
ClutterPaintFlag
|
|
clutter_paint_context_get_paint_flags (ClutterPaintContext *paint_context)
|
|
{
|
|
return paint_context->paint_flags;
|
|
}
|
|
|
|
void
|
|
clutter_paint_context_assign_frame (ClutterPaintContext *paint_context,
|
|
ClutterFrame *frame)
|
|
{
|
|
g_assert (paint_context != NULL);
|
|
g_assert (paint_context->frame == NULL);
|
|
g_assert (frame != NULL);
|
|
|
|
paint_context->frame = clutter_frame_ref (frame);
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_context_get_frame: (skip)
|
|
* @paint_context: The #ClutterPaintContext
|
|
*
|
|
* Retrieves the #ClutterFrame assigned to @paint_context, if any. A frame is
|
|
* only assigned when the paint context is created as part of a frame scheduled
|
|
* by the frame clock, and won't be assigned e.g. on offscreen paints.
|
|
*
|
|
* Returns: (transfer none)(nullable): The #ClutterFrame associated with the
|
|
* @paint_context, or %NULL
|
|
*/
|
|
ClutterFrame *
|
|
clutter_paint_context_get_frame (ClutterPaintContext *paint_context)
|
|
{
|
|
return paint_context->frame;
|
|
}
|
|
|
|
void
|
|
clutter_paint_context_push_target_color_state (ClutterPaintContext *paint_context,
|
|
ClutterColorState *color_state)
|
|
{
|
|
paint_context->target_color_states =
|
|
g_list_prepend (paint_context->target_color_states, color_state);
|
|
}
|
|
|
|
void
|
|
clutter_paint_context_pop_target_color_state (ClutterPaintContext *paint_context)
|
|
{
|
|
g_return_if_fail (paint_context->target_color_states);
|
|
|
|
paint_context->target_color_states =
|
|
g_list_delete_link (paint_context->target_color_states,
|
|
paint_context->target_color_states);
|
|
}
|
|
|
|
void
|
|
clutter_paint_context_push_color_state (ClutterPaintContext *paint_context,
|
|
ClutterColorState *color_state)
|
|
{
|
|
paint_context->color_states = g_list_prepend (paint_context->color_states,
|
|
color_state);
|
|
}
|
|
|
|
void
|
|
clutter_paint_context_pop_color_state (ClutterPaintContext *paint_context)
|
|
{
|
|
g_return_if_fail (paint_context->color_states);
|
|
|
|
paint_context->color_states =
|
|
g_list_delete_link (paint_context->color_states,
|
|
paint_context->color_states);
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_context_get_target_color_state: (skip)
|
|
*/
|
|
ClutterColorState *
|
|
clutter_paint_context_get_target_color_state (ClutterPaintContext *paint_context)
|
|
{
|
|
return CLUTTER_COLOR_STATE (paint_context->target_color_states->data);
|
|
}
|
|
|
|
/**
|
|
* clutter_paint_context_get_color_state: (skip)
|
|
*/
|
|
ClutterColorState *
|
|
clutter_paint_context_get_color_state (ClutterPaintContext *paint_context)
|
|
{
|
|
g_return_val_if_fail (paint_context->color_states, NULL);
|
|
|
|
return CLUTTER_COLOR_STATE (paint_context->color_states->data);
|
|
}
|