clutter/stage-view: Separate offscreen and shadowfb
Previously, we would use a single offscreen framebuffer for both transformations and when a shadow framebuffer should be used, but that can be dreadfully slow when using software rendering with a discrete GPU due to bandwidth limitations. Keep the offscreen framebuffer for transformations only and add another intermediate shadow framebuffer used as a copy of the onscreen framebuffer. https://gitlab.gnome.org/GNOME/mutter/merge_requests/877
This commit is contained in:
parent
e5b0f474ab
commit
db90c0d509
@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
#include "clutter/clutter-stage-view.h"
|
#include "clutter/clutter-stage-view.h"
|
||||||
|
|
||||||
void clutter_stage_view_blit_offscreen (ClutterStageView *view,
|
void clutter_stage_view_after_paint (ClutterStageView *view,
|
||||||
const cairo_rectangle_int_t *clip);
|
const cairo_rectangle_int_t *clip);
|
||||||
|
|
||||||
gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
|
gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ enum
|
|||||||
PROP_LAYOUT,
|
PROP_LAYOUT,
|
||||||
PROP_FRAMEBUFFER,
|
PROP_FRAMEBUFFER,
|
||||||
PROP_OFFSCREEN,
|
PROP_OFFSCREEN,
|
||||||
|
PROP_SHADOWFB,
|
||||||
PROP_SCALE,
|
PROP_SCALE,
|
||||||
|
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
@ -44,7 +45,10 @@ typedef struct _ClutterStageViewPrivate
|
|||||||
CoglFramebuffer *framebuffer;
|
CoglFramebuffer *framebuffer;
|
||||||
|
|
||||||
CoglOffscreen *offscreen;
|
CoglOffscreen *offscreen;
|
||||||
CoglPipeline *pipeline;
|
CoglPipeline *offscreen_pipeline;
|
||||||
|
|
||||||
|
CoglOffscreen *shadowfb;
|
||||||
|
CoglPipeline *shadowfb_pipeline;
|
||||||
|
|
||||||
guint dirty_viewport : 1;
|
guint dirty_viewport : 1;
|
||||||
guint dirty_projection : 1;
|
guint dirty_projection : 1;
|
||||||
@ -78,6 +82,8 @@ clutter_stage_view_get_framebuffer (ClutterStageView *view)
|
|||||||
|
|
||||||
if (priv->offscreen)
|
if (priv->offscreen)
|
||||||
return priv->offscreen;
|
return priv->offscreen;
|
||||||
|
else if (priv->shadowfb)
|
||||||
|
return priv->shadowfb;
|
||||||
else
|
else
|
||||||
return priv->framebuffer;
|
return priv->framebuffer;
|
||||||
}
|
}
|
||||||
@ -99,6 +105,24 @@ clutter_stage_view_get_onscreen (ClutterStageView *view)
|
|||||||
return priv->framebuffer;
|
return priv->framebuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CoglPipeline *
|
||||||
|
clutter_stage_view_create_framebuffer_pipeline (CoglFramebuffer *framebuffer)
|
||||||
|
{
|
||||||
|
CoglPipeline *pipeline;
|
||||||
|
|
||||||
|
pipeline = cogl_pipeline_new (cogl_framebuffer_get_context (framebuffer));
|
||||||
|
|
||||||
|
cogl_pipeline_set_layer_filters (pipeline, 0,
|
||||||
|
COGL_PIPELINE_FILTER_NEAREST,
|
||||||
|
COGL_PIPELINE_FILTER_NEAREST);
|
||||||
|
cogl_pipeline_set_layer_texture (pipeline, 0,
|
||||||
|
cogl_offscreen_get_texture (framebuffer));
|
||||||
|
cogl_pipeline_set_layer_wrap_mode (pipeline, 0,
|
||||||
|
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
|
clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
|
||||||
{
|
{
|
||||||
@ -109,21 +133,27 @@ clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
|
|||||||
|
|
||||||
g_assert (priv->offscreen != NULL);
|
g_assert (priv->offscreen != NULL);
|
||||||
|
|
||||||
if (priv->pipeline)
|
if (priv->offscreen_pipeline)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
priv->pipeline =
|
priv->offscreen_pipeline =
|
||||||
cogl_pipeline_new (cogl_framebuffer_get_context (priv->offscreen));
|
clutter_stage_view_create_framebuffer_pipeline (priv->offscreen);
|
||||||
cogl_pipeline_set_layer_filters (priv->pipeline, 0,
|
|
||||||
COGL_PIPELINE_FILTER_NEAREST,
|
|
||||||
COGL_PIPELINE_FILTER_NEAREST);
|
|
||||||
cogl_pipeline_set_layer_texture (priv->pipeline, 0,
|
|
||||||
cogl_offscreen_get_texture (priv->offscreen));
|
|
||||||
cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0,
|
|
||||||
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
if (view_class->setup_offscreen_blit_pipeline)
|
if (view_class->setup_offscreen_blit_pipeline)
|
||||||
view_class->setup_offscreen_blit_pipeline (view, priv->pipeline);
|
view_class->setup_offscreen_blit_pipeline (view, priv->offscreen_pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clutter_stage_view_ensure_shadowfb_blit_pipeline (ClutterStageView *view)
|
||||||
|
{
|
||||||
|
ClutterStageViewPrivate *priv =
|
||||||
|
clutter_stage_view_get_instance_private (view);
|
||||||
|
|
||||||
|
if (priv->shadowfb_pipeline)
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv->shadowfb_pipeline =
|
||||||
|
clutter_stage_view_create_framebuffer_pipeline (priv->shadowfb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -132,48 +162,93 @@ clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
|
|||||||
ClutterStageViewPrivate *priv =
|
ClutterStageViewPrivate *priv =
|
||||||
clutter_stage_view_get_instance_private (view);
|
clutter_stage_view_get_instance_private (view);
|
||||||
|
|
||||||
g_clear_pointer (&priv->pipeline, cogl_object_unref);
|
g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
clutter_stage_view_blit_offscreen (ClutterStageView *view,
|
clutter_stage_view_copy_to_framebuffer (ClutterStageView *view,
|
||||||
const cairo_rectangle_int_t *rect)
|
const cairo_rectangle_int_t *rect,
|
||||||
|
CoglPipeline *pipeline,
|
||||||
|
CoglFramebuffer *src_framebuffer,
|
||||||
|
CoglFramebuffer *dst_framebuffer,
|
||||||
|
gboolean can_blit)
|
||||||
{
|
{
|
||||||
ClutterStageViewPrivate *priv =
|
|
||||||
clutter_stage_view_get_instance_private (view);
|
|
||||||
CoglMatrix matrix;
|
CoglMatrix matrix;
|
||||||
|
|
||||||
clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
|
/* First, try with blit */
|
||||||
if (cogl_matrix_is_identity (&matrix))
|
if (can_blit)
|
||||||
{
|
{
|
||||||
int fb_width = cogl_framebuffer_get_width (priv->framebuffer);
|
if (cogl_blit_framebuffer (src_framebuffer,
|
||||||
int fb_height = cogl_framebuffer_get_height (priv->framebuffer);
|
dst_framebuffer,
|
||||||
|
|
||||||
if (cogl_blit_framebuffer (priv->offscreen,
|
|
||||||
priv->framebuffer,
|
|
||||||
0, 0,
|
0, 0,
|
||||||
0, 0,
|
0, 0,
|
||||||
fb_width, fb_height,
|
cogl_framebuffer_get_width (dst_framebuffer),
|
||||||
|
cogl_framebuffer_get_height (dst_framebuffer),
|
||||||
NULL))
|
NULL))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
clutter_stage_view_ensure_offscreen_blit_pipeline (view);
|
/* If blit fails, fallback to the slower painting method */
|
||||||
cogl_framebuffer_push_matrix (priv->framebuffer);
|
cogl_framebuffer_push_matrix (dst_framebuffer);
|
||||||
|
|
||||||
/* Set transform so 0,0 is on the top left corner and 1,1 on
|
|
||||||
* the bottom right corner.
|
|
||||||
*/
|
|
||||||
cogl_matrix_init_identity (&matrix);
|
cogl_matrix_init_identity (&matrix);
|
||||||
cogl_matrix_translate (&matrix, -1, 1, 0);
|
cogl_matrix_translate (&matrix, -1, 1, 0);
|
||||||
cogl_matrix_scale (&matrix, 2, -2, 0);
|
cogl_matrix_scale (&matrix, 2, -2, 0);
|
||||||
cogl_framebuffer_set_projection_matrix (priv->framebuffer, &matrix);
|
cogl_framebuffer_set_projection_matrix (dst_framebuffer, &matrix);
|
||||||
|
|
||||||
cogl_framebuffer_draw_rectangle (priv->framebuffer,
|
cogl_framebuffer_draw_rectangle (dst_framebuffer,
|
||||||
priv->pipeline,
|
pipeline,
|
||||||
0, 0, 1, 1);
|
0, 0, 1, 1);
|
||||||
|
|
||||||
cogl_framebuffer_pop_matrix (priv->framebuffer);
|
cogl_framebuffer_pop_matrix (dst_framebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clutter_stage_view_after_paint (ClutterStageView *view,
|
||||||
|
const cairo_rectangle_int_t *rect)
|
||||||
|
{
|
||||||
|
ClutterStageViewPrivate *priv =
|
||||||
|
clutter_stage_view_get_instance_private (view);
|
||||||
|
|
||||||
|
if (priv->offscreen)
|
||||||
|
{
|
||||||
|
gboolean can_blit;
|
||||||
|
CoglMatrix matrix;
|
||||||
|
|
||||||
|
clutter_stage_view_ensure_offscreen_blit_pipeline (view);
|
||||||
|
clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
|
||||||
|
can_blit = cogl_matrix_is_identity (&matrix);
|
||||||
|
|
||||||
|
if (priv->shadowfb)
|
||||||
|
{
|
||||||
|
clutter_stage_view_copy_to_framebuffer (view,
|
||||||
|
rect,
|
||||||
|
priv->offscreen_pipeline,
|
||||||
|
priv->offscreen,
|
||||||
|
priv->shadowfb,
|
||||||
|
can_blit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clutter_stage_view_copy_to_framebuffer (view,
|
||||||
|
rect,
|
||||||
|
priv->offscreen_pipeline,
|
||||||
|
priv->offscreen,
|
||||||
|
priv->framebuffer,
|
||||||
|
can_blit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->shadowfb)
|
||||||
|
{
|
||||||
|
clutter_stage_view_ensure_shadowfb_blit_pipeline (view);
|
||||||
|
clutter_stage_view_copy_to_framebuffer (view,
|
||||||
|
rect,
|
||||||
|
priv->shadowfb_pipeline,
|
||||||
|
priv->shadowfb,
|
||||||
|
priv->framebuffer,
|
||||||
|
TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
@ -273,6 +348,9 @@ clutter_stage_view_get_property (GObject *object,
|
|||||||
case PROP_OFFSCREEN:
|
case PROP_OFFSCREEN:
|
||||||
g_value_set_boxed (value, priv->offscreen);
|
g_value_set_boxed (value, priv->offscreen);
|
||||||
break;
|
break;
|
||||||
|
case PROP_SHADOWFB:
|
||||||
|
g_value_set_boxed (value, priv->shadowfb);
|
||||||
|
break;
|
||||||
case PROP_SCALE:
|
case PROP_SCALE:
|
||||||
g_value_set_float (value, priv->scale);
|
g_value_set_float (value, priv->scale);
|
||||||
break;
|
break;
|
||||||
@ -318,6 +396,9 @@ clutter_stage_view_set_property (GObject *object,
|
|||||||
case PROP_OFFSCREEN:
|
case PROP_OFFSCREEN:
|
||||||
priv->offscreen = g_value_dup_boxed (value);
|
priv->offscreen = g_value_dup_boxed (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_SHADOWFB:
|
||||||
|
priv->shadowfb = g_value_dup_boxed (value);
|
||||||
|
break;
|
||||||
case PROP_SCALE:
|
case PROP_SCALE:
|
||||||
priv->scale = g_value_get_float (value);
|
priv->scale = g_value_get_float (value);
|
||||||
break;
|
break;
|
||||||
@ -334,8 +415,10 @@ clutter_stage_view_dispose (GObject *object)
|
|||||||
clutter_stage_view_get_instance_private (view);
|
clutter_stage_view_get_instance_private (view);
|
||||||
|
|
||||||
g_clear_pointer (&priv->framebuffer, cogl_object_unref);
|
g_clear_pointer (&priv->framebuffer, cogl_object_unref);
|
||||||
|
g_clear_pointer (&priv->shadowfb, cogl_object_unref);
|
||||||
g_clear_pointer (&priv->offscreen, cogl_object_unref);
|
g_clear_pointer (&priv->offscreen, cogl_object_unref);
|
||||||
g_clear_pointer (&priv->pipeline, cogl_object_unref);
|
g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
|
||||||
|
g_clear_pointer (&priv->shadowfb_pipeline, cogl_object_unref);
|
||||||
|
|
||||||
G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
|
G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
@ -390,6 +473,15 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
|
|||||||
G_PARAM_CONSTRUCT_ONLY |
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
G_PARAM_STATIC_STRINGS);
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
obj_props[PROP_SHADOWFB] =
|
||||||
|
g_param_spec_boxed ("shadowfb",
|
||||||
|
"Shadow framebuffer",
|
||||||
|
"Framebuffer used as intermediate shadow buffer",
|
||||||
|
COGL_TYPE_HANDLE,
|
||||||
|
G_PARAM_READWRITE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
obj_props[PROP_SCALE] =
|
obj_props[PROP_SCALE] =
|
||||||
g_param_spec_float ("scale",
|
g_param_spec_float ("scale",
|
||||||
"View scale",
|
"View scale",
|
||||||
|
@ -563,11 +563,7 @@ paint_stage (ClutterStageCogl *stage_cogl,
|
|||||||
_clutter_stage_maybe_setup_viewport (stage, view);
|
_clutter_stage_maybe_setup_viewport (stage, view);
|
||||||
_clutter_stage_paint_view (stage, view, &paint_rect);
|
_clutter_stage_paint_view (stage, view, &paint_rect);
|
||||||
|
|
||||||
if (clutter_stage_view_get_onscreen (view) !=
|
clutter_stage_view_after_paint (view, &paint_rect);
|
||||||
clutter_stage_view_get_framebuffer (view))
|
|
||||||
{
|
|
||||||
clutter_stage_view_blit_offscreen (view, &paint_rect);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Loading…
Reference in New Issue
Block a user