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:
parent
6a1749009f
commit
a91fd4a72c
3 changed files with 156 additions and 146 deletions
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue