backend-glx: Make sure to throttle sub region blits
Neither glXCopySubBuffer or glBlitFramebuffer are integrated with the swap interval of a framebuffer so that means when we do partial stage updates (as Mutter does in response to window damage) then the blits aren't throttled which means applications that throw lots of damage events at the compositor can effectively cause Clutter to run flat out taking up all the system resources issuing more blits than can even be seen. This patch now makes sure we use the GLX_SGI_video_sync or a DRM_VBLANK_RELATIVE ioctl to throttle blits to the vblank frequency as we do when using glXSwapBuffers.
This commit is contained in:
parent
630a2c5edc
commit
f37de23dec
@ -245,6 +245,20 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
|
||||
|
||||
gl_extensions = (const gchar *)glGetString (GL_EXTENSIONS);
|
||||
|
||||
/* When using glBlitFramebuffer or glXCopySubBufferMESA for sub stage
|
||||
* redraws, we cannot rely on glXSwapIntervalSGI to throttle the blits
|
||||
* so we need to resort to manually synchronizing with the vblank so we
|
||||
* always check for the video_sync extension...
|
||||
*/
|
||||
if (_cogl_check_extension ("GLX_SGI_video_sync", glx_extensions))
|
||||
{
|
||||
backend_glx->get_video_sync =
|
||||
(GetVideoSyncProc) cogl_get_proc_address ("glXGetVideoSyncSGI");
|
||||
|
||||
backend_glx->wait_video_sync =
|
||||
(WaitVideoSyncProc) cogl_get_proc_address ("glXWaitVideoSyncSGI");
|
||||
}
|
||||
|
||||
use_dri = check_vblank_env ("dri");
|
||||
|
||||
/* First check for explicit disabling or it set elsewhere (eg NVIDIA) */
|
||||
@ -315,12 +329,6 @@ clutter_backend_glx_get_features (ClutterBackend *backend)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "attempting glXGetVideoSyncSGI vblank setup");
|
||||
|
||||
backend_glx->get_video_sync =
|
||||
(GetVideoSyncProc) cogl_get_proc_address ("glXGetVideoSyncSGI");
|
||||
|
||||
backend_glx->wait_video_sync =
|
||||
(WaitVideoSyncProc) cogl_get_proc_address ("glXWaitVideoSyncSGI");
|
||||
|
||||
if ((backend_glx->get_video_sync != NULL) &&
|
||||
(backend_glx->wait_video_sync != NULL))
|
||||
{
|
||||
|
@ -468,7 +468,7 @@ drm_wait_vblank(int fd, drm_wait_vblank_t *vbl)
|
||||
#endif /* __linux__ */
|
||||
|
||||
static void
|
||||
glx_wait_for_vblank (ClutterBackendGLX *backend_glx)
|
||||
wait_for_vblank (ClutterBackendGLX *backend_glx)
|
||||
{
|
||||
/* If we are going to wait for VBLANK manually, we not only need
|
||||
* to flush out pending drawing to the GPU before we sleep, we
|
||||
@ -486,46 +486,35 @@ glx_wait_for_vblank (ClutterBackendGLX *backend_glx)
|
||||
* happen when we use GLX_SWAP and let the driver do the right thing
|
||||
*/
|
||||
|
||||
switch (backend_glx->vblank_type)
|
||||
if (backend_glx->vblank_type == CLUTTER_VBLANK_NONE)
|
||||
return;
|
||||
|
||||
if (backend_glx->wait_video_sync)
|
||||
{
|
||||
case CLUTTER_VBLANK_GLX_SWAP:
|
||||
CLUTTER_NOTE (BACKEND, "Waiting for vblank (swap)");
|
||||
break;
|
||||
unsigned int retraceCount;
|
||||
|
||||
case CLUTTER_VBLANK_GLX:
|
||||
{
|
||||
unsigned int retraceCount;
|
||||
glFinish ();
|
||||
|
||||
glFinish ();
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Waiting for vblank (wait_video_sync)");
|
||||
backend_glx->get_video_sync (&retraceCount);
|
||||
backend_glx->wait_video_sync (2,
|
||||
(retraceCount + 1) % 2,
|
||||
&retraceCount);
|
||||
}
|
||||
break;
|
||||
|
||||
case CLUTTER_VBLANK_DRI:
|
||||
#ifdef __linux__
|
||||
{
|
||||
drm_wait_vblank_t blank;
|
||||
|
||||
glFinish ();
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Waiting for vblank (drm)");
|
||||
blank.request.type = DRM_VBLANK_RELATIVE;
|
||||
blank.request.sequence = 1;
|
||||
blank.request.signal = 0;
|
||||
drm_wait_vblank (backend_glx->dri_fd, &blank);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case CLUTTER_VBLANK_NONE:
|
||||
default:
|
||||
break;
|
||||
CLUTTER_NOTE (BACKEND, "Waiting for vblank (wait_video_sync)");
|
||||
backend_glx->get_video_sync (&retraceCount);
|
||||
backend_glx->wait_video_sync (2,
|
||||
(retraceCount + 1) % 2,
|
||||
&retraceCount);
|
||||
}
|
||||
else
|
||||
#ifdef __linux__
|
||||
{
|
||||
drm_wait_vblank_t blank;
|
||||
|
||||
glFinish ();
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Waiting for vblank (drm)");
|
||||
blank.request.type = DRM_VBLANK_RELATIVE;
|
||||
blank.request.sequence = 1;
|
||||
blank.request.signal = 0;
|
||||
drm_wait_vblank (backend_glx->dri_fd, &blank);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -585,9 +574,6 @@ clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
|
||||
|
||||
drawable = stage_glx->glxwin ? stage_glx->glxwin : stage_x11->xwin;
|
||||
|
||||
/* wait for the next vblank */
|
||||
glx_wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
|
||||
|
||||
/* push on the screen */
|
||||
if (backend_glx->can_blit_sub_buffer &&
|
||||
/* NB: a degenerate redraw clip width == full stage redraw */
|
||||
@ -658,6 +644,12 @@ clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
|
||||
copy_area.width = clip->width;
|
||||
copy_area.height = clip->height;
|
||||
|
||||
/* glXCopySubBufferMESA and glBlitFramebuffer are not integrated with the
|
||||
* glXSwapIntervalSGI mechanism which we usually use to throttle the
|
||||
* Clutter framerate to the vertical refresh and so we have to manually
|
||||
* wait for the vblank period. */
|
||||
wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
|
||||
|
||||
CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer);
|
||||
_clutter_backend_glx_blit_sub_buffer (backend_glx,
|
||||
drawable,
|
||||
@ -679,6 +671,9 @@ clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
|
||||
if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
|
||||
stage_glx->pending_swaps++;
|
||||
|
||||
if (backend_glx->vblank_type != CLUTTER_VBLANK_GLX_SWAP)
|
||||
wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
|
||||
|
||||
CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer);
|
||||
glXSwapBuffers (backend_x11->xdpy, drawable);
|
||||
CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer);
|
||||
|
Loading…
Reference in New Issue
Block a user