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.
This commit is contained in:
parent
9950d08ab7
commit
e4f3a2d77a
5
Makefile
5
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
|
||||
|
|
171
src/common.h
171
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 <X11/extensions/shape.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/Xdbe.h>
|
||||
#ifdef CONFIG_XSYNC
|
||||
#include <X11/extensions/sync.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_XINERAMA
|
||||
#include <X11/extensions/Xinerama.h>
|
||||
|
@ -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
|
||||
*/
|
||||
///@{
|
||||
|
|
125
src/compton.c
125
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);
|
||||
|
|
|
@ -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 <code>struct _win</code>.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
|
127
src/opengl.c
127
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue