diff options
| author | Albert Cervin <albert@acervin.com> | 2025-11-18 17:17:14 +0100 |
|---|---|---|
| committer | Albert Cervin <albert@acervin.com> | 2025-11-19 11:06:32 +0100 |
| commit | fd5683cdc61efa37a1be7b94901f75c5409d2297 (patch) | |
| tree | ecc88724fb0c0ac408daea1fca7a69a48416b96f /src/dged | |
| parent | 9cf86e6dcafc8e7d9a314fb8fdc87347eb00fb2c (diff) | |
| download | dged-rendering-improvements.tar.gz dged-rendering-improvements.tar.xz dged-rendering-improvements.zip | |
Make sure rendering happens at least 7ms apartrendering-improvements
Running a lot faster just causes tearing.
Diffstat (limited to 'src/dged')
| -rw-r--r-- | src/dged/buffer.c | 2 | ||||
| -rw-r--r-- | src/dged/display.c | 65 | ||||
| -rw-r--r-- | src/dged/display.h | 5 | ||||
| -rw-r--r-- | src/dged/reactor-epoll.c | 4 | ||||
| -rw-r--r-- | src/dged/reactor-kqueue.c | 10 | ||||
| -rw-r--r-- | src/dged/reactor.h | 2 | ||||
| -rw-r--r-- | src/dged/timers.c | 7 | ||||
| -rw-r--r-- | src/dged/timers.h | 2 | ||||
| -rw-r--r-- | src/dged/window.c | 13 |
9 files changed, 97 insertions, 13 deletions
diff --git a/src/dged/buffer.c b/src/dged/buffer.c index d03f3ad..7eb787d 100644 --- a/src/dged/buffer.c +++ b/src/dged/buffer.c @@ -1301,6 +1301,8 @@ void render_line(struct text_chunk *line, void *userdata) { command_list_set_show_whitespace(cmdbuf->cmds, false); if (drawn_coli < cmdbuf->width) { + // TODO: should really be (causes some issues in popups) + // command_list_clear_line(cmdbuf->cmds, drawn_coli, visual_line); command_list_draw_repeated(cmdbuf->cmds, drawn_coli, visual_line, ' ', cmdbuf->width - drawn_coli); } diff --git a/src/dged/display.c b/src/dged/display.c index 332f3bc..ae5369b 100644 --- a/src/dged/display.c +++ b/src/dged/display.c @@ -23,6 +23,7 @@ struct display { struct termios orig_term; uint32_t width; uint32_t height; + bool render_in_progress; }; enum render_cmd_type { @@ -32,6 +33,7 @@ enum render_cmd_type { RenderCommand_ClearFormat = 3, RenderCommand_SetShowWhitespace = 4, RenderCommand_DrawList = 5, + RenderCommand_ClearLine = 6, }; struct render_command { @@ -42,6 +44,7 @@ struct render_command { struct repeat_cmd *repeat; struct show_ws_cmd *show_ws; struct draw_list_cmd *draw_list; + struct clear_line_cmd *clear_line; } data; }; @@ -73,6 +76,11 @@ struct draw_list_cmd { struct command_list *list; }; +struct clear_line_cmd { + uint32_t col; + uint32_t row; +}; + struct command_list { struct render_command *cmds; uint64_t ncmds; @@ -147,6 +155,7 @@ struct display *display_create(void) { d->term = term; d->height = ws.ws_row; d->width = ws.ws_col; + d->render_in_progress = false; return d; } @@ -241,6 +250,15 @@ void display_clear(struct display *display) { putc('J', stdout); } +static void display_clear_line(struct display *display, uint32_t row, + uint32_t col) { + display_move_cursor(display, row, col); + putc(ESC, stdout); + putc('[', stdout); + putc('0', stdout); + putc('K', stdout); +} + struct command_list *command_list_create(uint32_t initial_capacity, void *(*allocator)(size_t), uint32_t xoffset, uint32_t yoffset, @@ -262,6 +280,8 @@ struct command_list *command_list_create(uint32_t initial_capacity, return command_list; } +bool command_list_empty(struct command_list *list) { return list->ncmds == 0; } + struct render_command *add_command(struct command_list *list, enum render_cmd_type tp) { struct command_list *l = list; @@ -299,6 +319,9 @@ struct render_command *add_command(struct command_list *list, case RenderCommand_DrawList: cmd->data.draw_list = l->allocator(sizeof(struct draw_list_cmd)); break; + case RenderCommand_ClearLine: + cmd->data.clear_line = l->allocator(sizeof(struct clear_line_cmd)); + break; default: assert(false); } @@ -334,6 +357,14 @@ void command_list_draw_repeated(struct command_list *list, uint32_t col, cmd->nrepeat = nrepeat; } +void command_list_clear_line(struct command_list *list, uint32_t col, + uint32_t row) { + struct clear_line_cmd *cmd = + add_command(list, RenderCommand_ClearLine)->data.clear_line; + cmd->col = col; + cmd->row = row; +} + void command_list_draw_command_list(struct command_list *list, struct command_list *to_draw) { struct draw_list_cmd *cmd = @@ -420,7 +451,6 @@ void display_render(struct display *display, bool show_whitespace_state = false; while (cl != NULL) { - for (uint64_t cmdi = 0; cmdi < cl->ncmds; ++cmdi) { struct render_command *cmd = &cl->cmds[cmdi]; switch (cmd->type) { @@ -467,6 +497,13 @@ void display_render(struct display *display, fmt_stack_len = 3; break; + case RenderCommand_ClearLine: { + apply_fmt(fmt_stack, fmt_stack_len); + struct clear_line_cmd *clear_cmd = cmd->data.clear_line; + display_clear_line(display, cl->yoffset + clear_cmd->row, + cl->xoffset + clear_cmd->col); + } break; + case RenderCommand_SetShowWhitespace: show_whitespace_state = cmd->data.show_ws->show; break; @@ -500,13 +537,33 @@ void show_cursor(void) { putc('h', stdout); } +static void begin_update(void) { + putc(ESC, stdout); + putc('[', stdout); + putc('?', stdout); + put_ansiparm(2026); + putc('h', stdout); +} + +static void end_update(void) { + putc(ESC, stdout); + putc('[', stdout); + putc('?', stdout); + put_ansiparm(2026); + putc('l', stdout); +} + void display_begin_render(struct display *display) { - (void)display; + assert(!display->render_in_progress); + + display->render_in_progress = true; + begin_update(); hide_cursor(); + fflush(stdout); } void display_end_render(struct display *display) { - (void)display; - show_cursor(); + end_update(); fflush(stdout); + display->render_in_progress = false; } diff --git a/src/dged/display.h b/src/dged/display.h index 6f7f12d..ac183e5 100644 --- a/src/dged/display.h +++ b/src/dged/display.h @@ -111,6 +111,8 @@ struct command_list *command_list_create(uint32_t capacity, uint32_t xoffset, uint32_t yoffset, uint32_t tab_width, const char *name); +bool command_list_empty(struct command_list *list); + /** * Enable/disable rendering of whitespace characters. * @@ -248,3 +250,6 @@ void command_list_draw_repeated(struct command_list *list, uint32_t col, void command_list_draw_command_list(struct command_list *list, struct command_list *to_draw); + +void command_list_clear_line(struct command_list *list, uint32_t col, + uint32_t row); diff --git a/src/dged/reactor-epoll.c b/src/dged/reactor-epoll.c index beee7ec..9904c90 100644 --- a/src/dged/reactor-epoll.c +++ b/src/dged/reactor-epoll.c @@ -112,9 +112,9 @@ bool reactor_next_file_event(struct reactor *reactor, struct file_event *out) { return false; } -void reactor_update(struct reactor *reactor) { +void reactor_update(struct reactor *reactor, int timeout_ms) { struct events *events = reactor->events; - int nfds = epoll_wait(reactor->epoll_fd, events->events, 10, -1); + int nfds = epoll_wait(reactor->epoll_fd, events->events, 10, timeout_ms); if (nfds == -1) { events->nevents = 0; diff --git a/src/dged/reactor-kqueue.c b/src/dged/reactor-kqueue.c index d370653..c48e2aa 100644 --- a/src/dged/reactor-kqueue.c +++ b/src/dged/reactor-kqueue.c @@ -34,8 +34,14 @@ void reactor_destroy(struct reactor *reactor) { free(reactor); } -void reactor_update(struct reactor *reactor) { - int events = kevent(reactor->queue, NULL, 0, reactor->events, 16, NULL); +void reactor_update(struct reactor *reactor, int timeout_ms) { + struct timespec timeout = {0}; + if (timeout_ms >= 0) { + timeout.tv_nsec = timeout_ms * 1e6; + } + + int events = kevent(reactor->queue, NULL, 0, reactor->events, 16, + timeout_ms >= 0 ? &timeout : NULL); if (events == -1) { // TODO: what to do here? return; diff --git a/src/dged/reactor.h b/src/dged/reactor.h index 82ff3fe..b5ae1eb 100644 --- a/src/dged/reactor.h +++ b/src/dged/reactor.h @@ -20,7 +20,7 @@ struct reactor; struct reactor *reactor_create(void); void reactor_destroy(struct reactor *reactor); -void reactor_update(struct reactor *reactor); +void reactor_update(struct reactor *reactor, int timeout_ms); bool reactor_poll_event(struct reactor *reactor, uint32_t ev_id); uint32_t reactor_register_interest(struct reactor *reactor, int fd, enum interest interest); diff --git a/src/dged/timers.c b/src/dged/timers.c index 2fd5fc9..224a6ed 100644 --- a/src/dged/timers.c +++ b/src/dged/timers.c @@ -108,3 +108,10 @@ void timers_for_each(timer_callback callback, void *userdata) { callback(timer, userdata); } } + +uint64_t instant_ns(void) { + struct timespec ts = {0}; + clock_gettime(CLOCK_MONOTONIC, &ts); + + return ts.tv_sec * 1e9 + ts.tv_nsec; +} diff --git a/src/dged/timers.h b/src/dged/timers.h index 03ec742..ee2b14e 100644 --- a/src/dged/timers.h +++ b/src/dged/timers.h @@ -22,4 +22,6 @@ void timers_for_each(timer_callback callback, void *userdata); void timers_end_frame(void); void timers_destroy(void); +uint64_t instant_ns(void); + #endif diff --git a/src/dged/window.c b/src/dged/window.c index 82b90d5..e28fcec 100644 --- a/src/dged/window.c +++ b/src/dged/window.c @@ -7,6 +7,7 @@ #include "display.h" #include "minibuffer.h" +#include <assert.h> #include <math.h> enum window_type { @@ -283,8 +284,8 @@ bool windows_update(void *(*frame_alloc)(size_t), float frame_time) { } // is there space for borders? - if (w_y > 1 && w_y + height <= rw->height && w_x > 1 && - w_x + width + border_width <= rw->width) { + if ((w_y > 1 && w_y + height <= rw->height) && + (w_x > 1 && w_x + width + border_width <= rw->width)) { draw_borders = true; w_x -= border_width; @@ -296,6 +297,7 @@ bool windows_update(void *(*frame_alloc)(size_t), float frame_time) { w->commands = command_list_create(height * width, frame_alloc, w_x, w_y, 4, "popup-decor"); + uint32_t x = 0, y = 0; if (draw_borders) { // top @@ -330,7 +332,7 @@ bool windows_update(void *(*frame_alloc)(size_t), float frame_time) { command_list_draw_repeated(w->commands, w->width + x + 1, line, ' ', hpadding); } - x += border_width; + x += hpadding; } struct command_list *inner = @@ -350,6 +352,8 @@ bool windows_update(void *(*frame_alloc)(size_t), float frame_time) { needs_render |= buffer_view_update(&w->buffer_view, &p); command_list_draw_command_list(w->commands, inner); + } else { + g_popup_window.commands = NULL; } return needs_render; @@ -367,7 +371,8 @@ void windows_render(struct display *display) { } display_render(display, g_minibuffer_window.commands); - if (g_popup_visible) { + if (g_popup_window.commands != NULL && + !command_list_empty(g_popup_window.commands)) { display_render(display, g_popup_window.commands); } } |
