summaryrefslogtreecommitdiff
path: root/src/dged
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2025-11-18 17:17:14 +0100
committerAlbert Cervin <albert@acervin.com>2025-11-19 11:06:32 +0100
commitfd5683cdc61efa37a1be7b94901f75c5409d2297 (patch)
treeecc88724fb0c0ac408daea1fca7a69a48416b96f /src/dged
parent9cf86e6dcafc8e7d9a314fb8fdc87347eb00fb2c (diff)
downloaddged-fd5683cdc61efa37a1be7b94901f75c5409d2297.tar.gz
dged-fd5683cdc61efa37a1be7b94901f75c5409d2297.tar.xz
dged-fd5683cdc61efa37a1be7b94901f75c5409d2297.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.c2
-rw-r--r--src/dged/display.c65
-rw-r--r--src/dged/display.h5
-rw-r--r--src/dged/reactor-epoll.c4
-rw-r--r--src/dged/reactor-kqueue.c10
-rw-r--r--src/dged/reactor.h2
-rw-r--r--src/dged/timers.c7
-rw-r--r--src/dged/timers.h2
-rw-r--r--src/dged/window.c13
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);
}
}