vtgl

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

Commit: 60fa5e65f199607d3edda83635fc75f7906201c7
Parent: 841511e052f412d9738758c36f15d59b4973e431
Author: Randy Palamar
Date:   Wed, 23 Oct 2024 09:40:17 -0600

group render parameters into a RenderCtx struct

Diffstat:
Mterminal.c | 1+
Mutil.c | 9+++++++++
Mutil.h | 16++++++++--------
Mvtgl.c | 92+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
4 files changed, 71 insertions(+), 47 deletions(-)

diff --git a/terminal.c b/terminal.c @@ -174,6 +174,7 @@ fb_clear_region(Term *t, u32 r1, u32 r2, u32 c1, u32 c2) for (u32 c = c1; c <= c2; c++) { tv->fb.rows[r][c].style = t->cursor.style; tv->fb.rows[r][c].cp = ' '; + /* TODO: this shouldn't be in this loop; make a region intersection test */ if (is_selected(&t->selection, c, r)) selection_clear(&t->selection); } diff --git a/util.c b/util.c @@ -84,6 +84,15 @@ alloc_(Arena *a, size len, size align, size count) return mem_clear(p, 0, count * len); } +static Arena +make_arena(Arena *a, size size) +{ + Arena result; + result.beg = alloc_(a, size, 64, 1); + result.end = result.beg + size; + return result; +} + /* NOTE: This performs wrapping of the ring buffer as needed; since a line could be in * progress this must also adjust the start and end of the current line */ static void diff --git a/util.h b/util.h @@ -266,7 +266,7 @@ typedef struct { /* TODO: try different sizes; largely depends on how many things we want to batch together */ #define RENDER_PUSH_BUFFER_CAP 8192 -typedef struct { +typedef __attribute__((aligned(64))) struct { v2 positions[RENDER_PUSH_BUFFER_CAP]; v2 texture_coordinates[RENDER_PUSH_BUFFER_CAP]; v4 colours[RENDER_PUSH_BUFFER_CAP]; @@ -327,13 +327,6 @@ typedef struct { } FontInfo; typedef struct { - /* distance to shift glyph from bounding box origin */ - iv2 delta; - /* rendered glyph bitmap data (pixels) */ - uv2 size; -} Glyph; - -typedef struct { u32 cp; u32 next_with_same_hash; u32 prev; @@ -423,6 +416,13 @@ enum terminal_mode { }; typedef struct { + RenderPushBuffer *rpb; + GLCtx *gl; + FontAtlas *fa; + Arena a; +} RenderCtx; + +typedef struct { GLCtx gl; FontAtlas fa; diff --git a/vtgl.c b/vtgl.c @@ -14,7 +14,7 @@ static u32 get_gpu_glyph_index(Arena, GLCtx *, FontAtlas *, u32, u32, enum face_ #ifdef _DEBUG #include "debug.c" -static void draw_debug_overlay(Term *, RenderPushBuffer *); +static void draw_debug_overlay(Term *, RenderCtx *); #endif #define REVERSE_VIDEO_MASK (Colour){.r = 0xff, .g = 0xff, .b = 0xff}.rgba @@ -139,6 +139,17 @@ update_uniforms(Term *t, enum shader_stages stage) } } +static RenderCtx +make_render_ctx(Arena *a, GLCtx *gl, FontAtlas *fa) +{ + RenderCtx result; + result.gl = gl; + result.fa = fa; + result.rpb = alloc(a, RenderPushBuffer, 1); + result.a = make_arena(a, 4 * MEGABYTE); + return result; +} + static iv2 get_gpu_texture_position(v2 cs, u32 gpu_tile_index) { @@ -171,10 +182,12 @@ get_gpu_glyph_index(Arena a, GLCtx *gl, FontAtlas *fa, u32 codepoint, u32 font_i /* NOTE: this function assumes we are drawing quads */ static void -flush_render_push_buffer(RenderPushBuffer *rpb, GLCtx *gl) +flush_render_push_buffer(RenderCtx *rc) { - if (rpb->count > 0) { - u32 n = rpb->count; + if (rc->rpb->count > 0) { + u32 n = rc->rpb->count; + GLCtx *gl = rc->gl; + RenderPushBuffer *rpb = rc->rpb; ASSERT((n % 4) == 0); glBindBuffer(GL_ARRAY_BUFFER, gl->vbos[0]); @@ -186,26 +199,27 @@ flush_render_push_buffer(RenderPushBuffer *rpb, GLCtx *gl) glDrawElements(GL_TRIANGLES, 6 * n / 4, GL_UNSIGNED_INT, 0); } - rpb->count = 0; + rc->rpb->count = 0; } static u32 -get_render_push_buffer_idx(RenderPushBuffer *rpb, GLCtx *gl, u32 count) +get_render_push_buffer_idx(RenderCtx *rc, u32 count) { - if (rpb->count + count > RENDER_PUSH_BUFFER_CAP) - flush_render_push_buffer(rpb, gl); - u32 result = rpb->count; - rpb->count += count; + if (rc->rpb->count + count > RENDER_PUSH_BUFFER_CAP) + flush_render_push_buffer(rc); + u32 result = rc->rpb->count; + rc->rpb->count += count; return result; } static void -push_rect_full(RenderPushBuffer *rpb, GLCtx *gl, Rect r, v4 colour, v2 min_tex_coord, v2 max_tex_coord) +push_rect_full(RenderCtx *rc, Rect r, v4 colour, v2 min_tex_coord, v2 max_tex_coord) { - u32 idx = get_render_push_buffer_idx(rpb, gl, 4); + u32 idx = get_render_push_buffer_idx(rc, 4); v2 start = r.pos; v2 end = {.x = r.pos.x + r.size.w, .y = r.pos.y + r.size.h}; + RenderPushBuffer *rpb = rc->rpb; rpb->positions[idx + 0] = (v2){.x = end.x, .y = end.y }; rpb->positions[idx + 1] = (v2){.x = end.x, .y = start.y}; rpb->positions[idx + 2] = (v2){.x = start.x, .y = start.y}; @@ -223,7 +237,7 @@ push_rect_full(RenderPushBuffer *rpb, GLCtx *gl, Rect r, v4 colour, v2 min_tex_c } static void -push_rect_textured(RenderPushBuffer *rpb, GLCtx *gl, Rect r, v4 colour, b32 flip_texture) +push_rect_textured(RenderCtx *rc, Rect r, v4 colour, b32 flip_texture) { v2 min_tex_coord, max_tex_coord; if (!flip_texture) { @@ -233,37 +247,37 @@ push_rect_textured(RenderPushBuffer *rpb, GLCtx *gl, Rect r, v4 colour, b32 flip max_tex_coord = (v2){.x = 1.0f, .y = 0.0f}; min_tex_coord = (v2){.x = 0.0f, .y = 1.0f}; } - push_rect_full(rpb, gl, r, colour, min_tex_coord, max_tex_coord); + push_rect_full(rc, r, colour, min_tex_coord, max_tex_coord); } static void -push_rect(RenderPushBuffer *rpb, GLCtx *gl, Rect r, v4 colour) +push_rect(RenderCtx *rc, Rect r, v4 colour) { - f32 max_x = 1.0f / gl->glyph_bitmap_dim.x; - f32 max_y = 1.0f / gl->glyph_bitmap_dim.y; - push_rect_full(rpb, gl, r, colour, (v2){0}, (v2){.x = max_x, .y = max_y}); + f32 max_x = 1.0f / rc->gl->glyph_bitmap_dim.x; + f32 max_y = 1.0f / rc->gl->glyph_bitmap_dim.y; + push_rect_full(rc, r, colour, (v2){0}, (v2){.x = max_x, .y = max_y}); } static v2 -push_s8(RenderPushBuffer *rpb, Arena a, GLCtx *gl, FontAtlas *fa, v2 pos, v4 colour, u32 font_id, s8 s) +push_s8(RenderCtx *rc, v2 pos, v4 colour, u32 font_id, s8 s) { CachedGlyph *cg; v2 start, end, text_size = {0}; - v2 scale = {.x = 1.0f / gl->glyph_bitmap_dim.x, .y = 1.0f / gl->glyph_bitmap_dim.y}; + v2 scale = {.x = 1.0f / rc->gl->glyph_bitmap_dim.x, .y = 1.0f / rc->gl->glyph_bitmap_dim.y}; while (s.len) { u32 cp = get_utf8(&s); if (cp == (u32)-1) break; - get_gpu_glyph_index(a, gl, fa, cp, font_id, FS_NORMAL, &cg); - cached_glyph_to_uv(fa, cg, &start, &end, scale); + get_gpu_glyph_index(rc->a, rc->gl, rc->fa, cp, font_id, FS_NORMAL, &cg); + cached_glyph_to_uv(rc->fa, cg, &start, &end, scale); Rect r = {.pos = pos, .size = {.x = cg->width, .y = cg->height}}; r.pos.x += cg->x0; r.pos.y -= (cg->height + cg->y0); - push_rect_full(rpb, gl, r, colour, start, end); + push_rect_full(rc, r, colour, start, end); text_size.x += cg->advance; pos.x += cg->advance; @@ -277,7 +291,7 @@ push_s8(RenderPushBuffer *rpb, Arena a, GLCtx *gl, FontAtlas *fa, v2 pos, v4 col } static v2 -measure_text(Arena a, GLCtx *gl, FontAtlas *fa, u32 font_id, s8 text) +measure_text(RenderCtx *rc, u32 font_id, s8 text) { v2 result = {0}; @@ -287,7 +301,7 @@ measure_text(Arena a, GLCtx *gl, FontAtlas *fa, u32 font_id, s8 text) cp = get_utf8(&text); if (cp == (u32)-1) break; - get_gpu_glyph_index(a, gl, fa, cp, font_id, FS_NORMAL, &cg); + get_gpu_glyph_index(rc->a, rc->gl, rc->fa, cp, font_id, FS_NORMAL, &cg); if (cg->height > result.y) result.y = cg->height; result.x += cg->advance; @@ -842,7 +856,7 @@ do_terminal(Term *t, f32 dt) set_projection_matrix(&t->gl); - RenderPushBuffer *rpb = alloc(&t->arena_for_frame, RenderPushBuffer, 1); + RenderCtx rc = make_render_ctx(&t->arena_for_frame, &t->gl, &t->fa); glUseProgram(t->gl.programs[SHADER_RENDER]); glBindFramebuffer(GL_FRAMEBUFFER, t->gl.fb); @@ -871,8 +885,8 @@ do_terminal(Term *t, f32 dt) glBindBufferBase(GL_UNIFORM_BUFFER, 0, t->gl.render_shader_ubo); glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(*sp), sp); - push_rect_textured(rpb, &t->gl, (Rect){.size = t->gl.window_size}, (v4){0}, 0); - flush_render_push_buffer(rpb, &t->gl); + push_rect_textured(&rc, (Rect){.size = t->gl.window_size}, (v4){0}, 0); + flush_render_push_buffer(&rc); static f32 param = 0; static f32 p_scale = 1; @@ -887,8 +901,8 @@ do_terminal(Term *t, f32 dt) glUniform1i(t->gl.post.texslot, t->gl.fb_tex_unit); glUniform1f(t->gl.post.param, param); - push_rect_textured(rpb, &t->gl, (Rect){.size = t->gl.window_size}, (v4){0}, 1); - flush_render_push_buffer(rpb, &t->gl); + push_rect_textured(&rc, (Rect){.size = t->gl.window_size}, (v4){0}, 1); + flush_render_push_buffer(&rc); /* TODO: update debug info at the start of the frame so that this function can * be properly included */ @@ -897,15 +911,15 @@ do_terminal(Term *t, f32 dt) /* NOTE: this happens at the end so that ui stuff doesn't go through the post * processing/effects shader */ glUseProgram(t->gl.programs[SHADER_RECTS]); - draw_debug_overlay(t, rpb); - flush_render_push_buffer(rpb, &t->gl); + draw_debug_overlay(t, &rc); + flush_render_push_buffer(&rc); } #ifdef _DEBUG DebugRecord debug_records[__COUNTER__]; static void -draw_debug_overlay(Term *t, RenderPushBuffer *rpb) +draw_debug_overlay(Term *t, RenderCtx *rc) { static u64 cycs[ARRAY_COUNT(debug_records)]; static u32 hits[ARRAY_COUNT(debug_records)]; @@ -936,7 +950,7 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) v4 fg = normalize_colour((Colour){.rgba = 0x1e9e33ff}); v4 bg = normalize_colour((Colour){.rgba = 0x090909bf}); - push_rect(rpb, &t->gl, r, bg); + push_rect(rc, r, bg); u32 font_id = g_ui_debug_font_id; f32 line_pad = 5; @@ -945,9 +959,9 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) { s8 txt = buf; txt.len = snprintf((char *)txt.data, buf.len, "Render Time: %0.02f ms/f", dt_for_frame * 1e3); - v2 ts = measure_text(t->arena_for_frame, &t->gl, &t->fa, font_id, txt); + v2 ts = measure_text(rc, font_id, txt); txt_pos.y = (u32)(txt_pos.y - ts.h - line_pad); - push_s8(rpb, t->arena_for_frame, &t->gl, &t->fa, txt_pos, fg, font_id, txt); + push_s8(rc, txt_pos, fg, font_id, txt); if (ts.w > max_text_width) max_text_width = ts.w; if (ts.h > line_height) line_height = ts.h; @@ -964,7 +978,7 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) dr->function_name, hits[i], hits[i] > 1? "hits" : "hit", (f32)cycs[i]/(f32)hits[i]); txt_pos.y = (u32)(txt_pos.y - line_height - line_pad); - v2 ts = push_s8(rpb, t->arena_for_frame, &t->gl, &t->fa, txt_pos, fg, font_id, txt); + v2 ts = push_s8(rc, txt_pos, fg, font_id, txt); if (ts.w > max_text_width) max_text_width = ts.w; if (ts.h > line_height) line_height = ts.h; @@ -976,7 +990,7 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) { s8 header = s8("Glyph Cache Stats:"); txt_pos.y = (u32)(txt_pos.y - line_height - line_pad); - v2 ts = push_s8(rpb, t->arena_for_frame, &t->gl, &t->fa, txt_pos, fg, font_id, header); + v2 ts = push_s8(rc, txt_pos, fg, font_id, header); /* TODO: This doesn't really work when we are redrawing on every frame */ static char *fmts[ARRAY_COUNT(glyph_stats.E)] = { @@ -988,7 +1002,7 @@ draw_debug_overlay(Term *t, RenderPushBuffer *rpb) s8 txt = buf; txt.len = snprintf((char *)txt.data, buf.len, fmts[i], glyph_stats.E[i]); txt_pos.y = (u32)(txt_pos.y - line_height - line_pad); - ts = push_s8(rpb, t->arena_for_frame, &t->gl, &t->fa, txt_pos, fg, font_id, txt); + ts = push_s8(rc, txt_pos, fg, font_id, txt); if (ts.w > max_text_width) max_text_width = ts.w; if (ts.h > line_height) line_height = ts.h;