diff options
author | Robert Bragg <robert@linux.intel.com> | 2011-03-22 00:26:34 +0000 |
---|---|---|
committer | Robert Bragg <robert@linux.intel.com> | 2011-04-01 17:26:29 +0100 |
commit | a9c667a34dfee4a4aeceda3357334a394a16023d (patch) | |
tree | 3fe6a525449caa363e3ea358b0293a950e35b7e4 | |
parent | 5c548ad9bd95bcec0c43bfe6c313b8f391ab2abd (diff) | |
download | clutter-a9c667a34dfee4a4aeceda3357334a394a16023d.tar.gz |
experimental clipped redraws without extensionwip/clip-with-swap-buffers
This implements an experimental approach to supporting clipped redraws
without the aid of an extension. Instead it depends on making an
assumption about the number of back buffers provided by the driver.
To tell Clutter about the number of back buffers set
CLUTTER_SWAP_CHAIN_LENGTH=3 for example in your environment before
running a Clutter app.
Note: This is unlikely to be big win if your driver doesn't actually
support flipping back buffers and instead uses a blit to present.
Compared to the blit based clipped redraw path we have when using GLX
one significant issue is that the whole window will effectively be
damaged when using glXSwapBuffers which means the whole window could
end up being blitted if the window isn't fullscreen. Even when
compositing, because we don't have a way to report a limited damage
region the compositor will be told that the whole window has been
damage.
-rw-r--r-- | clutter/glx/clutter-stage-glx.c | 87 | ||||
-rw-r--r-- | clutter/glx/clutter-stage-glx.h | 6 |
2 files changed, 75 insertions, 18 deletions
diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index a2ae2dabe..66e78707f 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -47,6 +47,7 @@ #include <sys/ioctl.h> #include <fcntl.h> #include <errno.h> +#include <stdlib.h> #ifdef HAVE_DRM #include <drm.h> @@ -108,6 +109,11 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window) if (!_clutter_stage_x11_create_window (stage_x11)) return FALSE; + if (getenv ("CLUTTER_SWAP_CHAIN_LENGTH")) + stage_glx->max_old_redraw_clips = + strtoul (getenv ("CLUTTER_SWAP_CHAIN_LENGTH"), NULL, 10) - 1; + stage_glx->n_old_redraw_clips = 0; + backend_x11 = stage_x11->backend; backend_glx = CLUTTER_BACKEND_GLX (backend_x11); @@ -371,7 +377,10 @@ clutter_stage_glx_redraw (ClutterStageWindow *stage_window) GLXDrawable drawable; unsigned int video_sync_count; gboolean may_use_clipped_redraw; + gboolean have_final_clip; gboolean use_clipped_redraw; + ClutterGeometry final_clip; + int i; CLUTTER_STATIC_TIMER (painting_timer, "Redrawing", /* parent */ @@ -400,7 +409,8 @@ clutter_stage_glx_redraw (ClutterStageWindow *stage_window) CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer); - if (G_LIKELY (backend_glx->can_blit_sub_buffer) && + if ((G_LIKELY (backend_glx->can_blit_sub_buffer) || + stage_glx->max_old_redraw_clips) && /* NB: a zero width redraw clip == full stage redraw */ stage_glx->bounding_redraw_clip.width != 0 && /* some drivers struggle to get going and produce some junk @@ -414,9 +424,49 @@ clutter_stage_glx_redraw (ClutterStageWindow *stage_window) may_use_clipped_redraw = TRUE; } else - may_use_clipped_redraw = FALSE; + { + stage_glx->n_old_redraw_clips = 0; + may_use_clipped_redraw = FALSE; + } + + if (may_use_clipped_redraw) + { + if (stage_glx->max_old_redraw_clips) + { + /* shift old redraw clips along and record the latest... */ + for (i = 0; i < stage_glx->max_old_redraw_clips - 1; i++) + stage_glx->old_redraw_clips[i] = stage_glx->old_redraw_clips[i + 1]; + stage_glx->old_redraw_clips[stage_glx->max_old_redraw_clips - 1] = + stage_glx->bounding_redraw_clip; + + /* Only if the history of old redraw clips is full then we + * can perform a clipped redraw... */ + if (stage_glx->n_old_redraw_clips == stage_glx->max_old_redraw_clips) + { + final_clip = stage_glx->old_redraw_clips[0]; + for (i = 1; i < stage_glx->max_old_redraw_clips; i++) + clutter_geometry_union (&stage_glx->old_redraw_clips[i], + &final_clip, + &final_clip); + + have_final_clip = TRUE; + } + else + { + stage_glx->n_old_redraw_clips++; + have_final_clip = FALSE; + } + } + else + { + final_clip = stage_glx->bounding_redraw_clip; + have_final_clip = TRUE; + } + } + else + have_final_clip = FALSE; - if (may_use_clipped_redraw && + if (have_final_clip && G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS))) use_clipped_redraw = TRUE; @@ -425,31 +475,31 @@ clutter_stage_glx_redraw (ClutterStageWindow *stage_window) if (use_clipped_redraw) { - CLUTTER_NOTE (CLIPPING, + CLUTTER_NOTE (BACKEND, "Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n", - stage_glx->bounding_redraw_clip.x, - stage_glx->bounding_redraw_clip.y, - stage_glx->bounding_redraw_clip.width, - stage_glx->bounding_redraw_clip.height); - cogl_clip_push_window_rectangle (stage_glx->bounding_redraw_clip.x, - stage_glx->bounding_redraw_clip.y, - stage_glx->bounding_redraw_clip.width, - stage_glx->bounding_redraw_clip.height); - _clutter_stage_do_paint (stage_x11->wrapper, - &stage_glx->bounding_redraw_clip); + final_clip.x, + final_clip.y, + final_clip.width, + final_clip.height); + + cogl_clip_push_window_rectangle (final_clip.x, + final_clip.y, + final_clip.width, + final_clip.height); + _clutter_stage_do_paint (stage_x11->wrapper, &final_clip); cogl_clip_pop (); } else { - CLUTTER_NOTE (CLIPPING, "Unclipped stage paint\n"); + CLUTTER_NOTE (BACKEND, "Unclipped stage paint\n"); _clutter_stage_do_paint (stage_x11->wrapper, NULL); } - if (may_use_clipped_redraw && + if (have_final_clip && G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))) { static CoglMaterial *outline = NULL; - ClutterGeometry *clip = &stage_glx->bounding_redraw_clip; + ClutterGeometry *clip = &final_clip; ClutterActor *actor = CLUTTER_ACTOR (stage_x11->wrapper); CoglHandle vbo; float x_1 = clip->x; @@ -510,7 +560,8 @@ clutter_stage_glx_redraw (ClutterStageWindow *stage_window) backend_glx->get_video_sync (&video_sync_count); /* push on the screen */ - if (use_clipped_redraw) + if (use_clipped_redraw && + stage_glx->max_old_redraw_clips == 0) { ClutterGeometry *clip = &stage_glx->bounding_redraw_clip; ClutterGeometry copy_area; diff --git a/clutter/glx/clutter-stage-glx.h b/clutter/glx/clutter-stage-glx.h index 9baa0f3d4..37f219ec8 100644 --- a/clutter/glx/clutter-stage-glx.h +++ b/clutter/glx/clutter-stage-glx.h @@ -44,6 +44,8 @@ G_BEGIN_DECLS typedef struct _ClutterStageGLX ClutterStageGLX; typedef struct _ClutterStageGLXClass ClutterStageGLXClass; +#define CLUTTER_STAGE_GLX_MAX_SWAP_CHAIN_LENGTH 3 + struct _ClutterStageGLX { ClutterStageX11 parent_instance; @@ -61,6 +63,10 @@ struct _ClutterStageGLX ClutterGeometry bounding_redraw_clip; + ClutterGeometry old_redraw_clips[CLUTTER_STAGE_GLX_MAX_SWAP_CHAIN_LENGTH - 1]; + int n_old_redraw_clips; + int max_old_redraw_clips; + guint initialized_redraw_clip : 1; }; |