Slightly better error handling

Handle backend initialization failure.

Also actually disable vsync when it's not supported in the new xrender
backend.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-02-25 00:07:12 +00:00
parent 72a977eed5
commit 7a446ca1f4
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
2 changed files with 85 additions and 38 deletions

View File

@ -25,6 +25,8 @@
#define auto __auto_type #define auto __auto_type
typedef struct _xrender_data { typedef struct _xrender_data {
/// If vsync is enabled and supported by the current system
bool vsync;
/// 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; bool present_in_progress;
@ -393,6 +395,30 @@ static void release_win(void *backend_data, session_t *ps, win *w, void *win_dat
free(wd); free(wd);
} }
static void deinit(void *backend_data, session_t *ps) {
struct _xrender_data *xd = backend_data;
for (int i = 0; i < 256; i++) {
xcb_render_free_picture(ps->c, xd->alpha_pict[i]);
}
xcb_render_free_picture(ps->c, xd->target);
xcb_render_free_picture(ps->c, xd->root_pict);
for (int i = 0; i < 2; i++) {
xcb_render_free_picture(ps->c, xd->back[i]);
xcb_free_pixmap(ps->c, xd->back_pixmap[i]);
}
for (int i = 0; ps->o.blur_kerns[i]; i++) {
free(xd->x_blur_kern[i]);
}
if (xd->present_event) {
xcb_unregister_for_special_event(ps->c, xd->present_event);
}
xcb_render_free_picture(ps->c, xd->white_pixel);
xcb_render_free_picture(ps->c, xd->black_pixel);
xcb_render_free_picture(ps->c, xd->shadow_pixel);
free_conv(xd->shadow_kernel);
free(xd);
}
static void *init(session_t *ps) { static void *init(session_t *ps) {
auto xd = ccalloc(1, struct _xrender_data); auto xd = ccalloc(1, struct _xrender_data);
@ -429,13 +455,41 @@ static void *init(session_t *ps) {
abort(); abort();
} }
xd->vsync = ps->o.vsync != VSYNC_NONE;
if (ps->present_exists) {
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 select present input, vsync will be disabled");
xd->vsync = false;
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");
xd->vsync = false;
}
} else {
xd->vsync = false;
}
// We might need to do double buffering for vsync // We might need to do double buffering for vsync
int pixmap_needed = ps->o.vsync ? 2 : 1; int pixmap_needed = xd->vsync ? 2 : 1;
for (int i = 0; i < pixmap_needed; i++) { for (int i = 0; i < pixmap_needed; i++) {
xd->back_pixmap[i] = x_create_pixmap(ps->c, pictfmt->depth, ps->root, xd->back_pixmap[i] = x_create_pixmap(ps->c, pictfmt->depth, ps->root,
ps->root_width, ps->root_height); ps->root_width, ps->root_height);
xd->back[i] = x_create_picture_with_pictfmt_and_pixmap( xd->back[i] = x_create_picture_with_pictfmt_and_pixmap(
ps->c, pictfmt, xd->back_pixmap[i], 0, NULL); ps->c, pictfmt, xd->back_pixmap[i], 0, NULL);
if (xd->back_pixmap[i] == XCB_NONE || xd->back[i] == XCB_NONE) {
log_error("Cannot create pixmap for rendering");
goto err;
}
} }
xd->curr_back = 0; xd->curr_back = 0;
@ -446,41 +500,15 @@ static void *init(session_t *ps) {
xd->root_pict = x_create_picture_with_visual_and_pixmap( xd->root_pict = x_create_picture_with_visual_and_pixmap(
ps->c, ps->vis, root_pixmap, 0, NULL); ps->c, ps->vis, root_pixmap, 0, NULL);
} }
if (ps->present_exists) {
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 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++) { for (int i = 0; ps->o.blur_kerns[i]; i++) {
assert(i < MAX_BLUR_PASS - 1); assert(i < MAX_BLUR_PASS - 1);
xd->x_blur_kern_size[i] = x_picture_filter_from_conv( xd->x_blur_kern_size[i] = x_picture_filter_from_conv(
ps->o.blur_kerns[i], 1, &xd->x_blur_kern[i], (size_t[]){0}); ps->o.blur_kerns[i], 1, &xd->x_blur_kern[i], (size_t[]){0});
} }
return xd; return xd;
} err:
deinit(xd, ps);
static void deinit(void *backend_data, session_t *ps) { return NULL;
struct _xrender_data *xd = backend_data;
for (int i = 0; i < 256; i++)
xcb_render_free_picture(ps->c, xd->alpha_pict[i]);
xcb_render_free_picture(ps->c, xd->white_pixel);
xcb_render_free_picture(ps->c, xd->black_pixel);
free_conv(xd->shadow_kernel);
free(xd);
} }
static void *root_change(void *backend_data, session_t *ps) { static void *root_change(void *backend_data, session_t *ps) {
@ -490,7 +518,7 @@ 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 && xd->present_in_progress) { if (xd->vsync && xd->present_in_progress) {
// TODO don't block wait for present completion // TODO don't block wait for present completion
xcb_present_generic_event_t *pev = xcb_present_generic_event_t *pev =
(void *)xcb_wait_for_special_event(ps->c, xd->present_event); (void *)xcb_wait_for_special_event(ps->c, xd->present_event);
@ -518,7 +546,7 @@ static void prepare(void *backend_data, session_t *ps, const region_t *reg_paint
static void present(void *backend_data, session_t *ps) { static void present(void *backend_data, session_t *ps) {
struct _xrender_data *xd = backend_data; struct _xrender_data *xd = backend_data;
if (ps->o.vsync != VSYNC_NONE && ps->present_exists) { if (xd->vsync) {
// 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.

View File

@ -75,7 +75,7 @@ session_destroy(session_t *ps);
static void static void
cxinerama_upd_scrs(session_t *ps); cxinerama_upd_scrs(session_t *ps);
static void static bool must_use
redir_start(session_t *ps); redir_start(session_t *ps);
static void static void
@ -657,7 +657,9 @@ paint_preprocess(session_t *ps, bool *fade_running) {
} }
} else { } else {
ev_timer_stop(ps->loop, &ps->unredir_timer); ev_timer_stop(ps->loop, &ps->unredir_timer);
redir_start(ps); if (!redir_start(ps)) {
return NULL;
}
} }
return t; return t;
@ -809,7 +811,7 @@ configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
if (!bi->root_change) { if (!bi->root_change) {
// deinit/reinit backend if the backend cannot handle root change // deinit/reinit backend if the backend cannot handle root change
bi->deinit(ps->backend_data, ps); bi->deinit(ps->backend_data, ps);
ps->backend_data = NULL; ps->backend_data = NULL;
} }
} else { } else {
free_paint(ps, &ps->tgt_buffer); free_paint(ps, &ps->tgt_buffer);
@ -821,14 +823,16 @@ configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
rebuild_screen_reg(ps); rebuild_screen_reg(ps);
rebuild_shadow_exclude_reg(ps); rebuild_shadow_exclude_reg(ps);
for (int i = 0; i < ps->ndamage; i++) { for (int i = 0; i < ps->ndamage; i++) {
pixman_region32_clear(&ps->damage_ring[i]); pixman_region32_clear(&ps->damage_ring[i]);
} }
ps->damage = ps->damage_ring + ps->ndamage - 1; ps->damage = ps->damage_ring + ps->ndamage - 1;
// Re-redirect screen if required // Re-redirect screen if required
if (ps->o.reredir_on_root_change && ps->redirected) { if (ps->o.reredir_on_root_change && ps->redirected) {
redir_stop(ps); redir_stop(ps);
redir_start(ps); if (!redir_start(ps)) {
return;
}
} }
// Invalidate reg_ignore from the top // Invalidate reg_ignore from the top
@ -853,6 +857,12 @@ configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
bi->root_change(ps->backend_data, ps); bi->root_change(ps->backend_data, ps);
} else { } else {
ps->backend_data = bi->init(ps); ps->backend_data = bi->init(ps);
if (!ps->backend_data) {
log_fatal("Failed to re-initialize backend after root change, aborting...");
ps->quit = true;
ev_break(ps->loop, EVBREAK_ALL);
return;
}
} }
} }
force_repaint(ps); force_repaint(ps);
@ -1961,8 +1971,10 @@ init_overlay(session_t *ps) {
/** /**
* Redirect all windows. * Redirect all windows.
*
* @return whether the operation succeeded or not
*/ */
static void static bool
redir_start(session_t *ps) { redir_start(session_t *ps) {
if (!ps->redirected) { if (!ps->redirected) {
log_debug("Screen redirected."); log_debug("Screen redirected.");
@ -1982,6 +1994,12 @@ redir_start(session_t *ps) {
backend_info_t *bi = backend_list[ps->o.backend]; backend_info_t *bi = backend_list[ps->o.backend];
assert(bi); assert(bi);
ps->backend_data = bi->init(ps); ps->backend_data = bi->init(ps);
if (!ps->backend_data) {
log_fatal("Failed to initialize backend, aborting...");
ps->quit = true;
ev_break(ps->loop, EVBREAK_ALL);
return false;
}
for (win *w = ps->list; w; w = w->next) { for (win *w = ps->list; w; w = w->next) {
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) { if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
w->win_data = bi->prepare_win(ps->backend_data, ps, w); w->win_data = bi->prepare_win(ps->backend_data, ps, w);
@ -2006,6 +2024,7 @@ redir_start(session_t *ps) {
// Repaint the whole screen // Repaint the whole screen
force_repaint(ps); force_repaint(ps);
} }
return true;
} }
/** /**