vtgl

terminal emulator implemented in OpenGL
git clone anongit@rnpnr.xyz:vtgl.git
Log | Files | Refs | Feed | LICENSE

Commit: fab540b6a860a098902b477d89aca29587fbda6d
Parent: e2ff94b95e6c84c27b2aaa51aee38457b94fadb3
Author: Randy Palamar
Date:   Tue,  3 Dec 2024 07:49:58 -0700

block terminal resizes while rendering

We aren't resizing every frame so its probably ok to push this
behind a lock.

Diffstat:
Mdebug.c | 5++---
Mplatform_linux_common.c | 2++
Mplatform_linux_x11.c | 4++++
Mutil.h | 7+++++--
Mvtgl.c | 68+++++++++++++++++++++++++++++++++++++++++---------------------------
Mvtgl.h | 1+
6 files changed, 55 insertions(+), 32 deletions(-)

diff --git a/debug.c b/debug.c @@ -392,9 +392,8 @@ debug_frame_end(TerminalMemory *memory) g_debug_table.snapshot_index++; if (g_debug_table.snapshot_index == MAX_DEBUG_RECORD_COUNT) g_debug_table.snapshot_index = 0; - u64 event_array_event_index = __atomic_exchange_n(&g_debug_table.event_array_event_index, - (u64)g_debug_table.snapshot_index << 32, - __ATOMIC_ACQUIRE); + u64 event_array_event_index = atomic_exchange_n(&g_debug_table.event_array_event_index, + (u64)g_debug_table.snapshot_index << 32); u32 array_index = event_array_event_index >> 32; u32 event_count = event_array_event_index & 0xFFFFFFFF; diff --git a/platform_linux_common.c b/platform_linux_common.c @@ -22,6 +22,8 @@ #define VERSION "unknown" #endif +#define atomic_exchange_n(ptr, val) __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST) + struct __attribute__((aligned(16))) stack_base { void (*entry)(struct stack_base *stack); Arena thread_arena; diff --git a/platform_linux_x11.c b/platform_linux_x11.c @@ -262,6 +262,10 @@ update_input(PlatformCtx *ctx) ctx->char_stream.widx = 0; struct timespec timeout = {.tv_nsec = 25e6}; + if (input->pending_updates) { + timeout.tv_nsec = 0; + input->pending_updates = 0; + } fd_set rfd; FD_ZERO(&rfd); diff --git a/util.h b/util.h @@ -164,8 +164,9 @@ typedef struct { X(texslot) enum gl_flags { - NEEDS_RESIZE = 1 << 0, - NEEDS_REFILL = 1 << 1, + RESIZE_RENDERER = 1 << 0, + NEEDS_RESIZE = 1 << 1, + NEEDS_REFILL = 1 << 2, DRAW_DEBUG_OVERLAY = 1 << 30, }; @@ -415,7 +416,9 @@ typedef struct Term { Cursor cursor; Cursor saved_cursors[2]; + TermView views[2]; + i32 resize_lock; i32 view_idx; i32 scroll_offset; diff --git a/vtgl.c b/vtgl.c @@ -262,6 +262,9 @@ resize_terminal(Term *t, PlatformAPI *platform, iv2 window_size) } platform->set_terminal_size(t->child, t->size.h, t->size.w, ws.w, ws.h); + + t->gl.flags |= RESIZE_RENDERER; + t->gl.flags &= ~NEEDS_RESIZE; } static void @@ -304,7 +307,9 @@ resize(Term *t, PlatformAPI *platform, iv2 window_size) sp->term_size_in_pixels = gl->window_size; sp->term_size_in_cells = t->size; - gl->flags &= ~NEEDS_RESIZE; + set_projection_matrix(gl); + + gl->flags &= ~RESIZE_RENDERER; } static RenderCtx @@ -509,13 +514,13 @@ render_framebuffer(Term *t, RenderCell *render_buf, TerminalInput *input, Arena { BEGIN_TIMED_BLOCK(); - TermView *tv = t->views + t->view_idx; - + TermView *tv = t->views + t->view_idx; + iv2 term_size = t->size; /* NOTE: draw whole framebuffer */ - for (u32 row = 0; row < t->size.h; row++) { - for (u32 col = 0; col < t->size.w; col++) { + for (u32 row = 0; row < term_size.h; row++) { + for (u32 col = 0; col < term_size.w; col++) { Cell c = tv->fb.rows[row][col]; - RenderCell *rc = render_buf + (row * t->size.w + col); + RenderCell *rc = render_buf + (row * term_size.w + col); CachedGlyph *cg; rc->gpu_glyph = get_gpu_glyph_index(arena, &t->gl, &t->fa, c.cp, 0, @@ -536,12 +541,10 @@ render_framebuffer(Term *t, RenderCell *render_buf, TerminalInput *input, Arena } /* NOTE: draw selection if active */ - if (is_valid_range(t->selection.range)) { - SelectionIterator si = selection_iterator(t->selection.range, tv->fb.rows, t->size.w); - for (Cell *c = selection_next(&si); c; c = selection_next(&si)) { - RenderCell *rc = render_buf + si.cursor.y * t->size.w + si.cursor.x; - rc->fg ^= SHADER_PACK_ATTR(ATTR_INVERSE); - } + SelectionIterator si = selection_iterator(t->selection.range, tv->fb.rows, term_size.w); + for (Cell *c = selection_next(&si); c; c = selection_next(&si)) { + RenderCell *rc = render_buf + si.cursor.y * term_size.w + si.cursor.x; + rc->fg ^= SHADER_PACK_ATTR(ATTR_INVERSE); } END_TIMED_BLOCK(); @@ -1234,13 +1237,8 @@ DEBUG_EXPORT VTGL_RENDER_FRAME_FN(vtgl_render_frame) dt_for_frame = input->dt; - b32 update_render_buffer = __atomic_exchange_n(&t->gl.queued_render, 0, __ATOMIC_SEQ_CST); - TempArena temp_arena = begin_temp_arena(&arena); - if (t->gl.flags & NEEDS_RESIZE || !equal_iv2(input->window_size, t->gl.window_size)) - resize(t, &memory->platform_api, input->window_size); - if (input->executable_reloaded) { reload_all_shaders(memory); } @@ -1256,21 +1254,30 @@ DEBUG_EXPORT VTGL_RENDER_FRAME_FN(vtgl_render_frame) BEGIN_NAMED_BLOCK(update_render); - set_projection_matrix(&t->gl); - RenderCtx rc = make_render_ctx(&arena, &t->gl, &t->fa); glUseProgram(t->gl.programs[SHADER_RENDER]); glBindFramebuffer(GL_FRAMEBUFFER, t->gl.fb); clear_colour(); - if (update_render_buffer) { - u32 cell_count = t->size.h * t->size.w; - RenderCell *render_buf = alloc(&arena, RenderCell, cell_count); - render_framebuffer(t, render_buf, input, arena); - glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, cell_count * sizeof(*render_buf), render_buf); + b32 can_render_term = atomic_exchange_n(&t->resize_lock, 1) == 0; + if (can_render_term) { + if (t->gl.flags & RESIZE_RENDERER) + resize(t, &memory->platform_api, input->window_size); + + if (t->gl.queued_render) { + t->gl.queued_render = 0; + u32 cell_count = t->size.h * t->size.w; + RenderCell *render_buf = alloc(&arena, RenderCell, cell_count); + render_framebuffer(t, render_buf, input, arena); + glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, + cell_count * sizeof(*render_buf), render_buf); + } + render_cursor(t, input->window_focused, arena); + t->resize_lock = 0; + } else if (t->gl.queued_render) { + input->pending_updates = 1; } - render_cursor(t, input->window_focused, arena); ShaderParameters *sp = &t->gl.shader_parameters; sp->blink_parameter += 2 * PI * g_blink_speed * dt_for_frame; @@ -1322,8 +1329,15 @@ DEBUG_EXPORT VTGL_FRAME_STEP_FN(vtgl_frame_step) t->temp_arena = begin_temp_arena(&t->arena_for_frame); - if (t->gl.flags & NEEDS_RESIZE || !equal_iv2(input->window_size, t->gl.window_size)) - resize_terminal(t, &memory->platform_api, input->window_size); + if (t->gl.flags & NEEDS_RESIZE || !equal_iv2(input->window_size, t->gl.window_size)) { + b32 can_resize_term = atomic_exchange_n(&t->resize_lock, 1) == 0; + if (can_resize_term) { + resize_terminal(t, &memory->platform_api, input->window_size); + t->resize_lock = 0; + } else { + input->pending_updates = 1; + } + } BEGIN_NAMED_BLOCK(mouse_and_keyboard_input); if (input->character_input.len) { diff --git a/vtgl.h b/vtgl.h @@ -340,6 +340,7 @@ typedef struct TerminalInput { b32 executable_reloaded; b32 window_refreshed; b32 window_focused; + b32 pending_updates; u32 modifiers;