mirror of
https://github.com/brl/mutter.git
synced 2025-02-11 02:44:09 +00:00
stage-cogl: Reuse backbuffer contents
Use the buffer_age extension when available to recycle backbuffer contents instead of blitting from the back to front buffer when doing clipped redraws. The picking is now done in a pixel that is going to be repaired during the next redraw cycle for non static scences. This should improve performance and avoid tearing. Reviewed-by: Robert Bragg <robert@linux.intel.com> https://bugzilla.gnome.org/show_bug.cgi?id=669122
This commit is contained in:
parent
60f20e8a7e
commit
b9ad93ad8d
@ -236,6 +236,23 @@ _clutter_stage_window_redraw (ClutterStageWindow *window)
|
||||
iface->redraw (window);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_clutter_stage_window_get_dirty_pixel (ClutterStageWindow *window,
|
||||
int *x, int *y)
|
||||
{
|
||||
ClutterStageWindowIface *iface;
|
||||
|
||||
*x = 0;
|
||||
*y = 0;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window));
|
||||
|
||||
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
|
||||
if (iface->get_dirty_pixel)
|
||||
iface->get_dirty_pixel (window, x, y);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_stage_window_dirty_back_buffer (ClutterStageWindow *window)
|
||||
{
|
||||
|
@ -75,6 +75,9 @@ struct _ClutterStageWindowIface
|
||||
|
||||
void (* dirty_back_buffer) (ClutterStageWindow *stage_window);
|
||||
|
||||
void (* get_dirty_pixel) (ClutterStageWindow *stage_window,
|
||||
int *x, int *y);
|
||||
|
||||
CoglFramebuffer *(* get_active_framebuffer) (ClutterStageWindow *stage_window);
|
||||
|
||||
gboolean (* can_clip_redraws) (ClutterStageWindow *stage_window);
|
||||
@ -121,6 +124,9 @@ void _clutter_stage_window_redraw (ClutterStageWin
|
||||
|
||||
void _clutter_stage_window_dirty_back_buffer (ClutterStageWindow *window);
|
||||
|
||||
void _clutter_stage_window_get_dirty_pixel (ClutterStageWindow *window,
|
||||
int *x, int *y);
|
||||
|
||||
CoglFramebuffer *_clutter_stage_window_get_active_framebuffer (ClutterStageWindow *window);
|
||||
|
||||
gboolean _clutter_stage_window_can_clip_redraws (ClutterStageWindow *window);
|
||||
|
@ -1417,6 +1417,9 @@ _clutter_stage_do_pick (ClutterStage *stage,
|
||||
CoglFramebuffer *fb;
|
||||
ClutterActor *actor;
|
||||
gboolean is_clipped;
|
||||
gint read_x;
|
||||
gint read_y;
|
||||
|
||||
CLUTTER_STATIC_COUNTER (do_pick_counter,
|
||||
"_clutter_stage_do_pick counter",
|
||||
"Increments for each full pick run",
|
||||
@ -1490,13 +1493,29 @@ _clutter_stage_do_pick (ClutterStage *stage,
|
||||
* picks for the same static scene won't require additional renders */
|
||||
if (priv->picks_per_frame < 2)
|
||||
{
|
||||
if (G_LIKELY (!(clutter_pick_debug_flags &
|
||||
CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
|
||||
cogl_clip_push_window_rectangle (x, y, 1, 1);
|
||||
gint dirty_x;
|
||||
gint dirty_y;
|
||||
|
||||
_clutter_stage_window_get_dirty_pixel (priv->impl, &dirty_x, &dirty_y);
|
||||
|
||||
if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
|
||||
cogl_clip_push_window_rectangle (dirty_x, dirty_y, 1, 1);
|
||||
|
||||
cogl_set_viewport (priv->viewport[0] - x + dirty_x,
|
||||
priv->viewport[1] - y + dirty_y,
|
||||
priv->viewport[2],
|
||||
priv->viewport[3]);
|
||||
|
||||
read_x = dirty_x;
|
||||
read_y = dirty_y;
|
||||
is_clipped = TRUE;
|
||||
}
|
||||
else
|
||||
is_clipped = FALSE;
|
||||
{
|
||||
read_x = x;
|
||||
read_y = y;
|
||||
is_clipped = FALSE;
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (PICK, "Performing %s pick at %i,%i",
|
||||
is_clipped ? "clippped" : "full", x, y);
|
||||
@ -1522,21 +1541,6 @@ _clutter_stage_do_pick (ClutterStage *stage,
|
||||
context->pick_mode = CLUTTER_PICK_NONE;
|
||||
CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_paint);
|
||||
|
||||
/* Notify the backend that we have trashed the contents of
|
||||
* the back buffer... */
|
||||
_clutter_stage_window_dirty_back_buffer (priv->impl);
|
||||
|
||||
if (is_clipped)
|
||||
{
|
||||
if (G_LIKELY (!(clutter_pick_debug_flags &
|
||||
CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
|
||||
cogl_clip_pop ();
|
||||
|
||||
_clutter_stage_set_pick_buffer_valid (stage, FALSE, -1);
|
||||
}
|
||||
else
|
||||
_clutter_stage_set_pick_buffer_valid (stage, TRUE, mode);
|
||||
|
||||
/* Read the color of the screen co-ords pixel. RGBA_8888_PRE is used
|
||||
even though we don't care about the alpha component because under
|
||||
GLES this is the only format that is guaranteed to work so Cogl
|
||||
@ -1545,7 +1549,7 @@ _clutter_stage_do_pick (ClutterStage *stage,
|
||||
assumes that all pixels in the framebuffer are premultiplied so
|
||||
it avoids a conversion. */
|
||||
CLUTTER_TIMER_START (_clutter_uprof_context, pick_read);
|
||||
cogl_read_pixels (x, y, 1, 1,
|
||||
cogl_read_pixels (read_x, read_y, 1, 1,
|
||||
COGL_READ_PIXELS_COLOR_BUFFER,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
|
||||
pixel);
|
||||
@ -1568,6 +1572,24 @@ _clutter_stage_do_pick (ClutterStage *stage,
|
||||
/* Restore whether GL_DITHER was enabled */
|
||||
cogl_framebuffer_set_dither_enabled (fb, dither_enabled_save);
|
||||
|
||||
if (is_clipped)
|
||||
{
|
||||
if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
|
||||
cogl_clip_pop ();
|
||||
|
||||
_clutter_stage_dirty_viewport (stage);
|
||||
|
||||
_clutter_stage_set_pick_buffer_valid (stage, FALSE, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Notify the backend that we have trashed the contents of
|
||||
* the back buffer... */
|
||||
_clutter_stage_window_dirty_back_buffer (priv->impl);
|
||||
|
||||
_clutter_stage_set_pick_buffer_valid (stage, TRUE, mode);
|
||||
}
|
||||
|
||||
check_pixel:
|
||||
if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
|
||||
{
|
||||
|
@ -319,7 +319,10 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
gboolean may_use_clipped_redraw;
|
||||
gboolean use_clipped_redraw;
|
||||
gboolean can_blit_sub_buffer;
|
||||
gboolean has_buffer_age;
|
||||
ClutterActor *wrapper;
|
||||
cairo_rectangle_int_t *clip_region;
|
||||
gboolean force_swap;
|
||||
|
||||
CLUTTER_STATIC_TIMER (painting_timer,
|
||||
"Redrawing", /* parent */
|
||||
@ -347,6 +350,8 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
can_blit_sub_buffer =
|
||||
cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION);
|
||||
|
||||
has_buffer_age = cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
|
||||
|
||||
may_use_clipped_redraw = FALSE;
|
||||
if (_clutter_stage_window_can_clip_redraws (stage_window) &&
|
||||
can_blit_sub_buffer &&
|
||||
@ -357,6 +362,7 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
stage_cogl->frame_count > 3)
|
||||
{
|
||||
may_use_clipped_redraw = TRUE;
|
||||
clip_region = &stage_cogl->bounding_redraw_clip;
|
||||
}
|
||||
|
||||
if (may_use_clipped_redraw &&
|
||||
@ -366,23 +372,83 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
else
|
||||
use_clipped_redraw = FALSE;
|
||||
|
||||
force_swap = FALSE;
|
||||
|
||||
if (use_clipped_redraw)
|
||||
{
|
||||
if (has_buffer_age)
|
||||
{
|
||||
int age = cogl_onscreen_get_buffer_age (stage_cogl->onscreen);
|
||||
cairo_rectangle_int_t *current_damage;
|
||||
|
||||
current_damage = g_new0 (cairo_rectangle_int_t, 1);
|
||||
current_damage->x = clip_region->x;
|
||||
current_damage->y = clip_region->y;
|
||||
current_damage->width = clip_region->width;
|
||||
current_damage->height = clip_region->height;
|
||||
|
||||
stage_cogl->damage_history = g_slist_prepend (stage_cogl->damage_history, current_damage);
|
||||
|
||||
if (age != 0 && !stage_cogl->dirty_backbuffer && g_slist_length (stage_cogl->damage_history) >= age)
|
||||
{
|
||||
int i = 0;
|
||||
GSList *tmp = NULL;
|
||||
for (tmp = stage_cogl->damage_history; tmp; tmp = tmp->next)
|
||||
{
|
||||
_clutter_util_rectangle_union (clip_region, tmp->data, clip_region);
|
||||
i++;
|
||||
if (i == age)
|
||||
{
|
||||
g_slist_free_full (tmp->next, g_free);
|
||||
tmp->next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
force_swap = TRUE;
|
||||
|
||||
CLUTTER_NOTE (CLIPPING, "Reusing back buffer - repairing region: x=%d, y=%d, width=%d, height=%d\n",
|
||||
clip_region->x,
|
||||
clip_region->y,
|
||||
clip_region->width,
|
||||
clip_region->height);
|
||||
|
||||
}
|
||||
else if (age == 0 || stage_cogl->dirty_backbuffer)
|
||||
{
|
||||
CLUTTER_NOTE (CLIPPING, "Invalid back buffer: Resetting damage history list.\n");
|
||||
g_slist_free_full (stage_cogl->damage_history, g_free);
|
||||
stage_cogl->damage_history = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLUTTER_NOTE (CLIPPING, "Unclipped redraw: Resetting damage history list.\n");
|
||||
g_slist_free_full (stage_cogl->damage_history, g_free);
|
||||
stage_cogl->damage_history = NULL;
|
||||
}
|
||||
|
||||
if (has_buffer_age && !force_swap)
|
||||
use_clipped_redraw = FALSE;
|
||||
|
||||
if (use_clipped_redraw)
|
||||
{
|
||||
CLUTTER_NOTE (CLIPPING,
|
||||
"Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n",
|
||||
stage_cogl->bounding_redraw_clip.x,
|
||||
stage_cogl->bounding_redraw_clip.y,
|
||||
stage_cogl->bounding_redraw_clip.width,
|
||||
stage_cogl->bounding_redraw_clip.height);
|
||||
clip_region->x,
|
||||
clip_region->y,
|
||||
clip_region->width,
|
||||
clip_region->height);
|
||||
|
||||
stage_cogl->using_clipped_redraw = TRUE;
|
||||
|
||||
cogl_clip_push_window_rectangle (stage_cogl->bounding_redraw_clip.x,
|
||||
stage_cogl->bounding_redraw_clip.y,
|
||||
stage_cogl->bounding_redraw_clip.width,
|
||||
stage_cogl->bounding_redraw_clip.height);
|
||||
cogl_clip_push_window_rectangle (clip_region->x,
|
||||
clip_region->y,
|
||||
clip_region->width,
|
||||
clip_region->height);
|
||||
_clutter_stage_do_paint (CLUTTER_STAGE (wrapper),
|
||||
&stage_cogl->bounding_redraw_clip);
|
||||
clip_region);
|
||||
cogl_clip_pop ();
|
||||
|
||||
stage_cogl->using_clipped_redraw = FALSE;
|
||||
@ -398,7 +464,7 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
may_use_clipped_redraw)
|
||||
{
|
||||
_clutter_stage_do_paint (CLUTTER_STAGE (wrapper),
|
||||
&stage_cogl->bounding_redraw_clip);
|
||||
clip_region);
|
||||
}
|
||||
else
|
||||
_clutter_stage_do_paint (CLUTTER_STAGE (wrapper), NULL);
|
||||
@ -450,9 +516,9 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
|
||||
CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer);
|
||||
|
||||
/* push on the screen */
|
||||
if (use_clipped_redraw)
|
||||
if (use_clipped_redraw && !force_swap)
|
||||
{
|
||||
cairo_rectangle_int_t *clip = &stage_cogl->bounding_redraw_clip;
|
||||
cairo_rectangle_int_t *clip = clip_region;
|
||||
int copy_area[4];
|
||||
|
||||
/* XXX: It seems there will be a race here in that the stage
|
||||
@ -524,6 +590,26 @@ clutter_stage_cogl_dirty_back_buffer (ClutterStageWindow *stage_window)
|
||||
stage_cogl->dirty_backbuffer = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_cogl_get_dirty_pixel (ClutterStageWindow *stage_window,
|
||||
int *x, int *y)
|
||||
{
|
||||
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
|
||||
gboolean has_buffer_age = cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
|
||||
if ((stage_cogl->damage_history == NULL && has_buffer_age) || !has_buffer_age)
|
||||
{
|
||||
*x = 0;
|
||||
*y = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_rectangle_int_t *rect;
|
||||
rect = (cairo_rectangle_int_t *) (stage_cogl->damage_history->data);
|
||||
*x = rect->x;
|
||||
*y = rect->y;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
|
||||
{
|
||||
@ -542,6 +628,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
|
||||
iface->redraw = clutter_stage_cogl_redraw;
|
||||
iface->get_active_framebuffer = clutter_stage_cogl_get_active_framebuffer;
|
||||
iface->dirty_back_buffer = clutter_stage_cogl_dirty_back_buffer;
|
||||
iface->get_dirty_pixel = clutter_stage_cogl_get_dirty_pixel;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -52,6 +52,9 @@ struct _ClutterStageCogl
|
||||
guint using_clipped_redraw : 1;
|
||||
|
||||
guint dirty_backbuffer : 1;
|
||||
|
||||
/* Stores a list of previous damaged areas */
|
||||
GSList *damage_history;
|
||||
};
|
||||
|
||||
struct _ClutterStageCoglClass
|
||||
|
Loading…
x
Reference in New Issue
Block a user