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:
parent
e986ebceda
commit
28cf35e43b
|
@ -15,18 +15,19 @@
|
||||||
#include "backend/backend_common.h"
|
#include "backend/backend_common.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "kernel.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "x.h"
|
#include "x.h"
|
||||||
#include "kernel.h"
|
|
||||||
|
|
||||||
#define auto __auto_type
|
#define auto __auto_type
|
||||||
|
|
||||||
typedef struct _xrender_data {
|
typedef struct _xrender_data {
|
||||||
/// The idle fence for the present extension
|
/// The idle fence for the present extension
|
||||||
xcb_sync_fence_t idle_fence;
|
xcb_sync_fence_t idle_fence;
|
||||||
|
bool present_in_progress;
|
||||||
/// The target window
|
/// The target window
|
||||||
xcb_window_t target_win;
|
xcb_window_t target_win;
|
||||||
/// The painting target, it is either the root or the overlay
|
/// 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];
|
xcb_render_fixed_t *x_blur_kern[MAX_BLUR_PASS];
|
||||||
/// Number of elements in each blur kernel
|
/// Number of elements in each blur kernel
|
||||||
size_t x_blur_kern_size[MAX_BLUR_PASS];
|
size_t x_blur_kern_size[MAX_BLUR_PASS];
|
||||||
|
|
||||||
|
xcb_special_event_t *present_event;
|
||||||
} xrender_data;
|
} xrender_data;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -400,6 +403,7 @@ static void *init(session_t *ps) {
|
||||||
xd->shadow_pixel = solid_picture(ps, true, 1, ps->o.shadow_red,
|
xd->shadow_pixel = solid_picture(ps, true, 1, ps->o.shadow_red,
|
||||||
ps->o.shadow_green, ps->o.shadow_blue);
|
ps->o.shadow_green, ps->o.shadow_blue);
|
||||||
xd->shadow_kernel = gaussian_kernel(ps->o.shadow_radius);
|
xd->shadow_kernel = gaussian_kernel(ps->o.shadow_radius);
|
||||||
|
xd->present_in_progress = false;
|
||||||
sum_kernel_preprocess(xd->shadow_kernel);
|
sum_kernel_preprocess(xd->shadow_kernel);
|
||||||
|
|
||||||
if (ps->overlay != XCB_NONE) {
|
if (ps->overlay != XCB_NONE) {
|
||||||
|
@ -435,17 +439,19 @@ static void *init(session_t *ps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps->present_exists) {
|
if (ps->present_exists) {
|
||||||
xd->idle_fence = xcb_generate_id(ps->c);
|
auto eid = xcb_generate_id(ps->c);
|
||||||
// To make sure we won't get stuck waiting for the idle_fence, we maintain
|
auto e = xcb_request_check(ps->c, xcb_present_select_input_checked(
|
||||||
// this invariant: the idle_fence is either triggered, or is in the
|
ps->c, eid, xd->target_win,
|
||||||
// process of being triggered (e.g. by xcb_present_pixmap)
|
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY));
|
||||||
auto e = xcb_request_check(
|
|
||||||
ps->c, xcb_sync_create_fence(ps->c, ps->root, xd->idle_fence, 1));
|
|
||||||
if (e) {
|
if (e) {
|
||||||
log_error("Cannot create a fence, vsync might not work");
|
log_error("Cannot select present input, vsync will be disabled");
|
||||||
xd->idle_fence = XCB_NONE;
|
|
||||||
free(e);
|
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++) {
|
for (int i = 0; ps->o.blur_kerns[i]; i++) {
|
||||||
assert(i < MAX_BLUR_PASS - 1);
|
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) {
|
static void prepare(void *backend_data, session_t *ps, const region_t *reg_paint) {
|
||||||
struct _xrender_data *xd = backend_data;
|
struct _xrender_data *xd = backend_data;
|
||||||
if (ps->o.vsync != VSYNC_NONE && ps->present_exists) {
|
if (ps->o.vsync != VSYNC_NONE && ps->present_exists && xd->present_in_progress) {
|
||||||
xcb_sync_await_fence(ps->c, 1, &xd->idle_fence);
|
// 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)
|
// 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.
|
// 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
|
// To make sure rendering won't get stuck if user toggles vsync on the
|
||||||
// fly.
|
// 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_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,
|
XCB_NONE, 0, 0, XCB_NONE, XCB_NONE, XCB_NONE, 0,
|
||||||
0, 1, 0, 0, NULL);
|
0, 0, 0, 0, NULL);
|
||||||
|
xd->present_in_progress = true;
|
||||||
} else {
|
} else {
|
||||||
// compose() sets clip region, so clear it first to make
|
// compose() sets clip region, so clear it first to make
|
||||||
// sure we update the whole screen.
|
// sure we update the whole screen.
|
||||||
|
|
Loading…
Reference in New Issue