mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-27 07:58:07 -04:00
Merge branch 'render-refresh-optimize'
This commit is contained in:
commit
f29d506f3b
6 changed files with 125 additions and 11 deletions
49
fdm.c
49
fdm.c
|
|
@ -21,11 +21,17 @@ struct handler {
|
||||||
bool deleted;
|
bool deleted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct hook {
|
||||||
|
fdm_hook_t callback;
|
||||||
|
void *callback_data;
|
||||||
|
};
|
||||||
|
|
||||||
struct fdm {
|
struct fdm {
|
||||||
int epoll_fd;
|
int epoll_fd;
|
||||||
bool is_polling;
|
bool is_polling;
|
||||||
tll(struct handler *) fds;
|
tll(struct handler *) fds;
|
||||||
tll(struct handler *) deferred_delete;
|
tll(struct handler *) deferred_delete;
|
||||||
|
tll(struct hook) hooks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fdm *
|
struct fdm *
|
||||||
|
|
@ -43,6 +49,7 @@ fdm_init(void)
|
||||||
.is_polling = false,
|
.is_polling = false,
|
||||||
.fds = tll_init(),
|
.fds = tll_init(),
|
||||||
.deferred_delete = tll_init(),
|
.deferred_delete = tll_init(),
|
||||||
|
.hooks = tll_init(),
|
||||||
};
|
};
|
||||||
return fdm;
|
return fdm;
|
||||||
}
|
}
|
||||||
|
|
@ -56,11 +63,16 @@ fdm_destroy(struct fdm *fdm)
|
||||||
if (tll_length(fdm->fds) > 0)
|
if (tll_length(fdm->fds) > 0)
|
||||||
LOG_WARN("FD list not empty");
|
LOG_WARN("FD list not empty");
|
||||||
|
|
||||||
|
if (tll_length(fdm->hooks) > 0)
|
||||||
|
LOG_WARN("hook list not empty");
|
||||||
|
|
||||||
assert(tll_length(fdm->fds) == 0);
|
assert(tll_length(fdm->fds) == 0);
|
||||||
assert(tll_length(fdm->deferred_delete) == 0);
|
assert(tll_length(fdm->deferred_delete) == 0);
|
||||||
|
assert(tll_length(fdm->hooks) == 0);
|
||||||
|
|
||||||
tll_free(fdm->fds);
|
tll_free(fdm->fds);
|
||||||
tll_free(fdm->deferred_delete);
|
tll_free(fdm->deferred_delete);
|
||||||
|
tll_free(fdm->hooks);
|
||||||
close(fdm->epoll_fd);
|
close(fdm->epoll_fd);
|
||||||
free(fdm);
|
free(fdm);
|
||||||
}
|
}
|
||||||
|
|
@ -195,6 +207,37 @@ fdm_event_del(struct fdm *fdm, int fd, int events)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
fdm_hook_add(struct fdm *fdm, fdm_hook_t hook, void *data)
|
||||||
|
{
|
||||||
|
#if defined(_DEBUG)
|
||||||
|
tll_foreach(fdm->hooks, it) {
|
||||||
|
if (it->item.callback == hook) {
|
||||||
|
LOG_ERR("hook=%p already registered", hook);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tll_push_back(fdm->hooks, ((struct hook){hook, data}));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
fdm_hook_del(struct fdm *fdm, fdm_hook_t hook)
|
||||||
|
{
|
||||||
|
tll_foreach(fdm->hooks, it) {
|
||||||
|
if (it->item.callback != hook)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tll_remove(fdm->hooks, it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_WARN("hook=%p not registered, hook", hook);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
fdm_poll(struct fdm *fdm)
|
fdm_poll(struct fdm *fdm)
|
||||||
{
|
{
|
||||||
|
|
@ -204,6 +247,12 @@ fdm_poll(struct fdm *fdm)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tll_foreach(fdm->hooks, it) {
|
||||||
|
LOG_DBG("executing hook %p(fdm=%p, data=%p)",
|
||||||
|
it->item.callback, fdm, it->item.callback_data);
|
||||||
|
it->item.callback(fdm, it->item.callback_data);
|
||||||
|
}
|
||||||
|
|
||||||
struct epoll_event events[tll_length(fdm->fds)];
|
struct epoll_event events[tll_length(fdm->fds)];
|
||||||
|
|
||||||
int r = epoll_wait(fdm->epoll_fd, events, tll_length(fdm->fds), -1);
|
int r = epoll_wait(fdm->epoll_fd, events, tll_length(fdm->fds), -1);
|
||||||
|
|
|
||||||
4
fdm.h
4
fdm.h
|
|
@ -5,6 +5,7 @@
|
||||||
struct fdm;
|
struct fdm;
|
||||||
|
|
||||||
typedef bool (*fdm_handler_t)(struct fdm *fdm, int fd, int events, void *data);
|
typedef bool (*fdm_handler_t)(struct fdm *fdm, int fd, int events, void *data);
|
||||||
|
typedef void (*fdm_hook_t)(struct fdm *fdm, void *data);
|
||||||
|
|
||||||
struct fdm *fdm_init(void);
|
struct fdm *fdm_init(void);
|
||||||
void fdm_destroy(struct fdm *fdm);
|
void fdm_destroy(struct fdm *fdm);
|
||||||
|
|
@ -16,4 +17,7 @@ bool fdm_del_no_close(struct fdm *fdm, int fd);
|
||||||
bool fdm_event_add(struct fdm *fdm, int fd, int events);
|
bool fdm_event_add(struct fdm *fdm, int fd, int events);
|
||||||
bool fdm_event_del(struct fdm *fdm, int fd, int events);
|
bool fdm_event_del(struct fdm *fdm, int fd, int events);
|
||||||
|
|
||||||
|
bool fdm_hook_add(struct fdm *fdm, fdm_hook_t hook, void *data);
|
||||||
|
bool fdm_hook_del(struct fdm *fdm, fdm_hook_t hook);
|
||||||
|
|
||||||
bool fdm_poll(struct fdm *fdm);
|
bool fdm_poll(struct fdm *fdm);
|
||||||
|
|
|
||||||
6
main.c
6
main.c
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "fdm.h"
|
#include "fdm.h"
|
||||||
|
#include "render.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "shm.h"
|
#include "shm.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
|
@ -218,6 +219,7 @@ main(int argc, char *const *argv)
|
||||||
|
|
||||||
struct fdm *fdm = NULL;
|
struct fdm *fdm = NULL;
|
||||||
struct wayland *wayl = NULL;
|
struct wayland *wayl = NULL;
|
||||||
|
struct renderer *renderer = NULL;
|
||||||
struct terminal *term = NULL;
|
struct terminal *term = NULL;
|
||||||
struct server *server = NULL;
|
struct server *server = NULL;
|
||||||
struct shutdown_context shutdown_ctx = {.term = &term, .exit_code = EXIT_FAILURE};
|
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)
|
if ((wayl = wayl_init(&conf, fdm)) == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if ((renderer = render_init(fdm, wayl)) == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!as_server && (term = term_init(
|
if (!as_server && (term = term_init(
|
||||||
&conf, fdm, wayl, conf.term, "foot", cwd, argc, argv,
|
&conf, fdm, wayl, conf.term, "foot", cwd, argc, argv,
|
||||||
&term_shutdown_cb, &shutdown_ctx)) == NULL) {
|
&term_shutdown_cb, &shutdown_ctx)) == NULL) {
|
||||||
|
|
@ -276,6 +281,7 @@ out:
|
||||||
term_destroy(term);
|
term_destroy(term);
|
||||||
|
|
||||||
shm_fini();
|
shm_fini();
|
||||||
|
render_destroy(renderer);
|
||||||
wayl_destroy(wayl);
|
wayl_destroy(wayl);
|
||||||
fdm_destroy(fdm);
|
fdm_destroy(fdm);
|
||||||
|
|
||||||
|
|
|
||||||
64
render.c
64
render.c
|
|
@ -22,6 +22,11 @@
|
||||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||||
|
|
||||||
|
struct renderer {
|
||||||
|
struct fdm *fdm;
|
||||||
|
struct wayland *wayl;
|
||||||
|
};
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
size_t total;
|
size_t total;
|
||||||
size_t zero; /* commits presented in less than one frame interval */
|
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 */
|
size_t two; /* commits presented in two or more frame intervals */
|
||||||
} presentation_statistics = {0};
|
} 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))
|
static void __attribute__((destructor))
|
||||||
log_presentation_statistics(void)
|
log_presentation_statistics(void)
|
||||||
{
|
{
|
||||||
|
|
@ -156,7 +211,7 @@ static const struct wp_presentation_feedback_listener presentation_feedback_list
|
||||||
.discarded = &discarded,
|
.discarded = &discarded,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct font *
|
static struct font *
|
||||||
attrs_to_font(const struct terminal *term, const struct attributes *attrs)
|
attrs_to_font(const struct terminal *term, const struct attributes *attrs)
|
||||||
{
|
{
|
||||||
int idx = attrs->italic << 1 | attrs->bold;
|
int idx = attrs->italic << 1 | attrs->bold;
|
||||||
|
|
@ -1079,10 +1134,5 @@ render_set_title(struct terminal *term, const char *_title)
|
||||||
void
|
void
|
||||||
render_refresh(struct terminal *term)
|
render_refresh(struct terminal *term)
|
||||||
{
|
{
|
||||||
assert(term->window->is_configured);
|
term->render.refresh_needed = true;
|
||||||
|
|
||||||
if (term->window->frame_callback == NULL)
|
|
||||||
grid_render(term);
|
|
||||||
else
|
|
||||||
term->render.pending = true;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7
render.h
7
render.h
|
|
@ -1,9 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
#include "fdm.h"
|
||||||
|
#include "wayland.h"
|
||||||
|
|
||||||
struct font *attrs_to_font(
|
struct renderer;
|
||||||
const struct terminal *term, const struct attributes *attrs);
|
struct renderer *render_init(struct fdm *fdm, struct wayland *wayl);
|
||||||
|
void render_destroy(struct renderer *renderer);
|
||||||
|
|
||||||
void grid_render(struct terminal *term);
|
void grid_render(struct terminal *term);
|
||||||
void render_resize(struct terminal *term, int width, int height);
|
void render_resize(struct terminal *term, int width, int height);
|
||||||
|
|
|
||||||
|
|
@ -283,8 +283,10 @@ struct terminal {
|
||||||
bool visual_focus;
|
bool visual_focus;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int scrollback_lines;
|
bool refresh_needed; /* Terminal needs to be re-rendered, as soon-as-possible */
|
||||||
|
int scrollback_lines; /* Number of scrollback lines, from conf (TODO: move out from render struct?) */
|
||||||
|
|
||||||
|
/* Render threads + synchronization primitives */
|
||||||
struct {
|
struct {
|
||||||
size_t count;
|
size_t count;
|
||||||
sem_t start;
|
sem_t start;
|
||||||
|
|
@ -303,7 +305,7 @@ struct terminal {
|
||||||
struct cell *cell; /* For easy access to content */
|
struct cell *cell; /* For easy access to content */
|
||||||
} last_cursor;
|
} last_cursor;
|
||||||
|
|
||||||
bool pending;
|
bool pending; /* Need to re-render again, after next frame-callback */
|
||||||
struct buffer *last_buf; /* Buffer we rendered to last time */
|
struct buffer *last_buf; /* Buffer we rendered to last time */
|
||||||
bool was_flashing; /* Flash was active last time we rendered */
|
bool was_flashing; /* Flash was active last time we rendered */
|
||||||
bool was_searching;
|
bool was_searching;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue