vtgl

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

Commit: edc98a4478a6aa44b1916586cf1f30d5f30f081a
Parent: 974e3f2ae6f0c1b4489cf8176b028758730719db
Author: Randy Palamar
Date:   Mon, 11 Nov 2024 21:47:33 -0700

remove runtime framebuffer allocations

We can just set off some space during initialization and use that
for resizing later. The chosen size of 2MB per framebuffer is
about 2 times the required size for a full 4K screen with 8 pixel
character height. In the unlikely case it is not big enough we
just clamp the number of visible rows.

Diffstat:
Mos_unix.c | 46----------------------------------------------
Mplatform_linux_x11.c | 9++++-----
Mterminal.c | 21+++++++++++++++++++++
Mtest.c | 6++++--
Mutil.c | 27++++++++++++++++++---------
Mutil.h | 6+-----
Mvtgl.c | 12+++++++++---
7 files changed, 57 insertions(+), 70 deletions(-)

diff --git a/os_unix.c b/os_unix.c @@ -211,52 +211,6 @@ static PLATFORM_ALLOCATE_RING_BUFFER_FN(posix_allocate_ring_buffer) } static void -os_alloc_framebuffer(Framebuffer *fb, u32 rows, u32 cols) -{ - size pagesize = sysconf(_SC_PAGESIZE); - - size fb_needed_space = rows * cols * sizeof(Cell); - if (fb->cells_alloc_size < fb_needed_space) { - if (fb_needed_space % pagesize != 0) - fb_needed_space += pagesize - fb_needed_space % pagesize; - - Cell *new = mmap(0, fb_needed_space, PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); - /* TODO: properly handle this case */ - ASSERT(new != MAP_FAILED); - - if (fb->cells) - munmap(fb->cells, fb->cells_alloc_size); - - fb->cells = new; - fb->cells_alloc_size = fb_needed_space; - } - - size rows_needed_space = rows * sizeof(Row); - if (fb->rows_alloc_size < rows_needed_space) { - if (rows_needed_space % pagesize != 0) - rows_needed_space += pagesize - rows_needed_space % pagesize; - - Row *new = mmap(0, rows_needed_space, PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); - /* TODO: properly handle this case */ - ASSERT(new != MAP_FAILED); - - if (fb->rows) - munmap(fb->rows, fb->rows_alloc_size); - - fb->rows = new; - fb->rows_alloc_size = rows_needed_space; - } - - fb->cells_count = rows * cols; - fb->rows_count = rows; - - for (u32 i = 0; i < fb->rows_count; i++) - fb->rows[i] = fb->cells + i * cols; -} - -static void execsh(char *defcmd) { char *sh; diff --git a/platform_linux_x11.c b/platform_linux_x11.c @@ -376,19 +376,19 @@ i32 main(i32 argc, char *argv[], char *envp[]) { { - MemoryBlock terminal_memory = posix_alloc(16 * MEGABYTE); + MemoryBlock terminal_memory = posix_alloc(32 * MEGABYTE); linux_ctx.memory.memory = terminal_memory.memory; linux_ctx.memory.memory_size = terminal_memory.size; #ifdef _DEBUG - MemoryBlock debug_memory = posix_alloc(128 * MEGABYTE); + MemoryBlock debug_memory = posix_alloc(128 * MEGABYTE); linux_ctx.memory.debug_memory = debug_memory.memory; linux_ctx.memory.debug_memory_size = debug_memory.size; #endif } + linux_ctx.memory.platform_api.allocate_ring_buffer = posix_allocate_ring_buffer; linux_ctx.memory.platform_api.read = posix_read; linux_ctx.memory.platform_api.write = posix_write; - linux_ctx.memory.platform_api.allocate_ring_buffer = posix_allocate_ring_buffer; linux_ctx.memory.platform_api.get_file_stats = posix_get_file_stats; linux_ctx.memory.platform_api.read_file = posix_read_file; linux_ctx.memory.platform_api.get_clipboard = x11_get_clipboard; @@ -458,9 +458,8 @@ main(i32 argc, char *argv[], char *envp[]) GLFWmonitor *mon = glfwGetPrimaryMonitor(); if (!mon) { glfwTerminate(); - os_fatal(s8("Failed to get GLFW monitor\n")); + os_fatal(s8("Failed to find any monitors!\n")); } - iv2 monitor_size; glfwGetMonitorWorkarea(mon, NULL, NULL, &monitor_size.w, &monitor_size.h); diff --git a/terminal.c b/terminal.c @@ -8,6 +8,27 @@ static const u8 utf8overhangmask[32] = { #define SPLIT_LONG 4096L +static uv2 +initialize_framebuffer(Framebuffer *fb, uv2 term_size) +{ + size cell_memory_size = sizeof(Cell) * term_size.h * term_size.w; + size rows_memory_size = sizeof(Row) * term_size.h; + + /* NOTE: make sure cell memory size is a multiple of pointer size */ + cell_memory_size += (sizeof(void *) - cell_memory_size % sizeof(void *)); + + if (cell_memory_size + rows_memory_size >= fb->backing_store.size) + term_size.h = (fb->backing_store.size - cell_memory_size) / sizeof(Row); + + fb->cells = fb->backing_store.memory; + fb->rows = fb->backing_store.memory + cell_memory_size; + + for (i32 i = 0; i < term_size.h; i++) + fb->rows[i] = fb->cells + i * term_size.w; + + return term_size; +} + static Range get_word_around_cell(Term *t, iv2 cell) { diff --git a/test.c b/test.c @@ -374,8 +374,10 @@ main(void) /* TODO: should probably be some odd size */ term.size = (uv2){.w = 80, .h = 24}; - os_alloc_framebuffer(&term.views[0].fb, term.size.h, term.size.w); - os_alloc_framebuffer(&term.views[1].fb, term.size.h, term.size.w); + term.views[0].fb.backing_store = memory_block_from_arena(&memory, 2 * MEGABYTE); + term.views[1].fb.backing_store = memory_block_from_arena(&memory, 2 * MEGABYTE); + initialize_framebuffer(&term.views[0].fb, term.size); + initialize_framebuffer(&term.views[1].fb, term.size); u32 max_name_len = 0; #define X(name) if (sizeof(#name) - 1 > max_name_len) max_name_len = sizeof(#name) - 1; diff --git a/util.c b/util.c @@ -97,15 +97,6 @@ mem_clear(void *p_, u8 c, size len) return p; } -static Arena -arena_from_memory_block(MemoryBlock memory) -{ - Arena result; - result.beg = memory.memory; - result.end = memory.memory + memory.size; - return result; -} - #define alloc(a, t, n) (t *)alloc_(a, sizeof(t), _Alignof(t), n) static void * alloc_(Arena *a, size len, size align, size count) @@ -122,6 +113,24 @@ alloc_(Arena *a, size len, size align, size count) } static Arena +arena_from_memory_block(MemoryBlock memory) +{ + Arena result; + result.beg = memory.memory; + result.end = memory.memory + memory.size; + return result; +} + +static MemoryBlock +memory_block_from_arena(Arena *a, size requested_size) +{ + MemoryBlock result; + result.memory = alloc_(a, requested_size, 64, 1); + result.size = requested_size; + return result; +} + +static Arena sub_arena(Arena *a, size size) { Arena result = {0}; diff --git a/util.h b/util.h @@ -172,12 +172,8 @@ typedef Cell *Row; typedef struct { Cell *cells; - size cells_count; - size cells_alloc_size; - Row *rows; - size rows_count; - size rows_alloc_size; + MemoryBlock backing_store; } Framebuffer; /* NOTE: virtual memory ring buffer */ diff --git a/vtgl.c b/vtgl.c @@ -275,8 +275,8 @@ resize(Term *t, iv2 window_size) } if (!equal_uv2(old_size, t->size)) { - os_alloc_framebuffer(&t->views[0].fb, t->size.h, t->size.w); - os_alloc_framebuffer(&t->views[1].fb, t->size.h, t->size.w); + t->size = initialize_framebuffer(&t->views[0].fb, t->size); + initialize_framebuffer(&t->views[1].fb, t->size); gl->flags |= NEEDS_FULL_REFILL; u32 buffer_size = t->size.w * t->size.h * sizeof(RenderCell); @@ -961,6 +961,9 @@ DEBUG_EXPORT VTGL_INITIALIZE_FN(vtgl_initialize) memory->platform_api.allocate_ring_buffer(&t->views[1].log, ALT_BACKLOG_SIZE); line_buf_alloc(&t->views[1].lines, &a, t->views[1].log.buf, t->cursor.style, ALT_BACKLOG_LINES); + t->views[0].fb.backing_store = memory_block_from_arena(&a, 2 * MEGABYTE); + t->views[1].fb.backing_store = memory_block_from_arena(&a, 2 * MEGABYTE); + t->gl.glyph_bitmap_dim = monitor_size; init_fonts(&t->fa, &a, t->gl.glyph_bitmap_dim); selection_clear(&t->selection); @@ -970,6 +973,10 @@ DEBUG_EXPORT VTGL_INITIALIZE_FN(vtgl_initialize) .y = cs.y * requested_cells.y + 2 * g_term_margin.y, }; + t->size = (uv2){.x = 1, .y = 1}; + initialize_framebuffer(&t->views[0].fb, t->size); + initialize_framebuffer(&t->views[1].fb, t->size); + shader_reload_ctx *shader_ctxs = alloc(&a, shader_reload_ctx, SHADER_COUNT); s8 shader_infos[SHADER_COUNT] = { @@ -994,7 +1001,6 @@ DEBUG_EXPORT VTGL_INITIALIZE_FN(vtgl_initialize) a.beg = path.buf + path.widx; } - t->size = (uv2){.x = 1, .y = 1}; t->error_stream = stream_alloc(&a, MEGABYTE / 4); t->saved_title = stream_alloc(&a, 16 * KILOBYTE); t->arena_for_frame = a;