mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-27 01:40:16 -05:00
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:
parent
a3c18e72f5
commit
99f471d738
4 changed files with 68 additions and 8 deletions
62
render.c
62
render.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue