backend-glx: Provide copy_sub_buffer fallback

Currently glXCopySubBufferMESA is used for sub stage redraws, but in case
a driver does not support GLX_MESA_copy_sub_buffer we fall back to redrawing
the complete stage which isn't really optimal.

So instead to directly fallback to complete redraws try using GL_EXT_framebuffer_blit
to do the BACK to FRONT buffer copies.

http://bugzilla.openedhand.com/show_bug.cgi?id=2128
This commit is contained in:
Adel Gadllah 2010-06-05 12:51:32 +02:00 committed by Robert Bragg
parent ac3e0150ed
commit 630a2c5edc
3 changed files with 66 additions and 16 deletions

View File

@ -215,6 +215,7 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
{
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
const gchar *glx_extensions = NULL;
const gchar *gl_extensions = NULL;
ClutterFeatureFlags flags;
gboolean use_dri = FALSE;
@ -242,6 +243,8 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
CLUTTER_NOTE (BACKEND, " GLX Extensions: %s", glx_extensions);
gl_extensions = (const gchar *)glGetString (GL_EXTENSIONS);
use_dri = check_vblank_env ("dri");
/* First check for explicit disabling or it set elsewhere (eg NVIDIA) */
@ -363,6 +366,15 @@ vblank_setup_done:
{
backend_glx->copy_sub_buffer =
(CopySubBufferProc) cogl_get_proc_address ("glXCopySubBufferMESA");
backend_glx->can_blit_sub_buffer = TRUE;
}
else if (_cogl_check_extension ("GL_EXT_framebuffer_blit", gl_extensions))
{
CLUTTER_NOTE (BACKEND,
"Using glBlitFramebuffer fallback for sub_buffer copies");
backend_glx->blit_framebuffer =
(BlitFramebufferProc) cogl_get_proc_address ("glBlitFramebuffer");
backend_glx->can_blit_sub_buffer = TRUE;
}
CLUTTER_NOTE (BACKEND, "backend features checked");
@ -464,6 +476,29 @@ _clutter_backend_glx_get_fbconfig (ClutterBackendGLX *backend_glx,
return FALSE;
}
void
_clutter_backend_glx_blit_sub_buffer (ClutterBackendGLX *backend_glx,
GLXDrawable drawable,
int x, int y, int width, int height)
{
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend_glx);
if (backend_glx->copy_sub_buffer)
{
backend_glx->copy_sub_buffer (backend_x11->xdpy, drawable,
x, y, width, height);
}
else if (backend_glx->blit_framebuffer)
{
glDrawBuffer (GL_FRONT);
backend_glx->blit_framebuffer (x, y, x + width, y + height,
x, y, x + width, y + height,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glDrawBuffer (GL_BACK);
glFlush();
}
}
static XVisualInfo *
clutter_backend_glx_get_visual_info (ClutterBackendX11 *backend_x11)
{

View File

@ -60,6 +60,16 @@ typedef int (*SwapIntervalProc) (int interval);
typedef void (*CopySubBufferProc)(Display *dpy,
GLXDrawable drawable,
int x, int y, int width, int height);
typedef void (*BlitFramebufferProc) (GLint srcX0,
GLint srcY0,
GLint srcX1,
GLint srcY1,
GLint dstX0,
GLint dstY0,
GLint dstX1,
GLint dstY1,
GLbitfield mask,
GLenum filter);
struct _ClutterBackendGLX
{
@ -82,7 +92,9 @@ struct _ClutterBackendGLX
gint dri_fd;
ClutterGLXVBlankType vblank_type;
gboolean can_blit_sub_buffer;
CopySubBufferProc copy_sub_buffer;
BlitFramebufferProc blit_framebuffer;
/* props */
Atom atom_WM_STATE;
@ -100,6 +112,11 @@ gboolean
_clutter_backend_glx_get_fbconfig (ClutterBackendGLX *backend_x11,
GLXFBConfig *config);
void
_clutter_backend_glx_blit_sub_buffer (ClutterBackendGLX *backend_glx,
GLXDrawable drawable,
int x, int y, int width, int height);
G_END_DECLS
#endif /* __CLUTTER_BACKEND_GLX_H__ */

View File

@ -547,10 +547,10 @@ clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
"glXSwapBuffers",
"The time spent blocked by glXSwapBuffers",
0 /* no application private data */);
CLUTTER_STATIC_TIMER (copy_sub_buffer_timer,
CLUTTER_STATIC_TIMER (blit_sub_buffer_timer,
"Redrawing", /* parent */
"glXCopySubBufferMESA",
"The time spent blocked by glXCopySubBufferMESA",
"glx_blit_sub_buffer",
"The time spent in _glx_blit_sub_buffer",
0 /* no application private data */);
backend = clutter_get_default_backend ();
@ -561,7 +561,7 @@ clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer);
if (backend_glx->copy_sub_buffer &&
if (backend_glx->can_blit_sub_buffer &&
/* NB: a degenerate redraw clip width == full stage redraw */
(stage_glx->bounding_redraw_clip.width != 0) &&
G_LIKELY (!(clutter_paint_debug_flags &
@ -589,7 +589,7 @@ clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
glx_wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
/* push on the screen */
if (backend_glx->copy_sub_buffer &&
if (backend_glx->can_blit_sub_buffer &&
/* NB: a degenerate redraw clip width == full stage redraw */
(stage_glx->bounding_redraw_clip.width != 0) &&
G_LIKELY (!(clutter_paint_debug_flags &
@ -599,11 +599,9 @@ clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
ClutterGeometry copy_area;
CLUTTER_NOTE (BACKEND,
"glXCopySubBufferMESA (display: %p, "
"window: 0x%lx, "
"_glx_blit_sub_buffer (window: 0x%lx, "
"x: %d, y: %d, "
"width: %d, height: %d)",
backend_x11->xdpy,
(unsigned long) drawable,
stage_glx->bounding_redraw_clip.x,
stage_glx->bounding_redraw_clip.y,
@ -660,14 +658,14 @@ clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
copy_area.width = clip->width;
copy_area.height = clip->height;
CLUTTER_TIMER_START (_clutter_uprof_context, copy_sub_buffer_timer);
backend_glx->copy_sub_buffer (backend_x11->xdpy,
drawable,
copy_area.x,
copy_area.y,
copy_area.width,
copy_area.height);
CLUTTER_TIMER_STOP (_clutter_uprof_context, copy_sub_buffer_timer);
CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer);
_clutter_backend_glx_blit_sub_buffer (backend_glx,
drawable,
copy_area.x,
copy_area.y,
copy_area.width,
copy_area.height);
CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer);
}
else
{