From e4f3a2d77a91ce806347f2b213275a57abeb7fe9 Mon Sep 17 00:00:00 2001 From: Richard Grenville Date: Mon, 17 Mar 2014 23:25:34 +0800 Subject: [PATCH] Bug fix #181: Add --xrender-sync{,-fence} - Add --xrender-sync{,-fence} to deal with redraw lag issue on GLX backend. --xrender-sync-fence requires a sufficiently new xorg-server and libXext. NO_XSYNC=1 may be used to disable it at compile time. Thanks to tchebb for reporting and everybody else for testing. (#181) - A bit code clean-up. Replace a few XSync() with XFlush() to minimize the latency. --- Makefile | 5 ++ src/common.h | 171 +++++++++++++++++++++++++++++++++++++++++++++++++- src/compton.c | 125 +++++++++++++++++++++++++++--------- src/compton.h | 11 +++- src/opengl.c | 127 ++++++++++++++++++++++++++++++------- src/opengl.h | 2 + 6 files changed, 387 insertions(+), 54 deletions(-) diff --git a/Makefile b/Makefile index 701308b6..9eb5b7e5 100644 --- a/Makefile +++ b/Makefile @@ -73,6 +73,11 @@ ifeq "$(NO_DBUS)" "" OBJS += dbus.o endif +# ==== D-Bus ==== +ifeq "$(NO_XSYNC)" "" + CFG += -DCONFIG_XSYNC +endif + # ==== C2 ==== ifeq "$(NO_C2)" "" CFG += -DCONFIG_C2 diff --git a/src/common.h b/src/common.h index e87651c9..d243dc07 100644 --- a/src/common.h +++ b/src/common.h @@ -55,11 +55,19 @@ // #define CONFIG_DBUS 1 // Whether to enable condition support. // #define CONFIG_C2 1 +// Whether to enable X Sync support. +// #define CONFIG_XSYNC 1 +// Whether to enable GLX Sync support. +// #define CONFIG_GLX_XSYNC 1 #if !defined(CONFIG_C2) && defined(DEBUG_C2) #error Cannot enable c2 debugging without c2 support. #endif +#if (!defined(CONFIG_XSYNC) || !defined(CONFIG_VSYNC_OPENGL)) && defined(CONFIG_GLX_SYNC) +#error Cannot enable GL sync without X Sync / OpenGL support. +#endif + #ifndef COMPTON_VERSION #define COMPTON_VERSION "unknown" #endif @@ -89,6 +97,9 @@ #include #include #include +#ifdef CONFIG_XSYNC +#include +#endif #ifdef CONFIG_XINERAMA #include @@ -338,6 +349,16 @@ enum { typedef struct _glx_texture glx_texture_t; #ifdef CONFIG_VSYNC_OPENGL +#ifdef DEBUG_GLX_DEBUG_CONTEXT +typedef GLXContext (*f_glXCreateContextAttribsARB) (Display *dpy, + GLXFBConfig config, GLXContext share_context, Bool direct, + const int *attrib_list); +typedef void (*GLDEBUGPROC) (GLenum source, GLenum type, + GLuint id, GLenum severity, GLsizei length, const GLchar* message, + GLvoid* userParam); +typedef void (*f_DebugMessageCallback) (GLDEBUGPROC, void *userParam); +#endif + typedef int (*f_WaitVideoSync) (int, int, unsigned *); typedef int (*f_GetVideoSync) (unsigned *); @@ -352,6 +373,47 @@ typedef void (*f_ReleaseTexImageEXT) (Display *display, GLXDrawable drawable, in typedef void (*f_CopySubBuffer) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); +#ifdef CONFIG_GLX_SYNC +// Looks like duplicate typedef of the same type is safe? +typedef int64_t GLint64; +typedef uint64_t GLuint64; +typedef struct __GLsync *GLsync; + +#ifndef GL_SYNC_FLUSH_COMMANDS_BIT +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#endif + +#ifndef GL_TIMEOUT_IGNORED +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#endif + +#ifndef GL_ALREADY_SIGNALED +#define GL_ALREADY_SIGNALED 0x911A +#endif + +#ifndef GL_TIMEOUT_EXPIRED +#define GL_TIMEOUT_EXPIRED 0x911B +#endif + +#ifndef GL_CONDITION_SATISFIED +#define GL_CONDITION_SATISFIED 0x911C +#endif + +#ifndef GL_WAIT_FAILED +#define GL_WAIT_FAILED 0x911D +#endif + +typedef GLsync (*f_FenceSync) (GLenum condition, GLbitfield flags); +typedef GLboolean (*f_IsSync) (GLsync sync); +typedef void (*f_DeleteSync) (GLsync sync); +typedef GLenum (*f_ClientWaitSync) (GLsync sync, GLbitfield flags, + GLuint64 timeout); +typedef void (*f_WaitSync) (GLsync sync, GLbitfield flags, + GLuint64 timeout); +typedef GLsync (*f_ImportSyncEXT) (GLenum external_sync_type, + GLintptr external_sync, GLbitfield flags); +#endif + #ifdef DEBUG_GLX_MARK typedef void (*f_StringMarkerGREMEDY) (GLsizei len, const void *string); typedef void (*f_FrameTerminatorGREMEDY) (void); @@ -438,7 +500,7 @@ struct _win; typedef struct _c2_lptr c2_lptr_t; /// Structure representing all options. -typedef struct { +typedef struct _options_t { // === General === /// The configuration file we used. char *config_file; @@ -451,6 +513,11 @@ typedef struct { char *display_repr; /// The backend in use. enum backend backend; + /// Whether to sync X drawing to avoid certain delay issues with + /// GLX backend. + bool xrender_sync; + /// Whether to sync X drawing with X Sync fence. + bool xrender_sync_fence; /// Whether to avoid using stencil buffer under GLX backend. Might be /// unsafe. bool glx_no_stencil; @@ -617,7 +684,7 @@ typedef struct { } options_t; /// Structure containing all necessary data for a compton session. -typedef struct { +typedef struct _session_t { // === Display related === /// Display in use. Display *dpy; @@ -650,6 +717,9 @@ typedef struct { Picture tgt_picture; /// Temporary buffer to paint to before sending to display. paint_t tgt_buffer; +#ifdef CONFIG_XSYNC + XSyncFence tgt_buffer_fence; +#endif /// DBE back buffer for root window. Used in DBE painting mode. XdbeBackBuffer root_dbe; /// Window ID of the window we register as a symbol. @@ -783,6 +853,20 @@ typedef struct { f_ReleaseTexImageEXT glXReleaseTexImageProc; /// Pointer to glXCopySubBufferMESA function. f_CopySubBuffer glXCopySubBufferProc; +#ifdef CONFIG_GLX_SYNC + /// Pointer to the glFenceSync() function. + f_FenceSync glFenceSyncProc; + /// Pointer to the glIsSync() function. + f_IsSync glIsSyncProc; + /// Pointer to the glDeleteSync() function. + f_DeleteSync glDeleteSyncProc; + /// Pointer to the glClientWaitSync() function. + f_ClientWaitSync glClientWaitSyncProc; + /// Pointer to the glWaitSync() function. + f_WaitSync glWaitSyncProc; + /// Pointer to the glImportSyncEXT() function. + f_ImportSyncEXT glImportSyncEXT; +#endif #ifdef DEBUG_GLX_MARK /// Pointer to StringMarkerGREMEDY function. f_StringMarkerGREMEDY glStringMarkerGREMEDY; @@ -849,6 +933,14 @@ typedef struct { XserverRegion *xinerama_scr_regs; /// Number of Xinerama screens. int xinerama_nscrs; +#endif +#ifdef CONFIG_XSYNC + /// Whether X Sync extension exists. + bool xsync_exists; + /// Event base number for X Sync extension. + int xsync_event; + /// Error base number for X Sync extension. + int xsync_error; #endif /// Whether X Render convolution filter exists. bool xrfilter_convolution_exists; @@ -915,6 +1007,10 @@ typedef struct _win { winmode_t mode; /// Whether the window has been damaged at least once. bool damaged; +#ifdef CONFIG_XSYNC + /// X Sync fence of drawable. + XSyncFence fence; +#endif /// Whether the window was damaged after last paint. bool pixmap_damaged; /// Damage of the window. @@ -1802,6 +1898,20 @@ free_all_damage_last(session_t *ps) { free_region(ps, &ps->all_damage_last[i]); } +#ifdef CONFIG_XSYNC +/** + * Free a XSync fence. + */ +static inline void +free_fence(session_t *ps, XSyncFence *pfence) { + if (*pfence) + XSyncDestroyFence(ps->dpy, *pfence); + *pfence = None; +} +#else +#define free_fence(ps, pfence) ((void) 0) +#endif + /** * Crop a rectangle by another rectangle. * @@ -1927,6 +2037,11 @@ vsync_deinit(session_t *ps); */ ///@{ +#ifdef CONFIG_GLX_SYNC +void +xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence); +#endif + bool glx_init(session_t *ps, bool need_render); @@ -2096,6 +2211,58 @@ glx_mark_frame(session_t *ps) { ///@} +#ifdef CONFIG_XSYNC +#define xr_sync(ps, d, pfence) xr_sync_(ps, d, pfence) +#else +#define xr_sync(ps, d, pfence) xr_sync_(ps, d) +#endif + +/** + * Synchronizes a X Render drawable to ensure all pending painting requests + * are completed. + */ +static inline void +xr_sync_(session_t *ps, Drawable d +#ifdef CONFIG_XSYNC + , XSyncFence *pfence +#endif + ) { + if (!ps->o.xrender_sync) + return; + +#ifdef CONFIG_XSYNC + if (ps->o.xrender_sync_fence && ps->xsync_exists) { + // TODO: If everybody just follows the rules stated in X Sync prototype, + // we need only one fence per screen, but let's stay a bit cautious right + // now + XSyncFence tmp_fence = None; + if (!pfence) + pfence = &tmp_fence; + assert(pfence); + if (!*pfence) + *pfence = XSyncCreateFence(ps->dpy, d, False); + if (*pfence) { + Bool triggered = False; + // The fence may fail to be created (e.g. because of died drawable) + assert(!XSyncQueryFence(ps->dpy, *pfence, &triggered) || !triggered); + XSyncTriggerFence(ps->dpy, *pfence); + XSyncAwaitFence(ps->dpy, pfence, 1); + assert(!XSyncQueryFence(ps->dpy, *pfence, &triggered) || triggered); + } + else { + printf_errf("(%#010lx): Failed to create X Sync fence.", d); + } + free_fence(ps, &tmp_fence); + if (*pfence) + XSyncResetFence(ps->dpy, *pfence); + } +#endif + XSync(ps->dpy, False); +#ifdef CONFIG_GLX_SYNC + xr_glx_sync(ps, d, pfence); +#endif +} + /** @name DBus handling */ ///@{ diff --git a/src/compton.c b/src/compton.c index 645aa5c5..1efb05d6 100644 --- a/src/compton.c +++ b/src/compton.c @@ -489,6 +489,9 @@ win_build_shadow(session_t *ps, win *w, double opacity) { w->shadow_paint.pixmap = shadow_pixmap_argb; w->shadow_paint.pict = shadow_picture_argb; + // Sync it once and only once + xr_sync(ps, w->shadow_paint.pixmap, NULL); + bool success = paint_bind_tex(ps, &w->shadow_paint, shadow_image->width, shadow_image->height, 32, true); XFreeGC(ps->dpy, gc); @@ -1513,12 +1516,16 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint, if (!w->paint.pixmap && ps->has_name_pixmap) { set_ignore_next(ps); w->paint.pixmap = XCompositeNameWindowPixmap(ps->dpy, w->id); + if (w->paint.pixmap) + free_fence(ps, &w->fence); } + + Drawable draw = w->paint.pixmap; + if (!draw) + draw = w->id; + // XRender: Build picture if (bkend_use_xrender(ps) && !w->paint.pict) { - Drawable draw = w->paint.pixmap; - if (!draw) - draw = w->id; { XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors, @@ -1528,6 +1535,10 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint, CPSubwindowMode, &pa); } } + + if (IsViewable == w->a.map_state) + xr_sync(ps, draw, &w->fence); + // GLX: Build texture // Let glx_bind_pixmap() determine pixmap size, because if the user // is resizing windows, the width and height we get may not be up-to-date, @@ -1948,11 +1959,13 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t else glFlush(); glXWaitX(); + assert(ps->tgt_buffer.pixmap); + xr_sync(ps, ps->tgt_buffer.pixmap, &ps->tgt_buffer_fence); paint_bind_tex_real(ps, &ps->tgt_buffer, ps->root_width, ps->root_height, ps->depth, !ps->o.glx_no_rebind_pixmap); // See #163 - XSync(ps->dpy, False); + xr_sync(ps, ps->tgt_buffer.pixmap, &ps->tgt_buffer_fence); if (ps->o.vsync_use_glfinish) glFinish(); else @@ -2116,7 +2129,7 @@ map_win(session_t *ps, Window id) { } // Make sure the XSelectInput() requests are sent - XSync(ps->dpy, False); + XFlush(ps->dpy); // Update window mode here to check for ARGB windows win_determine_mode(ps, w); @@ -2205,7 +2218,7 @@ finish_unmap_win(session_t *ps, win *w) { w->extents = None; } - free_paint(ps, &w->paint); + free_wpaint(ps, w); free_region(ps, &w->border_size); free_paint(ps, &w->shadow_paint); } @@ -2219,6 +2232,11 @@ static void unmap_win(session_t *ps, win *w) { if (!w || IsUnmapped == w->a.map_state) return; + // One last synchronization + if (w->paint.pixmap) + xr_sync(ps, w->paint.pixmap, &w->fence); + free_fence(ps, &w->fence); + // Set focus out win_set_focused(ps, w, false); @@ -2654,7 +2672,7 @@ win_mark_client(session_t *ps, win *w, Window client) { determine_evmask(ps, client, WIN_EVMODE_CLIENT)); // Make sure the XSelectInput() requests are sent - XSync(ps->dpy, False); + XFlush(ps->dpy); win_upd_wintype(ps, w); @@ -3037,7 +3055,7 @@ configure_win(session_t *ps, XConfigureEvent *ce) { if (w->a.width != ce->width || w->a.height != ce->height || w->a.border_width != ce->border_width) - free_paint(ps, &w->paint); + free_wpaint(ps, w); if (w->a.width != ce->width || w->a.height != ce->height || w->a.border_width != ce->border_width) { @@ -3097,7 +3115,7 @@ finish_destroy_win(session_t *ps, Window id) { for (prev = &ps->list; (w = *prev); prev = &w->next) { if (w->id == id && w->destroyed) { #ifdef DEBUG_EVENTS - printf_dbgf("(%#010lx \"%s\"): %p\n", id, w->name, w); + printf_dbgf("(%#010lx \"%s\"): %p\n", id, w->name, w); #endif finish_unmap_win(ps, w); @@ -3188,10 +3206,10 @@ damage_win(session_t *ps, XDamageNotifyEvent *de) { * Xlib error handler function. */ static int -error(Display __attribute__((unused)) *dpy, XErrorEvent *ev) { +xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) { session_t * const ps = ps_g; - int o; + int o = 0; const char *name = "Unknown"; if (should_ignore(ps, ev->serial)) { @@ -3240,6 +3258,17 @@ error(Display __attribute__((unused)) *dpy, XErrorEvent *ev) { } #endif +#ifdef CONFIG_XSYNC + if (ps->xsync_exists) { + o = ev->error_code - ps->xsync_error; + switch (o) { + CASESTRRET2(XSyncBadCounter); + CASESTRRET2(XSyncBadAlarm); + CASESTRRET2(XSyncBadFence); + } + } +#endif + switch (ev->error_code) { CASESTRRET2(BadAccess); CASESTRRET2(BadAlloc); @@ -3771,18 +3800,27 @@ ev_name(session_t *ps, XEvent *ev) { CASESTRRET(Expose); CASESTRRET(PropertyNotify); CASESTRRET(ClientMessage); - default: - if (isdamagenotify(ps, ev)) - return "Damage"; - - if (ps->shape_exists && ev->type == ps->shape_event) { - return "ShapeNotify"; - } - - sprintf(buf, "Event %d", ev->type); - - return buf; } + + if (isdamagenotify(ps, ev)) + return "Damage"; + + if (ps->shape_exists && ev->type == ps->shape_event) + return "ShapeNotify"; + +#ifdef CONFIG_XSYNC + if (ps->xsync_exists) { + int o = ev->type - ps->xsync_event; + switch (o) { + CASESTRRET(CounterNotify); + CASESTRRET(AlarmNotify); + } + } +#endif + + sprintf(buf, "Event %d", ev->type); + + return buf; } static Window @@ -5464,6 +5502,8 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { { "unredir-if-possible-delay", required_argument, NULL, 309 }, { "write-pid-path", required_argument, NULL, 310 }, { "vsync-use-glfinish", no_argument, NULL, 311 }, + { "xrender-sync", no_argument, NULL, 312 }, + { "xrender-sync-fence", no_argument, NULL, 313 }, // Must terminate with a NULL entry { NULL, 0, NULL, 0 }, }; @@ -5714,6 +5754,8 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { ps->o.write_pid_path = mstrcpy(optarg); break; P_CASEBOOL(311, vsync_use_glfinish); + P_CASEBOOL(312, xrender_sync); + P_CASEBOOL(313, xrender_sync_fence); default: usage(1); break; @@ -5761,6 +5803,9 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { if (ps->o.blur_background_frame) ps->o.blur_background = true; + if (ps->o.xrender_sync_fence) + ps->o.xrender_sync = true; + // Other variables determined by options // Determine whether we need to track focus changes @@ -6478,7 +6523,7 @@ redir_stop(session_t *ps) { // If we don't destroy them here, looks like the resources are just // kept inaccessible somehow for (win *w = ps->list; w; w = w->next) - free_paint(ps, &w->paint); + free_wpaint(ps, w); XCompositeUnredirectSubwindows(ps->dpy, ps->root, CompositeRedirectManual); // Unmap overlay window @@ -6852,7 +6897,7 @@ session_init(session_t *ps_old, int argc, char **argv) { } } - XSetErrorHandler(error); + XSetErrorHandler(xerror); if (ps->o.synchronize) { XSynchronize(ps->dpy, 1); } @@ -6907,11 +6952,6 @@ session_init(session_t *ps_old, int argc, char **argv) { exit(1); } - // Query X Shape - if (XShapeQueryExtension(ps->dpy, &ps->shape_event, &ps->shape_error)) { - ps->shape_exists = true; - } - // Build a safe representation of display name { char *display_repr = DisplayString(ps->dpy); @@ -6936,6 +6976,32 @@ session_init(session_t *ps_old, int argc, char **argv) { // Second pass get_cfg(ps, argc, argv, false); + // Query X Shape + if (XShapeQueryExtension(ps->dpy, &ps->shape_event, &ps->shape_error)) { + ps->shape_exists = true; + } + + if (ps->o.xrender_sync_fence) { +#ifdef CONFIG_XSYNC + // Query X Sync + if (XSyncQueryExtension(ps->dpy, &ps->xsync_event, &ps->xsync_error)) { + // TODO: Fencing may require version >= 3.0? + int major_version_return = 0, minor_version_return = 0; + if (XSyncInitialize(ps->dpy, &major_version_return, &minor_version_return)) + ps->xsync_exists = true; + } + if (!ps->xsync_exists) { + printf_errf("(): X Sync extension not found. No X Sync fence sync is " + "possible."); + exit(1); + } +#else + printf_errf("(): X Sync support not compiled in. --xrender-sync-fence" + "can't work."); + exit(1); +#endif + } + // Query X RandR if ((ps->o.sw_opti && !ps->o.refresh_rate) || ps->o.xinerama_shadow_crop) { if (XRRQueryExtension(ps->dpy, &ps->randr_event, &ps->randr_error)) @@ -7219,6 +7285,7 @@ session_destroy(session_t *ps) { ps->tgt_picture = None; else free_picture(ps, &ps->tgt_picture); + free_fence(ps, &ps->tgt_buffer_fence); free_picture(ps, &ps->root_picture); free_paint(ps, &ps->tgt_buffer); diff --git a/src/compton.h b/src/compton.h index 22ee195d..a4e838ef 100644 --- a/src/compton.h +++ b/src/compton.h @@ -275,6 +275,15 @@ free_paint(session_t *ps, paint_t *ppaint) { free_pixmap(ps, &ppaint->pixmap); } +/** + * Free w->paint. + */ +static inline void +free_wpaint(session_t *ps, win *w) { + free_paint(ps, &w->paint); + free_fence(ps, &w->fence); +} + /** * Destroy all resources in a struct _win. */ @@ -883,7 +892,7 @@ static void damage_win(session_t *ps, XDamageNotifyEvent *de); static int -error(Display *dpy, XErrorEvent *ev); +xerror(Display *dpy, XErrorEvent *ev); static void expose_root(session_t *ps, XRectangle *rects, int nrects); diff --git a/src/opengl.c b/src/opengl.c index d557aea6..39aac33c 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -10,6 +10,50 @@ #include "opengl.h" +#ifdef CONFIG_GLX_SYNC +void +xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence) { + if (*pfence) { + // GLsync sync = ps->glFenceSyncProc(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + GLsync sync = ps->glImportSyncEXT(GL_SYNC_X11_FENCE_EXT, *pfence, 0); + XSync(ps->dpy, False); + glx_check_err(ps); + /* GLenum ret = ps->glClientWaitSyncProc(sync, GL_SYNC_FLUSH_COMMANDS_BIT, + 1000); + assert(GL_CONDITION_SATISFIED == ret); */ + ps->glWaitSyncProc(sync, 0, GL_TIMEOUT_IGNORED); + // ps->glDeleteSyncProc(sync); + // XSyncResetFence(ps->dpy, *pfence); + } + glx_check_err(ps); +} +#endif + +static inline GLXFBConfig +get_fbconfig_from_visualinfo(session_t *ps, const XVisualInfo *visualinfo) { + int nelements = 0; + GLXFBConfig *fbconfigs = glXGetFBConfigs(ps->dpy, visualinfo->screen, + &nelements); + for (int i = 0; i < nelements; ++i) { + int visual_id = 0; + if (Success == glXGetFBConfigAttrib(ps->dpy, fbconfigs[i], GLX_VISUAL_ID, &visual_id) + && visual_id == visualinfo->visualid) + return fbconfigs[i]; + } + + return NULL; +} + +#ifdef DEBUG_GLX_DEBUG_CONTEXT +static void +glx_debug_msg_callback(GLenum source, GLenum type, + GLuint id, GLenum severity, GLsizei length, const GLchar *message, + GLvoid *userParam) { + printf_dbgf("(): source 0x%04X, type 0x%04X, id %u, severity 0x%0X, \"%s\"\n", + source, type, id, severity, message); +} +#endif + /** * Initialize OpenGL. */ @@ -56,7 +100,33 @@ glx_init(session_t *ps, bool need_render) { if (!ps->glx_context) { // Get GLX context +#ifndef DEBUG_GLX_DEBUG_CONTEXT ps->glx_context = glXCreateContext(ps->dpy, pvis, None, GL_TRUE); +#else + { + GLXFBConfig fbconfig = get_fbconfig_from_visualinfo(ps, pvis); + if (!fbconfig) { + printf_errf("(): Failed to get GLXFBConfig for root visual %#lx.", + pvis->visualid); + goto glx_init_end; + } + + f_glXCreateContextAttribsARB p_glXCreateContextAttribsARB = + (f_glXCreateContextAttribsARB) + glXGetProcAddress((const GLubyte *) "glXCreateContextAttribsARB"); + if (!p_glXCreateContextAttribsARB) { + printf_errf("(): Failed to get glXCreateContextAttribsARB()."); + goto glx_init_end; + } + + static const int attrib_list[] = { + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, + None + }; + ps->glx_context = p_glXCreateContextAttribsARB(ps->dpy, fbconfig, NULL, + GL_TRUE, attrib_list); + } +#endif if (!ps->glx_context) { printf_errf("(): Failed to get GLX context."); @@ -68,6 +138,20 @@ glx_init(session_t *ps, bool need_render) { printf_errf("(): Failed to attach GLX context."); goto glx_init_end; } + +#ifdef DEBUG_GLX_DEBUG_CONTEXT + { + f_DebugMessageCallback p_DebugMessageCallback = + (f_DebugMessageCallback) + glXGetProcAddress((const GLubyte *) "glDebugMessageCallback"); + if (!p_DebugMessageCallback) { + printf_errf("(): Failed to get glDebugMessageCallback(0."); + goto glx_init_end; + } + p_DebugMessageCallback(glx_debug_msg_callback, ps); + } +#endif + } // Ensure we have a stencil buffer. X Fixes does not guarantee rectangles @@ -114,6 +198,27 @@ glx_init(session_t *ps, bool need_render) { goto glx_init_end; } } + +#ifdef CONFIG_GLX_SYNC + ps->glFenceSyncProc = (f_FenceSync) + glXGetProcAddress((const GLubyte *) "glFenceSync"); + ps->glIsSyncProc = (f_IsSync) + glXGetProcAddress((const GLubyte *) "glIsSync"); + ps->glDeleteSyncProc = (f_DeleteSync) + glXGetProcAddress((const GLubyte *) "glDeleteSync"); + ps->glClientWaitSyncProc = (f_ClientWaitSync) + glXGetProcAddress((const GLubyte *) "glClientWaitSync"); + ps->glWaitSyncProc = (f_WaitSync) + glXGetProcAddress((const GLubyte *) "glWaitSync"); + ps->glImportSyncEXT = (f_ImportSyncEXT) + glXGetProcAddress((const GLubyte *) "glImportSyncEXT"); + if (!ps->glFenceSyncProc || !ps->glIsSyncProc || !ps->glDeleteSyncProc + || !ps->glClientWaitSyncProc || !ps->glWaitSyncProc + || !ps->glImportSyncEXT) { + printf_errf("(): Failed to acquire GLX sync functions."); + goto glx_init_end; + } +#endif } // Acquire FBConfigs @@ -344,9 +449,7 @@ glx_init_blur(session_t *ps) { } -#ifdef DEBUG_GLX_ERR glx_check_err(ps); -#endif return true; #else @@ -655,9 +758,7 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, glBindTexture(ptex->target, 0); glDisable(ptex->target); -#ifdef DEBUG_GLX_ERR glx_check_err(ps); -#endif return true; } @@ -680,9 +781,7 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) { ptex->glpixmap = 0; } -#ifdef DEBUG_GLX_ERR glx_check_err(ps); -#endif } /** @@ -803,9 +902,7 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) { glx_render_color(ps, 0, 0, ps->root_width, ps->root_height, 0, *preg, NULL); #endif -#ifdef DEBUG_GLX_ERR glx_check_err(ps); -#endif } /** @@ -886,9 +983,7 @@ glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg) { cxfree(rects_free); -#ifdef DEBUG_GLX_ERR glx_check_err(ps); -#endif } #define P_PAINTREG_START() \ @@ -1174,9 +1269,7 @@ glx_blur_dst_end: free_glx_bc(ps, pbc); } -#ifdef DEBUG_GLX_ERR glx_check_err(ps); -#endif return ret; } @@ -1212,9 +1305,7 @@ glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z, glColor4f(0.0f, 0.0f, 0.0f, 0.0f); glDisable(GL_BLEND); -#ifdef DEBUG_GLX_ERR glx_check_err(ps); -#endif return true; } @@ -1412,9 +1503,7 @@ glx_render(session_t *ps, const glx_texture_t *ptex, glActiveTexture(GL_TEXTURE0); } -#ifdef DEBUG_GLX_ERR glx_check_err(ps); -#endif return true; } @@ -1452,9 +1541,7 @@ glx_render_color(session_t *ps, int dx, int dy, int width, int height, int z, } glColor4f(0.0f, 0.0f, 0.0f, 0.0f); -#ifdef DEBUG_GLX_ERR glx_check_err(ps); -#endif } /** @@ -1492,9 +1579,7 @@ glx_render_dots(session_t *ps, int dx, int dy, int width, int height, int z, } glColor4f(0.0f, 0.0f, 0.0f, 0.0f); -#ifdef DEBUG_GLX_ERR glx_check_err(ps); -#endif } /** @@ -1524,9 +1609,7 @@ glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg) { } } -#ifdef DEBUG_GLX_ERR glx_check_err(ps); -#endif cxfree(rects); } diff --git a/src/opengl.h b/src/opengl.h index 564b7e20..8628e36d 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -59,6 +59,8 @@ glx_check_err_(session_t *ps, const char *func, int line) { } #define glx_check_err(ps) glx_check_err_(ps, __func__, __LINE__) +#else +#define glx_check_err(ps) ((void) 0) #endif /**