diff options
author | Simon Ser <contact@emersion.fr> | 2019-09-26 12:10:49 +0300 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2019-09-26 10:36:18 -0400 |
commit | 00c4c7e8cc437c6f905c6fbe94cf8eaf508f8644 (patch) | |
tree | 224a10fe66802900ca02dfc8db345fed92cb3124 /sway/desktop/output.c | |
parent | input: Add support for tablet protocol. (diff) | |
download | sway-00c4c7e8cc437c6f905c6fbe94cf8eaf508f8644.tar.gz sway-00c4c7e8cc437c6f905c6fbe94cf8eaf508f8644.tar.zst sway-00c4c7e8cc437c6f905c6fbe94cf8eaf508f8644.zip |
Fix direct scan-out flickering
Sometimes when using direct scan-out, some flickering between the
fullscreen app and the regular desktop could be seen.
This happened because we called wlr_output_attach_render and then
wlr_output_attach_buffer for direct scan-out. wlr_output_attach_render
makes the OpenGL context current but also attaches the OpenGL buffer to
the primary plane apparently (all of this happens inside
eglMakeCurrent).
This patch moves the scan-out logic outside of output_render, before
wlr_output_attach_render. This lines it up with rootston's
implementation. This also makes more sense since no rendering is
involved when using direct scan-out.
Sorry about that, I should've tested this with more clients. The new
code has been tested with mpv and a GLFW demo.
Diffstat (limited to 'sway/desktop/output.c')
-rw-r--r-- | sway/desktop/output.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 4bfc3b77..7f250542 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -412,6 +412,72 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { | |||
412 | output_for_each_surface(output, send_frame_done_iterator, when); | 412 | output_for_each_surface(output, send_frame_done_iterator, when); |
413 | } | 413 | } |
414 | 414 | ||
415 | static void count_surface_iterator(struct sway_output *output, | ||
416 | struct wlr_surface *surface, struct wlr_box *_box, float rotation, | ||
417 | void *data) { | ||
418 | size_t *n = data; | ||
419 | (*n)++; | ||
420 | } | ||
421 | |||
422 | static bool scan_out_fullscreen_view(struct sway_output *output, | ||
423 | struct sway_view *view) { | ||
424 | struct wlr_output *wlr_output = output->wlr_output; | ||
425 | struct sway_workspace *workspace = output->current.active_workspace; | ||
426 | if (!sway_assert(workspace, "Expected an active workspace")) { | ||
427 | return false; | ||
428 | } | ||
429 | |||
430 | if (view->saved_buffer) { | ||
431 | return false; | ||
432 | } | ||
433 | |||
434 | for (int i = 0; i < workspace->current.floating->length; ++i) { | ||
435 | struct sway_container *floater = | ||
436 | workspace->current.floating->items[i]; | ||
437 | if (container_is_transient_for(floater, view->container)) { | ||
438 | return false; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | #if HAVE_XWAYLAND | ||
443 | if (!wl_list_empty(&root->xwayland_unmanaged)) { | ||
444 | return false; | ||
445 | } | ||
446 | #endif | ||
447 | |||
448 | if (!wl_list_empty(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY])) { | ||
449 | return false; | ||
450 | } | ||
451 | if (!wl_list_empty(&root->drag_icons)) { | ||
452 | return false; | ||
453 | } | ||
454 | |||
455 | struct wlr_surface *surface = view->surface; | ||
456 | if (surface == NULL) { | ||
457 | return false; | ||
458 | } | ||
459 | size_t n_surfaces = 0; | ||
460 | output_view_for_each_surface(output, view, | ||
461 | count_surface_iterator, &n_surfaces); | ||
462 | if (n_surfaces != 1) { | ||
463 | return false; | ||
464 | } | ||
465 | |||
466 | if (surface->buffer == NULL) { | ||
467 | return false; | ||
468 | } | ||
469 | |||
470 | if ((float)surface->current.scale != wlr_output->scale || | ||
471 | surface->current.transform != wlr_output->transform) { | ||
472 | return false; | ||
473 | } | ||
474 | |||
475 | if (!wlr_output_attach_buffer(wlr_output, surface->buffer)) { | ||
476 | return false; | ||
477 | } | ||
478 | return wlr_output_commit(wlr_output); | ||
479 | } | ||
480 | |||
415 | static void damage_handle_frame(struct wl_listener *listener, void *data) { | 481 | static void damage_handle_frame(struct wl_listener *listener, void *data) { |
416 | struct sway_output *output = | 482 | struct sway_output *output = |
417 | wl_container_of(listener, output, damage_frame); | 483 | wl_container_of(listener, output, damage_frame); |
@@ -422,6 +488,35 @@ static void damage_handle_frame(struct wl_listener *listener, void *data) { | |||
422 | struct timespec now; | 488 | struct timespec now; |
423 | clock_gettime(CLOCK_MONOTONIC, &now); | 489 | clock_gettime(CLOCK_MONOTONIC, &now); |
424 | 490 | ||
491 | struct sway_workspace *workspace = output->current.active_workspace; | ||
492 | if (workspace == NULL) { | ||
493 | return; | ||
494 | } | ||
495 | |||
496 | struct sway_container *fullscreen_con = root->fullscreen_global; | ||
497 | if (!fullscreen_con) { | ||
498 | fullscreen_con = workspace->current.fullscreen; | ||
499 | } | ||
500 | |||
501 | if (fullscreen_con && fullscreen_con->view) { | ||
502 | // Try to scan-out the fullscreen view | ||
503 | static bool last_scanned_out = false; | ||
504 | bool scanned_out = | ||
505 | scan_out_fullscreen_view(output, fullscreen_con->view); | ||
506 | |||
507 | if (scanned_out && !last_scanned_out) { | ||
508 | sway_log(SWAY_DEBUG, "Scanning out fullscreen view"); | ||
509 | } | ||
510 | if (last_scanned_out && !scanned_out) { | ||
511 | sway_log(SWAY_DEBUG, "Stopping fullscreen view scan out"); | ||
512 | } | ||
513 | last_scanned_out = scanned_out; | ||
514 | |||
515 | if (scanned_out) { | ||
516 | goto frame_done; | ||
517 | } | ||
518 | } | ||
519 | |||
425 | bool needs_frame; | 520 | bool needs_frame; |
426 | pixman_region32_t damage; | 521 | pixman_region32_t damage; |
427 | pixman_region32_init(&damage); | 522 | pixman_region32_init(&damage); |
@@ -436,6 +531,7 @@ static void damage_handle_frame(struct wl_listener *listener, void *data) { | |||
436 | 531 | ||
437 | pixman_region32_fini(&damage); | 532 | pixman_region32_fini(&damage); |
438 | 533 | ||
534 | frame_done: | ||
439 | // Send frame done to all visible surfaces | 535 | // Send frame done to all visible surfaces |
440 | send_frame_done(output, &now); | 536 | send_frame_done(output, &now); |
441 | } | 537 | } |