Wait for PresentCompleteNotify

Don't use idle fence. There is no reliable & portable way to obtain a
fence Present will like. Intel driver wants a DRI3 fence, NVIDIA driver
doesn't support DRI3, and wants a XSync fence (I am not even sure, since
Present doesn't really work with the NVIDIA driver. And using the fence
on NVIDIA driver causes compton to use 100% CPU).

Just don't bother.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-02-24 23:29:48 +00:00
parent e986ebceda
commit 28cf35e43b
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
1 changed files with 27 additions and 14 deletions

View File

@ -15,18 +15,19 @@
#include "backend/backend_common.h"
#include "common.h"
#include "config.h"
#include "kernel.h"
#include "log.h"
#include "region.h"
#include "utils.h"
#include "win.h"
#include "x.h"
#include "kernel.h"
#define auto __auto_type
typedef struct _xrender_data {
/// The idle fence for the present extension
xcb_sync_fence_t idle_fence;
bool present_in_progress;
/// The target window
xcb_window_t target_win;
/// The painting target, it is either the root or the overlay
@ -59,6 +60,8 @@ typedef struct _xrender_data {
xcb_render_fixed_t *x_blur_kern[MAX_BLUR_PASS];
/// Number of elements in each blur kernel
size_t x_blur_kern_size[MAX_BLUR_PASS];
xcb_special_event_t *present_event;
} xrender_data;
#if 0
@ -400,6 +403,7 @@ static void *init(session_t *ps) {
xd->shadow_pixel = solid_picture(ps, true, 1, ps->o.shadow_red,
ps->o.shadow_green, ps->o.shadow_blue);
xd->shadow_kernel = gaussian_kernel(ps->o.shadow_radius);
xd->present_in_progress = false;
sum_kernel_preprocess(xd->shadow_kernel);
if (ps->overlay != XCB_NONE) {
@ -435,17 +439,19 @@ static void *init(session_t *ps) {
}
if (ps->present_exists) {
xd->idle_fence = xcb_generate_id(ps->c);
// To make sure we won't get stuck waiting for the idle_fence, we maintain
// this invariant: the idle_fence is either triggered, or is in the
// process of being triggered (e.g. by xcb_present_pixmap)
auto e = xcb_request_check(
ps->c, xcb_sync_create_fence(ps->c, ps->root, xd->idle_fence, 1));
auto eid = xcb_generate_id(ps->c);
auto e = xcb_request_check(ps->c, xcb_present_select_input_checked(
ps->c, eid, xd->target_win,
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY));
if (e) {
log_error("Cannot create a fence, vsync might not work");
xd->idle_fence = XCB_NONE;
log_error("Cannot select present input, vsync will be disabled");
free(e);
}
xd->present_event = xcb_register_for_special_xge(ps->c, &xcb_present_id, eid, NULL);
if (!xd->present_event) {
log_error("Cannot register for special XGE, vsync will be disabled");
}
}
for (int i = 0; ps->o.blur_kerns[i]; i++) {
assert(i < MAX_BLUR_PASS - 1);
@ -472,8 +478,15 @@ static void *root_change(void *backend_data, session_t *ps) {
static void prepare(void *backend_data, session_t *ps, const region_t *reg_paint) {
struct _xrender_data *xd = backend_data;
if (ps->o.vsync != VSYNC_NONE && ps->present_exists) {
xcb_sync_await_fence(ps->c, 1, &xd->idle_fence);
if (ps->o.vsync != VSYNC_NONE && ps->present_exists && xd->present_in_progress) {
// TODO don't block wait for present completion
xcb_present_generic_event_t *pev = (void *)xcb_wait_for_special_event(ps->c, xd->present_event);
assert(pev->evtype == XCB_PRESENT_COMPLETE_NOTIFY);
//xcb_present_complete_notify_event_t *pcev = (void *)pev;
//log_trace("Present complete: %d %ld", pcev->mode, pcev->msc);
free(pev);
xd->present_in_progress = false;
}
// Paint the root pixmap (i.e. wallpaper)
@ -491,10 +504,10 @@ static void present(void *backend_data, session_t *ps) {
// Only reset the fence when we are sure we will trigger it again.
// To make sure rendering won't get stuck if user toggles vsync on the
// fly.
xcb_sync_reset_fence(ps->c, xd->idle_fence);
xcb_present_pixmap(ps->c, xd->target_win, xd->back_pixmap, 0, XCB_NONE,
XCB_NONE, 0, 0, XCB_NONE, XCB_NONE, xd->idle_fence, 0,
0, 1, 0, 0, NULL);
XCB_NONE, 0, 0, XCB_NONE, XCB_NONE, XCB_NONE, 0,
0, 0, 0, 0, NULL);
xd->present_in_progress = true;
} else {
// compose() sets clip region, so clear it first to make
// sure we update the whole screen.