1
0
Fork 0

clutter/stage-view: Move offscreen creation from renderer to view

This allows us to destroy and create a new offscreen dynamically, when
the rotation or color state changes.

An idle gsource with priority higher than CLUTTER_PRIORITY_REDRAW is
used to ensure the an offscreen exists when required without having to
allocate in the redraw process.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3930>
This commit is contained in:
Sebastian Wick 2024-08-08 00:07:23 +02:00 committed by Marge Bot
parent 6a1749009f
commit a91fd4a72c
3 changed files with 156 additions and 146 deletions

View file

@ -40,7 +40,6 @@ enum
PROP_STAGE,
PROP_LAYOUT,
PROP_FRAMEBUFFER,
PROP_OFFSCREEN,
PROP_USE_SHADOWFB,
PROP_COLOR_STATE,
PROP_OUTPUT_COLOR_STATE,
@ -75,6 +74,7 @@ typedef struct _ClutterStageViewPrivate
ClutterColorState *color_state;
ClutterColorState *output_color_state;
guint ensure_offscreen_idle_id;
CoglOffscreen *offscreen;
CoglPipeline *offscreen_pipeline;
@ -140,6 +140,8 @@ clutter_stage_view_get_framebuffer (ClutterStageView *view)
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
g_warn_if_fail (priv->ensure_offscreen_idle_id == 0);
if (priv->offscreen)
return COGL_FRAMEBUFFER (priv->offscreen);
else if (priv->shadow.framebuffer)
@ -165,11 +167,19 @@ clutter_stage_view_get_onscreen (ClutterStageView *view)
return priv->framebuffer;
}
static CoglPipeline *
clutter_stage_view_create_offscreen_pipeline (CoglOffscreen *offscreen)
static void
ensure_stage_view_offscreen (ClutterStageView *view);
static void
ensure_stage_view_offscreen_pipeline (ClutterStageView *view)
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (offscreen);
CoglPipeline *pipeline;
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (priv->offscreen);
g_autoptr (CoglPipeline) pipeline = NULL;
if (priv->offscreen_pipeline)
return;
pipeline = cogl_pipeline_new (cogl_framebuffer_get_context (framebuffer));
cogl_pipeline_set_static_name (pipeline, "ClutterStageView (offscreen)");
@ -178,56 +188,68 @@ clutter_stage_view_create_offscreen_pipeline (CoglOffscreen *offscreen)
COGL_PIPELINE_FILTER_NEAREST,
COGL_PIPELINE_FILTER_NEAREST);
cogl_pipeline_set_layer_texture (pipeline, 0,
cogl_offscreen_get_texture (offscreen));
cogl_offscreen_get_texture (priv->offscreen));
cogl_pipeline_set_layer_wrap_mode (pipeline, 0,
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
return pipeline;
}
if (priv->transform != MTK_MONITOR_TRANSFORM_NORMAL)
{
graphene_matrix_t matrix;
static void
setup_offscreen_transform (ClutterStageView *view,
CoglPipeline *pipeline)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
graphene_matrix_t matrix;
if (priv->transform == MTK_MONITOR_TRANSFORM_NORMAL)
return;
clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
}
static void
clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
g_assert (priv->offscreen != NULL);
if (priv->offscreen_pipeline)
return;
priv->offscreen_pipeline =
clutter_stage_view_create_offscreen_pipeline (priv->offscreen);
setup_offscreen_transform (view, priv->offscreen_pipeline);
clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
}
clutter_color_state_add_pipeline_transform (priv->color_state,
priv->output_color_state,
priv->offscreen_pipeline);
pipeline);
g_set_object (&priv->offscreen_pipeline, g_steal_pointer (&pipeline));
}
void
clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
static gboolean
on_ensure_offscreen_idle (gpointer data)
{
ClutterStageView *view = CLUTTER_STAGE_VIEW (data);
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
ensure_stage_view_offscreen (view);
ensure_stage_view_offscreen_pipeline (view);
priv->ensure_offscreen_idle_id = 0;
return G_SOURCE_REMOVE;
}
static void
clutter_stage_view_invalidate_offscreen (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
if (priv->frame_clock)
{
clutter_stage_view_add_redraw_clip (view, NULL);
clutter_stage_view_schedule_update (view);
}
if (priv->transform == MTK_MONITOR_TRANSFORM_NORMAL &&
clutter_color_state_equals (priv->color_state, priv->output_color_state))
{
g_clear_object (&priv->offscreen_pipeline);
g_clear_object (&priv->offscreen);
g_clear_handle_id (&priv->ensure_offscreen_idle_id, g_source_remove);
return;
}
g_clear_object (&priv->offscreen_pipeline);
if (priv->ensure_offscreen_idle_id != 0)
return;
priv->ensure_offscreen_idle_id = g_idle_add_full (CLUTTER_PRIORITY_REDRAW - 1,
on_ensure_offscreen_idle,
view, NULL);
}
static void
@ -240,7 +262,7 @@ set_color_state (ClutterStageView *view,
g_set_object (dest_color_state, color_state);
clutter_stage_view_invalidate_offscreen_blit_pipeline (view);
clutter_stage_view_invalidate_offscreen (view);
}
static void
@ -386,6 +408,91 @@ create_offscreen (ClutterStageView *view,
return g_steal_pointer (&framebuffer);
}
static CoglOffscreen *
create_offscreen_with_formats (ClutterStageView *view,
CoglPixelFormat *formats,
size_t n_formats,
int width,
int height,
GError **error)
{
g_autoptr (GError) local_error = NULL;
size_t i;
for (i = 0; i < n_formats; i++)
{
CoglOffscreen *offscreen;
g_clear_error (&local_error);
offscreen = create_offscreen (view, formats[i], width, height, &local_error);
if (offscreen)
return offscreen;
}
g_propagate_error (error, g_steal_pointer (&local_error));
return NULL;
}
static void
ensure_stage_view_offscreen (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
ClutterEncodingRequiredFormat required_format;
CoglPixelFormat formats[10];
size_t n_formats = 0;
int offscreen_width, offscreen_height;
int onscreen_width, onscreen_height;
g_autoptr (CoglOffscreen) offscreen = NULL;
g_autoptr (GError) local_error = NULL;
if (priv->offscreen)
return;
required_format = clutter_color_state_required_format (priv->color_state);
if (required_format <= CLUTTER_ENCODING_REQUIRED_FORMAT_UINT8)
{
formats[n_formats++] =
cogl_framebuffer_get_internal_format (priv->framebuffer);
}
else
{
formats[n_formats++] = COGL_PIXEL_FORMAT_XRGB_FP_16161616;
formats[n_formats++] = COGL_PIXEL_FORMAT_XBGR_FP_16161616;
formats[n_formats++] = COGL_PIXEL_FORMAT_RGBA_FP_16161616_PRE;
formats[n_formats++] = COGL_PIXEL_FORMAT_BGRA_FP_16161616_PRE;
formats[n_formats++] = COGL_PIXEL_FORMAT_ARGB_FP_16161616_PRE;
formats[n_formats++] = COGL_PIXEL_FORMAT_ABGR_FP_16161616_PRE;
}
onscreen_width = cogl_framebuffer_get_width (priv->framebuffer);
onscreen_height = cogl_framebuffer_get_height (priv->framebuffer);
if (mtk_monitor_transform_is_rotated (priv->transform))
{
offscreen_width = onscreen_height;
offscreen_height = onscreen_width;
}
else
{
offscreen_width = onscreen_width;
offscreen_height = onscreen_height;
}
offscreen = create_offscreen_with_formats (view,
formats,
n_formats,
offscreen_width,
offscreen_height,
&local_error);
if (!offscreen)
g_error ("Failed to allocate back buffer texture: %s", local_error->message);
g_set_object (&priv->offscreen, g_steal_pointer (&offscreen));
}
static void
init_shadowfb (ClutterStageView *view)
{
@ -419,10 +526,10 @@ clutter_stage_view_after_paint (ClutterStageView *view,
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
g_warn_if_fail (priv->ensure_offscreen_idle_id == 0);
if (priv->offscreen)
{
clutter_stage_view_ensure_offscreen_blit_pipeline (view);
if (priv->shadow.framebuffer)
{
CoglFramebuffer *shadowfb =
@ -522,6 +629,8 @@ clutter_stage_view_foreach_front_buffer (ClutterStageView *view,
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
g_warn_if_fail (priv->ensure_offscreen_idle_id == 0);
if (priv->offscreen)
{
callback (COGL_FRAMEBUFFER (priv->offscreen), user_data);
@ -1049,7 +1158,7 @@ clutter_stage_view_set_transform (ClutterStageView *view,
priv->transform = transform;
clutter_stage_view_invalidate_offscreen_blit_pipeline (CLUTTER_STAGE_VIEW (view));
clutter_stage_view_invalidate_offscreen (CLUTTER_STAGE_VIEW (view));
}
MtkMonitorTransform
@ -1085,9 +1194,6 @@ clutter_stage_view_get_property (GObject *object,
case PROP_FRAMEBUFFER:
g_value_set_object (value, priv->framebuffer);
break;
case PROP_OFFSCREEN:
g_value_set_object (value, priv->offscreen);
break;
case PROP_USE_SHADOWFB:
g_value_set_boolean (value, priv->use_shadowfb);
break;
@ -1139,9 +1245,6 @@ clutter_stage_view_set_property (GObject *object,
case PROP_FRAMEBUFFER:
clutter_stage_view_set_framebuffer (view, g_value_get_object (value));
break;
case PROP_OFFSCREEN:
priv->offscreen = g_value_dup_object (value);
break;
case PROP_USE_SHADOWFB:
priv->use_shadowfb = g_value_get_boolean (value);
break;
@ -1212,6 +1315,7 @@ clutter_stage_view_dispose (GObject *object)
g_clear_pointer (&priv->redraw_clip, mtk_region_unref);
g_clear_pointer (&priv->accumulated_redraw_clip, mtk_region_unref);
g_clear_pointer (&priv->frame_clock, clutter_frame_clock_destroy);
g_clear_handle_id (&priv->ensure_offscreen_idle_id, g_source_remove);
G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
}
@ -1279,13 +1383,6 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_OFFSCREEN] =
g_param_spec_object ("offscreen", NULL, NULL,
COGL_TYPE_OFFSCREEN,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_USE_SHADOWFB] =
g_param_spec_boolean ("use-shadowfb", NULL, NULL,
FALSE,

View file

@ -55,8 +55,6 @@ CLUTTER_EXPORT
CoglFramebuffer *clutter_stage_view_get_framebuffer (ClutterStageView *view);
CLUTTER_EXPORT
CoglFramebuffer *clutter_stage_view_get_onscreen (ClutterStageView *view);
CLUTTER_EXPORT
void clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view);
CLUTTER_EXPORT
float clutter_stage_view_get_scale (ClutterStageView *view);

View file

@ -1255,36 +1255,6 @@ meta_renderer_native_create_offscreen (MetaRendererNative *renderer_native,
return fb;
}
static CoglOffscreen *
create_offscreen_with_formats (MetaRendererNative *renderer_native,
CoglPixelFormat *formats,
size_t n_formats,
int width,
int height,
GError **error)
{
g_autoptr (GError) local_error = NULL;
size_t i;
for (i = 0; i < n_formats; i++)
{
CoglOffscreen *offscreen;
g_clear_error (&local_error);
offscreen = meta_renderer_native_create_offscreen (renderer_native,
formats[i],
width,
height,
&local_error);
if (offscreen)
return offscreen;
}
g_propagate_error (error, g_steal_pointer (&local_error));
return NULL;
}
static const CoglWinsysVtable *
get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer)
{
@ -1389,7 +1359,6 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
g_autoptr (ClutterColorState) blending_color_state = NULL;
MtkMonitorTransform view_transform;
g_autoptr (CoglFramebuffer) framebuffer = NULL;
g_autoptr (CoglOffscreen) offscreen = NULL;
gboolean use_shadowfb;
float scale;
int onscreen_width;
@ -1491,60 +1460,6 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
output,
crtc);
if (view_transform != MTK_MONITOR_TRANSFORM_NORMAL ||
!clutter_color_state_equals (color_state, blending_color_state))
{
int offscreen_width;
int offscreen_height;
CoglPixelFormat formats[10];
size_t n_formats = 0;
CoglPixelFormat format;
ClutterEncodingRequiredFormat required_format =
clutter_color_state_required_format (blending_color_state);
if (required_format <= CLUTTER_ENCODING_REQUIRED_FORMAT_UINT8)
{
formats[n_formats++] = cogl_framebuffer_get_internal_format (framebuffer);
}
else
{
formats[n_formats++] = COGL_PIXEL_FORMAT_XRGB_FP_16161616;
formats[n_formats++] = COGL_PIXEL_FORMAT_XBGR_FP_16161616;
formats[n_formats++] = COGL_PIXEL_FORMAT_RGBA_FP_16161616_PRE;
formats[n_formats++] = COGL_PIXEL_FORMAT_BGRA_FP_16161616_PRE;
formats[n_formats++] = COGL_PIXEL_FORMAT_ARGB_FP_16161616_PRE;
formats[n_formats++] = COGL_PIXEL_FORMAT_ABGR_FP_16161616_PRE;
}
if (mtk_monitor_transform_is_rotated (view_transform))
{
offscreen_width = onscreen_height;
offscreen_height = onscreen_width;
}
else
{
offscreen_width = onscreen_width;
offscreen_height = onscreen_height;
}
offscreen = create_offscreen_with_formats (renderer_native,
formats,
n_formats,
offscreen_width,
offscreen_height,
&local_error);
if (!offscreen)
g_error ("Failed to allocate back buffer texture: %s", local_error->message);
format =
cogl_framebuffer_get_internal_format (COGL_FRAMEBUFFER (offscreen));
meta_topic (META_DEBUG_RENDER,
"Using an additional intermediate %s offscreen (%dx%d) for %s",
cogl_pixel_format_to_string (format),
offscreen_width, offscreen_height,
meta_output_get_name (output));
}
if (meta_backend_is_stage_views_scaled (backend))
scale = meta_logical_monitor_get_scale (logical_monitor);
else
@ -1553,6 +1468,7 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
mtk_rectangle_from_graphene_rect (&crtc_config->layout,
MTK_ROUNDING_STRATEGY_ROUND,
&view_layout);
view_native = g_object_new (META_TYPE_RENDERER_VIEW_NATIVE,
"name", meta_output_get_name (output),
"stage", meta_backend_get_stage (backend),
@ -1560,7 +1476,6 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
"crtc", crtc,
"scale", scale,
"framebuffer", framebuffer,
"offscreen", offscreen,
"color-state", blending_color_state,
"output-color-state", color_state,
"use-shadowfb", use_shadowfb,