render: trigger terminal refreshes in an FDM hook

In some cases, we end up calling render_refresh() multiple times in
the same FDM iteration. This means will render the first update
immediately, and then set the 'pending' flag, causing the updated
content to be rendered in the next frame.

This can cause flicker, or flashes, since we're presenting one or more
intermediate frames until the final content is shown.

Not to mention that it is inefficient to render multiple frames like
this.

Fix by:

* render_refresh() only sets a flag in the terminal

* install an FDM hook; this hook loops all terminals and executes what
  render_refresh() _used_ to do (that is, render immediately if we're
  not waiting for a frame callback, otherwise set 'pending' flag). for
  all terminals that have the 'refresh_needed' flag set.
This commit is contained in:
Daniel Eklöf 2020-01-04 19:49:26 +01:00
parent a3c18e72f5
commit 99f471d738
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
4 changed files with 68 additions and 8 deletions

6
main.c
View file

@ -19,6 +19,7 @@
#include "config.h"
#include "fdm.h"
#include "render.h"
#include "server.h"
#include "shm.h"
#include "terminal.h"
@ -218,6 +219,7 @@ main(int argc, char *const *argv)
struct fdm *fdm = NULL;
struct wayland *wayl = NULL;
struct renderer *renderer = NULL;
struct terminal *term = NULL;
struct server *server = NULL;
struct shutdown_context shutdown_ctx = {.term = &term, .exit_code = EXIT_FAILURE};
@ -238,6 +240,9 @@ main(int argc, char *const *argv)
if ((wayl = wayl_init(&conf, fdm)) == NULL)
goto out;
if ((renderer = render_init(fdm, wayl)) == NULL)
goto out;
if (!as_server && (term = term_init(
&conf, fdm, wayl, conf.term, "foot", cwd, argc, argv,
&term_shutdown_cb, &shutdown_ctx)) == NULL) {
@ -276,6 +281,7 @@ out:
term_destroy(term);
shm_fini();
render_destroy(renderer);
wayl_destroy(wayl);
fdm_destroy(fdm);

View file

@ -22,6 +22,11 @@
#define min(x, y) ((x) < (y) ? (x) : (y))
#define max(x, y) ((x) > (y) ? (x) : (y))
struct renderer {
struct fdm *fdm;
struct wayland *wayl;
};
static struct {
size_t total;
size_t zero; /* commits presented in less than one frame interval */
@ -29,6 +34,56 @@ static struct {
size_t two; /* commits presented in two or more frame intervals */
} presentation_statistics = {0};
static void
fdm_hook_refresh_pending_terminals(struct fdm *fdm, void *data)
{
struct renderer *renderer = data;
tll_foreach(renderer->wayl->terms, it) {
struct terminal *term = it->item;
if (!term->render.refresh_needed)
continue;
assert(term->window->is_configured);
term->render.refresh_needed = false;
if (term->window->frame_callback == NULL) {
LOG_INFO("rendering immediately");
grid_render(term);
} else {
LOG_INFO("setting pending");
term->render.pending = true;
}
}
}
struct renderer *
render_init(struct fdm *fdm, struct wayland *wayl)
{
struct renderer *renderer = calloc(1, sizeof(*renderer));
*renderer = (struct renderer) {
.fdm = fdm,
.wayl = wayl,
};
if (!fdm_hook_add(fdm, &fdm_hook_refresh_pending_terminals, renderer)) {
LOG_ERR("failed to register FDM hook");
free(renderer);
return NULL;
}
return renderer;
}
void
render_destroy(struct renderer *renderer)
{
if (renderer == NULL)
return;
fdm_hook_del(renderer->fdm, &fdm_hook_refresh_pending_terminals);
}
static void __attribute__((destructor))
log_presentation_statistics(void)
{
@ -1079,10 +1134,5 @@ render_set_title(struct terminal *term, const char *_title)
void
render_refresh(struct terminal *term)
{
assert(term->window->is_configured);
if (term->window->frame_callback == NULL)
grid_render(term);
else
term->render.pending = true;
term->render.refresh_needed = true;
}

View file

@ -1,9 +1,12 @@
#pragma once
#include "terminal.h"
#include "fdm.h"
#include "wayland.h"
struct font *attrs_to_font(
const struct terminal *term, const struct attributes *attrs);
struct renderer;
struct renderer *render_init(struct fdm *fdm, struct wayland *wayl);
void render_destroy(struct renderer *renderer);
void grid_render(struct terminal *term);
void render_resize(struct terminal *term, int width, int height);

View file

@ -283,6 +283,7 @@ struct terminal {
bool visual_focus;
struct {
bool refresh_needed;
int scrollback_lines;
struct {