Bug fix #7: Correct a possible issue in VSync
- I realized I might have fundamentally misunderstood VSync. This commit tries to fix the possible problem, or at least move the tearing line close to the top of the screen. - Software VSync is replaced by --sw-opti (software optimization), as I guess it isn't possible at all to do VSync without driver support. - Add "vsync" and "sw-opti" as configuration file options.
This commit is contained in:
parent
049621bed7
commit
66e615775b
|
@ -34,7 +34,9 @@ mark-ovredir-focused = true;
|
||||||
detect-rounded-corners = true;
|
detect-rounded-corners = true;
|
||||||
detect-client-opacity = false;
|
detect-client-opacity = false;
|
||||||
refresh-rate = 0;
|
refresh-rate = 0;
|
||||||
|
vsync = "none";
|
||||||
paint-on-overlay = true;
|
paint-on-overlay = true;
|
||||||
|
sw-opti = false;
|
||||||
|
|
||||||
# Window type settings
|
# Window type settings
|
||||||
wintypes:
|
wintypes:
|
||||||
|
|
214
src/compton.c
214
src/compton.c
|
@ -74,12 +74,11 @@ Bool reg_ignore_expire = False;
|
||||||
/// Window ID of the window we register as a symbol.
|
/// Window ID of the window we register as a symbol.
|
||||||
Window reg_win = 0;
|
Window reg_win = 0;
|
||||||
|
|
||||||
/// Currently used refresh rate. Used for Software VSync.
|
/// Currently used refresh rate. Used for sw_opti.
|
||||||
short refresh_rate = 0;
|
short refresh_rate = 0;
|
||||||
/// Interval between refresh in nanoseconds. Used for Software VSync.
|
/// Interval between refresh in nanoseconds. Used for sw_opti.
|
||||||
unsigned long refresh_intv = 0;
|
unsigned long refresh_intv = 0;
|
||||||
/// Nanosecond-level offset of the first painting.
|
/// Nanosecond-level offset of the first painting. Used for sw_opti.
|
||||||
/// Used for Software VSync.
|
|
||||||
long paint_tm_offset = 0;
|
long paint_tm_offset = 0;
|
||||||
|
|
||||||
#ifdef CONFIG_VSYNC_DRM
|
#ifdef CONFIG_VSYNC_DRM
|
||||||
|
@ -179,6 +178,7 @@ static options_t opts = {
|
||||||
.paint_on_overlay = False,
|
.paint_on_overlay = False,
|
||||||
|
|
||||||
.refresh_rate = 0,
|
.refresh_rate = 0,
|
||||||
|
.sw_opti = False,
|
||||||
.vsync = VSYNC_NONE,
|
.vsync = VSYNC_NONE,
|
||||||
.dbe = False,
|
.dbe = False,
|
||||||
|
|
||||||
|
@ -1568,6 +1568,10 @@ win_paint_win(Display *dpy, win *w, Picture tgt_buffer) {
|
||||||
|
|
||||||
static void
|
static void
|
||||||
paint_all(Display *dpy, XserverRegion region, win *t) {
|
paint_all(Display *dpy, XserverRegion region, win *t) {
|
||||||
|
#ifdef DEBUG_REPAINT
|
||||||
|
static struct timespec last_paint = { 0 };
|
||||||
|
#endif
|
||||||
|
|
||||||
win *w;
|
win *w;
|
||||||
XserverRegion reg_paint = None, reg_tmp = None, reg_tmp2 = None;
|
XserverRegion reg_paint = None, reg_tmp = None, reg_tmp2 = None;
|
||||||
|
|
||||||
|
@ -1616,7 +1620,6 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_REPAINT
|
#ifdef DEBUG_REPAINT
|
||||||
print_timestamp();
|
|
||||||
printf("paint:");
|
printf("paint:");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1700,7 +1703,6 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
|
||||||
|
|
||||||
#ifdef DEBUG_REPAINT
|
#ifdef DEBUG_REPAINT
|
||||||
printf("\n");
|
printf("\n");
|
||||||
fflush(stdout);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Free up all temporary regions
|
// Free up all temporary regions
|
||||||
|
@ -1708,6 +1710,9 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
|
||||||
XFixesDestroyRegion(dpy, reg_tmp);
|
XFixesDestroyRegion(dpy, reg_tmp);
|
||||||
XFixesDestroyRegion(dpy, reg_tmp2);
|
XFixesDestroyRegion(dpy, reg_tmp2);
|
||||||
|
|
||||||
|
// Wait for VBlank
|
||||||
|
vsync_wait();
|
||||||
|
|
||||||
// DBE painting mode, only need to swap the buffer
|
// DBE painting mode, only need to swap the buffer
|
||||||
if (opts.dbe) {
|
if (opts.dbe) {
|
||||||
XdbeSwapInfo swap_info = {
|
XdbeSwapInfo swap_info = {
|
||||||
|
@ -1725,6 +1730,20 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
|
||||||
tgt_picture, 0, 0, 0, 0,
|
tgt_picture, 0, 0, 0, 0,
|
||||||
0, 0, root_width, root_height);
|
0, 0, root_width, root_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XFlush(dpy);
|
||||||
|
|
||||||
|
#ifdef DEBUG_REPAINT
|
||||||
|
// It prints the timestamp in the wrong line, but...
|
||||||
|
print_timestamp();
|
||||||
|
struct timespec now = get_time_timespec();
|
||||||
|
struct timespec diff = { 0 };
|
||||||
|
timespec_subtract(&diff, &now, &last_paint);
|
||||||
|
printf("[ %5ld:%09ld ] ", diff.tv_sec, diff.tv_nsec);
|
||||||
|
last_paint = now;
|
||||||
|
fflush(stdout);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -3304,10 +3323,8 @@ usage(void) {
|
||||||
" Specify refresh rate of the screen. If not specified or 0, compton\n"
|
" Specify refresh rate of the screen. If not specified or 0, compton\n"
|
||||||
" will try detecting this with X RandR extension.\n"
|
" will try detecting this with X RandR extension.\n"
|
||||||
"--vsync vsync-method\n"
|
"--vsync vsync-method\n"
|
||||||
" Set VSync method. There are 4 VSync methods currently available:\n"
|
" Set VSync method. There are 2 VSync methods currently available:\n"
|
||||||
" none = No VSync\n"
|
" none = No VSync\n"
|
||||||
" sw = software VSync, basically limits compton to send a request\n"
|
|
||||||
" every 1 / refresh_rate second. Experimental.\n"
|
|
||||||
" drm = VSync with DRM_IOCTL_WAIT_VBLANK. May only work on some\n"
|
" drm = VSync with DRM_IOCTL_WAIT_VBLANK. May only work on some\n"
|
||||||
" drivers. Experimental.\n"
|
" drivers. Experimental.\n"
|
||||||
" opengl = Try to VSync with SGI_swap_control OpenGL extension. Only\n"
|
" opengl = Try to VSync with SGI_swap_control OpenGL extension. Only\n"
|
||||||
|
@ -3321,6 +3338,9 @@ usage(void) {
|
||||||
" (hopefully) eliminate tearing.\n"
|
" (hopefully) eliminate tearing.\n"
|
||||||
"--paint-on-overlay\n"
|
"--paint-on-overlay\n"
|
||||||
" Painting on X Composite overlay window.\n"
|
" Painting on X Composite overlay window.\n"
|
||||||
|
"--sw-opti\n"
|
||||||
|
" Limit compton to repaint at most once every 1 / refresh_rate\n"
|
||||||
|
" second to boost performance. Experimental.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Format of a condition:\n"
|
"Format of a condition:\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -3533,6 +3553,29 @@ open_config_file(char *cpath, char **ppath) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a VSync option argument.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
parse_vsync(const char *optarg) {
|
||||||
|
const static char * const vsync_str[] = {
|
||||||
|
"none", // VSYNC_NONE
|
||||||
|
"drm", // VSYNC_DRM
|
||||||
|
"opengl", // VSYNC_OPENGL
|
||||||
|
};
|
||||||
|
|
||||||
|
vsync_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < (sizeof(vsync_str) / sizeof(vsync_str[0])); ++i)
|
||||||
|
if (!strcasecmp(optarg, vsync_str[i])) {
|
||||||
|
opts.vsync = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((sizeof(vsync_str) / sizeof(vsync_str[0])) == i) {
|
||||||
|
fputs("Invalid --vsync argument. Ignored.\n", stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a configuration file from default location.
|
* Parse a configuration file from default location.
|
||||||
*/
|
*/
|
||||||
|
@ -3543,6 +3586,7 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) {
|
||||||
config_t cfg;
|
config_t cfg;
|
||||||
int ival = 0;
|
int ival = 0;
|
||||||
double dval = 0.0;
|
double dval = 0.0;
|
||||||
|
const char *sval = NULL;
|
||||||
|
|
||||||
f = open_config_file(cpath, &path);
|
f = open_config_file(cpath, &path);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
|
@ -3637,10 +3681,15 @@ parse_config(char *cpath, struct options_tmp *pcfgtmp) {
|
||||||
&opts.detect_client_opacity);
|
&opts.detect_client_opacity);
|
||||||
// --refresh-rate
|
// --refresh-rate
|
||||||
lcfg_lookup_int(&cfg, "refresh-rate", &opts.refresh_rate);
|
lcfg_lookup_int(&cfg, "refresh-rate", &opts.refresh_rate);
|
||||||
|
// --vsync
|
||||||
|
if (config_lookup_string(&cfg, "vsync", &sval))
|
||||||
|
parse_vsync(sval);
|
||||||
// --alpha-step
|
// --alpha-step
|
||||||
config_lookup_float(&cfg, "alpha-step", &opts.alpha_step);
|
config_lookup_float(&cfg, "alpha-step", &opts.alpha_step);
|
||||||
// --paint-on-overlay
|
// --paint-on-overlay
|
||||||
lcfg_lookup_bool(&cfg, "paint-on-overlay", &opts.paint_on_overlay);
|
lcfg_lookup_bool(&cfg, "paint-on-overlay", &opts.paint_on_overlay);
|
||||||
|
// --sw-opti
|
||||||
|
lcfg_lookup_bool(&cfg, "sw-opti", &opts.sw_opti);
|
||||||
// --shadow-exclude
|
// --shadow-exclude
|
||||||
{
|
{
|
||||||
config_setting_t *setting =
|
config_setting_t *setting =
|
||||||
|
@ -3709,15 +3758,10 @@ get_cfg(int argc, char *const *argv) {
|
||||||
{ "alpha-step", required_argument, NULL, 271 },
|
{ "alpha-step", required_argument, NULL, 271 },
|
||||||
{ "dbe", no_argument, NULL, 272 },
|
{ "dbe", no_argument, NULL, 272 },
|
||||||
{ "paint-on-overlay", no_argument, NULL, 273 },
|
{ "paint-on-overlay", no_argument, NULL, 273 },
|
||||||
|
{ "sw-opti", no_argument, NULL, 274 },
|
||||||
// Must terminate with a NULL entry
|
// Must terminate with a NULL entry
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
const static char * const vsync_str[] = {
|
|
||||||
"none", // VSYNC_NONE
|
|
||||||
"sw", // VSYNC_SW
|
|
||||||
"drm", // VSYNC_DRM
|
|
||||||
"opengl", // VSYNC_OPENGL
|
|
||||||
};
|
|
||||||
|
|
||||||
struct options_tmp cfgtmp = {
|
struct options_tmp cfgtmp = {
|
||||||
.no_dock_shadow = False,
|
.no_dock_shadow = False,
|
||||||
|
@ -3879,17 +3923,7 @@ get_cfg(int argc, char *const *argv) {
|
||||||
break;
|
break;
|
||||||
case 270:
|
case 270:
|
||||||
// --vsync
|
// --vsync
|
||||||
{
|
parse_vsync(optarg);
|
||||||
vsync_t i;
|
|
||||||
for (i = 0; i < (sizeof(vsync_str) / sizeof(vsync_str[0])); ++i)
|
|
||||||
if (!strcasecmp(optarg, vsync_str[i])) {
|
|
||||||
opts.vsync = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((sizeof(vsync_str) / sizeof(vsync_str[0])) == i) {
|
|
||||||
fputs("Invalid --vsync argument. Ignored.\n", stderr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 271:
|
case 271:
|
||||||
// --alpha-step
|
// --alpha-step
|
||||||
|
@ -3903,6 +3937,10 @@ get_cfg(int argc, char *const *argv) {
|
||||||
// --paint-on-overlay
|
// --paint-on-overlay
|
||||||
opts.paint_on_overlay = True;
|
opts.paint_on_overlay = True;
|
||||||
break;
|
break;
|
||||||
|
case 274:
|
||||||
|
// --sw-opti
|
||||||
|
opts.sw_opti = True;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
break;
|
break;
|
||||||
|
@ -4018,12 +4056,12 @@ update_refresh_rate(Display *dpy) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize software VSync.
|
* Initialize refresh-rated based software optimization.
|
||||||
*
|
*
|
||||||
* @return True for success, False otherwise
|
* @return True for success, False otherwise
|
||||||
*/
|
*/
|
||||||
static Bool
|
static Bool
|
||||||
vsync_sw_init(void) {
|
sw_opti_init(void) {
|
||||||
// Prepare refresh rate
|
// Prepare refresh rate
|
||||||
// Check if user provides one
|
// Check if user provides one
|
||||||
refresh_rate = opts.refresh_rate;
|
refresh_rate = opts.refresh_rate;
|
||||||
|
@ -4047,21 +4085,6 @@ vsync_sw_init(void) {
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current time in struct timespec.
|
|
||||||
*
|
|
||||||
* Note its starting time is unspecified.
|
|
||||||
*/
|
|
||||||
static inline struct timespec
|
|
||||||
get_time_timespec(void) {
|
|
||||||
struct timespec tm = { 0 };
|
|
||||||
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &tm);
|
|
||||||
|
|
||||||
// Return a time of all 0 if the call fails
|
|
||||||
return tm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the smaller number that is bigger than <code>dividend</code> and is
|
* Get the smaller number that is bigger than <code>dividend</code> and is
|
||||||
* N times of <code>divisor</code>.
|
* N times of <code>divisor</code>.
|
||||||
|
@ -4079,19 +4102,35 @@ lceil_ntimes(long dividend, long divisor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate time for which the program should wait for events if vsync_sw is
|
* Wait for events until next paint.
|
||||||
* enabled.
|
|
||||||
*
|
*
|
||||||
* @param timeout old timeout value, never negative!
|
* Optionally use refresh-rate based optimization to reduce painting.
|
||||||
* @return time to wait, in struct timespec
|
*
|
||||||
|
* @param fd struct pollfd used for poll()
|
||||||
|
* @param timeout second timeout (fading timeout)
|
||||||
|
* @return > 0 if we get some events, 0 if timeout is reached, < 0 on
|
||||||
|
* problems
|
||||||
*/
|
*/
|
||||||
static struct timespec
|
static int
|
||||||
vsync_sw_ntimeout(int timeout) {
|
evpoll(struct pollfd *fd, int timeout) {
|
||||||
|
// Always wait infinitely if asked so, to minimize CPU usage
|
||||||
|
if (timeout < 0) {
|
||||||
|
int ret = poll(fd, 1, timeout);
|
||||||
|
// Reset fade_time so the fading steps during idling are not counted
|
||||||
|
fade_time = get_time_ms();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just do a poll() if we are not using optimization
|
||||||
|
if (!opts.sw_opti)
|
||||||
|
return poll(fd, 1, timeout);
|
||||||
|
|
||||||
// Convert the old timeout to struct timespec
|
// Convert the old timeout to struct timespec
|
||||||
struct timespec next_paint_tmout = {
|
struct timespec next_paint_tmout = {
|
||||||
.tv_sec = timeout / MS_PER_SEC,
|
.tv_sec = timeout / MS_PER_SEC,
|
||||||
.tv_nsec = timeout % MS_PER_SEC * (NS_PER_SEC / MS_PER_SEC)
|
.tv_nsec = timeout % MS_PER_SEC * (NS_PER_SEC / MS_PER_SEC)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the nanosecond offset of the time when the we reach the timeout
|
// Get the nanosecond offset of the time when the we reach the timeout
|
||||||
// I don't think a 32-bit long could overflow here.
|
// I don't think a 32-bit long could overflow here.
|
||||||
long target_relative_offset = (next_paint_tmout.tv_nsec + get_time_timespec().tv_nsec - paint_tm_offset) % NS_PER_SEC;
|
long target_relative_offset = (next_paint_tmout.tv_nsec + get_time_timespec().tv_nsec - paint_tm_offset) % NS_PER_SEC;
|
||||||
|
@ -4100,19 +4139,19 @@ vsync_sw_ntimeout(int timeout) {
|
||||||
|
|
||||||
assert(target_relative_offset >= 0);
|
assert(target_relative_offset >= 0);
|
||||||
|
|
||||||
// If the target time is sufficiently close to a VSync time, don't add
|
// If the target time is sufficiently close to a refresh time, don't add
|
||||||
// an offset, to avoid certain blocking conditions.
|
// an offset, to avoid certain blocking conditions.
|
||||||
if ((target_relative_offset % NS_PER_SEC) < VSYNC_SW_TOLERANCE)
|
if ((target_relative_offset % NS_PER_SEC) < SW_OPTI_TOLERANCE)
|
||||||
return next_paint_tmout;
|
return poll(fd, 1, timeout);
|
||||||
|
|
||||||
// Add an offset so we wait until the next VSync after timeout
|
// Add an offset so we wait until the next refresh after timeout
|
||||||
next_paint_tmout.tv_nsec += lceil_ntimes(target_relative_offset, refresh_intv) - target_relative_offset;
|
next_paint_tmout.tv_nsec += lceil_ntimes(target_relative_offset, refresh_intv) - target_relative_offset;
|
||||||
if (next_paint_tmout.tv_nsec > NS_PER_SEC) {
|
if (next_paint_tmout.tv_nsec > NS_PER_SEC) {
|
||||||
next_paint_tmout.tv_nsec -= NS_PER_SEC;
|
next_paint_tmout.tv_nsec -= NS_PER_SEC;
|
||||||
++next_paint_tmout.tv_sec;
|
++next_paint_tmout.tv_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
return next_paint_tmout;
|
return ppoll(fd, 1, &next_paint_tmout, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4211,57 +4250,31 @@ vsync_opengl_wait(void) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for next vsync and timeout unless new events appear.
|
* Wait for next VSync.
|
||||||
*
|
|
||||||
* @param fd struct pollfd used for poll()
|
|
||||||
* @param timeout second timeout (fading timeout)
|
|
||||||
* @return > 0 if we get some events, 0 if timeout is reached, < 0 on
|
|
||||||
* problems
|
|
||||||
*/
|
*/
|
||||||
static Bool
|
static void
|
||||||
vsync_wait(Display *dpy, struct pollfd *fd, int timeout) {
|
vsync_wait(void) {
|
||||||
// Always wait infinitely if asked so, to minimize CPU usage
|
|
||||||
if (timeout < 0) {
|
|
||||||
int ret = poll(fd, 1, timeout);
|
|
||||||
// Reset fade_time so the fading steps during idling are not counted
|
|
||||||
fade_time = get_time_ms();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VSYNC_NONE == opts.vsync)
|
if (VSYNC_NONE == opts.vsync)
|
||||||
return poll(fd, 1, timeout);
|
return;
|
||||||
|
|
||||||
// vsync_sw: Wait until the next sync right after next fading timeout
|
|
||||||
if (VSYNC_SW == opts.vsync) {
|
|
||||||
struct timespec new_tmout = vsync_sw_ntimeout(timeout);
|
|
||||||
// printf("ppoll(): %3ld:%09ld\n", new_tmout.tv_sec, new_tmout.tv_nsec);
|
|
||||||
return ppoll(fd, 1, &new_tmout, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_VSYNC_DRM
|
#ifdef CONFIG_VSYNC_DRM
|
||||||
// vsync_drm: We are not accepting events when waiting for next sync,
|
|
||||||
// so I guess this would generate a latency of at most one frame. I'm
|
|
||||||
// not sure if it's possible to add some smart logic in vsync_drm_wait()
|
|
||||||
// to avoid this problem, unless I could find more documentation...
|
|
||||||
if (VSYNC_DRM == opts.vsync) {
|
if (VSYNC_DRM == opts.vsync) {
|
||||||
vsync_drm_wait();
|
vsync_drm_wait();
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_VSYNC_OPENGL
|
#ifdef CONFIG_VSYNC_OPENGL
|
||||||
// vsync_opengl: Same one-frame-latency issue, well, not sure how to deal it
|
|
||||||
// here.
|
|
||||||
if (VSYNC_OPENGL == opts.vsync) {
|
if (VSYNC_OPENGL == opts.vsync) {
|
||||||
vsync_opengl_wait();
|
vsync_opengl_wait();
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This place should not reached!
|
// This place should not reached!
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4391,7 +4404,7 @@ main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query X RandR
|
// Query X RandR
|
||||||
if (VSYNC_SW == opts.vsync && !opts.refresh_rate) {
|
if (opts.sw_opti && !opts.refresh_rate) {
|
||||||
if (XRRQueryExtension(dpy, &randr_event, &randr_error))
|
if (XRRQueryExtension(dpy, &randr_event, &randr_error))
|
||||||
randr_exists = True;
|
randr_exists = True;
|
||||||
else
|
else
|
||||||
|
@ -4429,9 +4442,12 @@ main(int argc, char **argv) {
|
||||||
|
|
||||||
register_cm((VSYNC_OPENGL == opts.vsync));
|
register_cm((VSYNC_OPENGL == opts.vsync));
|
||||||
|
|
||||||
// Initialize software/DRM/OpenGL VSync
|
// Initialize software optimization
|
||||||
if ((VSYNC_SW == opts.vsync && !vsync_sw_init())
|
if (opts.sw_opti)
|
||||||
|| (VSYNC_DRM == opts.vsync && !vsync_drm_init())
|
opts.sw_opti = sw_opti_init();
|
||||||
|
|
||||||
|
// Initialize DRM/OpenGL VSync
|
||||||
|
if ((VSYNC_DRM == opts.vsync && !vsync_drm_init())
|
||||||
|| (VSYNC_OPENGL == opts.vsync && !vsync_opengl_init()))
|
|| (VSYNC_OPENGL == opts.vsync && !vsync_opengl_init()))
|
||||||
opts.vsync = VSYNC_NONE;
|
opts.vsync = VSYNC_NONE;
|
||||||
|
|
||||||
|
@ -4513,11 +4529,7 @@ main(int argc, char **argv) {
|
||||||
ufd.fd = ConnectionNumber(dpy);
|
ufd.fd = ConnectionNumber(dpy);
|
||||||
ufd.events = POLLIN;
|
ufd.events = POLLIN;
|
||||||
|
|
||||||
#ifdef DEBUG_REPAINT
|
if (opts.sw_opti)
|
||||||
struct timespec last_paint = get_time_timespec();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (VSYNC_SW == opts.vsync)
|
|
||||||
paint_tm_offset = get_time_timespec().tv_nsec;
|
paint_tm_offset = get_time_timespec().tv_nsec;
|
||||||
|
|
||||||
reg_ignore_expire = True;
|
reg_ignore_expire = True;
|
||||||
|
@ -4534,7 +4546,7 @@ main(int argc, char **argv) {
|
||||||
Bool ev_received = False;
|
Bool ev_received = False;
|
||||||
|
|
||||||
while (QLength(dpy)
|
while (QLength(dpy)
|
||||||
|| (vsync_wait(dpy, &ufd,
|
|| (evpoll(&ufd,
|
||||||
(ev_received ? 0: (idling ? -1: fade_timeout()))) > 0)) {
|
(ev_received ? 0: (idling ? -1: fade_timeout()))) > 0)) {
|
||||||
XNextEvent(dpy, &ev);
|
XNextEvent(dpy, &ev);
|
||||||
ev_handle((XEvent *) &ev);
|
ev_handle((XEvent *) &ev);
|
||||||
|
@ -4547,14 +4559,6 @@ main(int argc, char **argv) {
|
||||||
t = paint_preprocess(dpy, list);
|
t = paint_preprocess(dpy, list);
|
||||||
|
|
||||||
if (all_damage && !is_region_empty(dpy, all_damage)) {
|
if (all_damage && !is_region_empty(dpy, all_damage)) {
|
||||||
#ifdef DEBUG_REPAINT
|
|
||||||
struct timespec now = get_time_timespec();
|
|
||||||
struct timespec diff = { 0 };
|
|
||||||
timespec_subtract(&diff, &now, &last_paint);
|
|
||||||
printf("[ %5ld:%09ld ] ", diff.tv_sec, diff.tv_nsec);
|
|
||||||
last_paint = now;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int paint;
|
static int paint;
|
||||||
paint_all(dpy, all_damage, t);
|
paint_all(dpy, all_damage, t);
|
||||||
reg_ignore_expire = False;
|
reg_ignore_expire = False;
|
||||||
|
|
|
@ -111,7 +111,7 @@ extern struct timeval time_start;
|
||||||
#define WINDOW_ARGB 2
|
#define WINDOW_ARGB 2
|
||||||
|
|
||||||
#define FADE_DELTA_TOLERANCE 0.2
|
#define FADE_DELTA_TOLERANCE 0.2
|
||||||
#define VSYNC_SW_TOLERANCE 1000
|
#define SW_OPTI_TOLERANCE 1000
|
||||||
|
|
||||||
#define NS_PER_SEC 1000000000L
|
#define NS_PER_SEC 1000000000L
|
||||||
#define US_PER_SEC 1000000L
|
#define US_PER_SEC 1000000L
|
||||||
|
@ -286,7 +286,6 @@ typedef struct _win {
|
||||||
|
|
||||||
typedef enum _vsync_t {
|
typedef enum _vsync_t {
|
||||||
VSYNC_NONE,
|
VSYNC_NONE,
|
||||||
VSYNC_SW,
|
|
||||||
VSYNC_DRM,
|
VSYNC_DRM,
|
||||||
VSYNC_OPENGL,
|
VSYNC_OPENGL,
|
||||||
} vsync_t;
|
} vsync_t;
|
||||||
|
@ -313,9 +312,11 @@ typedef struct _options {
|
||||||
/// Whether to work under synchronized mode for debugging.
|
/// Whether to work under synchronized mode for debugging.
|
||||||
Bool synchronize;
|
Bool synchronize;
|
||||||
|
|
||||||
// VSync
|
// VSync and software optimization
|
||||||
/// User-specified refresh rate.
|
/// User-specified refresh rate.
|
||||||
int refresh_rate;
|
int refresh_rate;
|
||||||
|
/// Whether to enable refresh-rate-based software optimization.
|
||||||
|
Bool sw_opti;
|
||||||
/// VSync method to use;
|
/// VSync method to use;
|
||||||
vsync_t vsync;
|
vsync_t vsync;
|
||||||
/// Whether to enable double buffer.
|
/// Whether to enable double buffer.
|
||||||
|
@ -619,6 +620,21 @@ timespec_subtract(struct timespec *result,
|
||||||
return x->tv_sec < y->tv_sec;
|
return x->tv_sec < y->tv_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current time in struct timespec.
|
||||||
|
*
|
||||||
|
* Note its starting time is unspecified.
|
||||||
|
*/
|
||||||
|
static inline struct timespec
|
||||||
|
get_time_timespec(void) {
|
||||||
|
struct timespec tm = { 0 };
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &tm);
|
||||||
|
|
||||||
|
// Return a time of all 0 if the call fails
|
||||||
|
return tm;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print time passed since program starts execution.
|
* Print time passed since program starts execution.
|
||||||
*
|
*
|
||||||
|
@ -1136,10 +1152,10 @@ static void
|
||||||
update_refresh_rate(Display *dpy);
|
update_refresh_rate(Display *dpy);
|
||||||
|
|
||||||
static Bool
|
static Bool
|
||||||
vsync_sw_init(void);
|
sw_opti_init(void);
|
||||||
|
|
||||||
static struct timespec
|
static int
|
||||||
vsync_sw_ntimeout(int timeout);
|
evpoll(struct pollfd *fd, int timeout);
|
||||||
|
|
||||||
static Bool
|
static Bool
|
||||||
vsync_drm_init(void);
|
vsync_drm_init(void);
|
||||||
|
@ -1157,8 +1173,8 @@ static void
|
||||||
vsync_opengl_wait(void);
|
vsync_opengl_wait(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Bool
|
static void
|
||||||
vsync_wait(Display *dpy, struct pollfd *fd, int timeout);
|
vsync_wait(void);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_alpha_picts(Display *dpy);
|
init_alpha_picts(Display *dpy);
|
||||||
|
|
Loading…
Reference in New Issue