diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index 62185ba80..c184ab25c 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -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) { diff --git a/clutter/glx/clutter-backend-glx.h b/clutter/glx/clutter-backend-glx.h index feb8d4f3e..fd111ff52 100644 --- a/clutter/glx/clutter-backend-glx.h +++ b/clutter/glx/clutter-backend-glx.h @@ -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__ */ diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index 6ae70bd76..783b09fa4 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -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 {