vtgl

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

Commit: c1a10af51ff1c0eff85d48a6bdd2d9a46e94d4ad
Parent: 9cd19ebbaa828415dbbe2b6ed9d202fe3379b95f
Author: Randy Palamar
Date:   Sun, 22 Sep 2024 03:28:19 -0600

debug cycle counts and debug overlay

just press F12 in debug mode

Diffstat:
Mconfig.def.h | 4++++
Mdebug.c | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adebug.h | 36++++++++++++++++++++++++++++++++++++
Mfont.c | 24++++++++++++++----------
Mmain.c | 8+++++---
Mterminal.c | 13+++++++++++--
Mutil.h | 39++++++++++++++++++++++++---------------
Mvtgl.c | 113+++++++++++++++++++++++--------------------------------------------------------
8 files changed, 281 insertions(+), 111 deletions(-)

diff --git a/config.def.h b/config.def.h @@ -8,6 +8,10 @@ static FontDesc g_fonts[][FS_LAST] = { }, }; +#ifdef _DEBUG +static FontDesc g_debug_font_desc = {.path = "/usr/share/fonts/gofont/Go-Mono-Bold.ttf", .height = 18}; +#endif + /* NOTE: terminal padding in pixels */ static v2 g_term_pad = {.w = 8, .h = 8}; /* NOTE: cell padding in pixels (glyphs will be centered) */ diff --git a/debug.c b/debug.c @@ -137,3 +137,158 @@ dump_glyph_cache_to_file(FontAtlas *fa) fclose(f); } + +#define MAX_DEBUG_FONT_SIZE 32.0 +static void +debug_init(Term *t, Arena a) +{ + Font *f = &t->debug_font; + init_font(f, &g_debug_font_desc); + + glGenTextures(1, &t->debug_glyph_texture); + glActiveTexture(GL_TEXTURE0 + 1); + glBindTexture(GL_TEXTURE_2D_ARRAY, t->debug_glyph_texture); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, MAX_DEBUG_FONT_SIZE, MAX_DEBUG_FONT_SIZE, + ARRAY_COUNT(t->debug_glyphs), 0, GL_RED, GL_UNSIGNED_BYTE, 0); + + /* NOTE: calculate glyph sizes and upload rendered glyph to GPU */ + f32 scale = f->stbtt_scale; + for (u32 i = ' '; i < 0x7F; i++) { + Arena tmp = a; + i32 x0, y0, x1, y1; + i32 glyph_idx = stbtt_FindGlyphIndex(&f->font_info, i); + stbtt_GetGlyphBitmapBoxSubpixel(&f->font_info, glyph_idx, scale, scale, 0, 0, + &x0, &y0, &x1, &y1); + Glyph *g = t->debug_glyphs + i - ' '; + g->size.w = x1 - x0; + g->size.h = y1 - y0; + g->delta.x = x0; + g->delta.y = -y1; + + u8 *render_buf = alloc(&tmp, u8, g->size.w * g->size.h); + stbtt_MakeGlyphBitmapSubpixel(tmp, &f->font_info, render_buf, g->size.w, g->size.h, + g->size.w, scale, scale, 0, 0, glyph_idx); + + u32 *rgba_bitmap = alloc(&tmp, u32, g->size.w * g->size.h); + for (u32 i = 0; i < g->size.h; i++) + for (u32 j = 0; j < g->size.w; j++) + rgba_bitmap[i * g->size.w + j] = (u32)(render_buf[i * g->size.w + j]) << 24; + + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i - ' ', g->size.w, g->size.h, 1, + GL_RGBA, GL_UNSIGNED_BYTE, rgba_bitmap); + } + + glActiveTexture(GL_TEXTURE0); + + i32 x0, x1, y0, y1; + stbtt_GetFontBoundingBox(&t->debug_font.font_info, &x0, &y0, &x1, &y1); + t->debug_glyphs[0].size.w = scale * (x1 - x0) + 0.5; +} + +static void draw_rectangle(RenderPushBuffer *rpb, GLCtx *gl, Rect r, Colour colour); +static void push_char(RenderPushBuffer *rpb, GLCtx *gl, v2 vertscale, v2 vertoff, v2 texscale, + uv2 colours, i32 char_idx); + +static v2 +debug_measure_text(Term *t, Font *f, s8 text, b32 monospaced) +{ + v2 result = {0}; + f32 single_space_width = t->debug_glyphs[0].size.w; + for (size i = 0; i < text.len; i++) { + Glyph g = t->debug_glyphs[text.data[i] - ' ']; + /* TODO: should we consider offset characters in y? */ + if (g.size.h > result.y) + result.y = g.size.h; + result.x += monospaced? single_space_width : g.size.w; + } + return result; +} + +static void +debug_draw_text(Term *t, RenderPushBuffer *rpb, s8 text, v2 position, Colour colour, b32 monospaced) +{ + f32 single_space_width = t->debug_glyphs[0].size.w; + for (size i = 0; i < text.len; i++) { + i32 glyph_idx = text.data[i] - ' '; + Glyph g = t->debug_glyphs[glyph_idx]; + v2 texscale = {.x = g.size.w / MAX_DEBUG_FONT_SIZE, .y = g.size.h / MAX_DEBUG_FONT_SIZE}; + v2 vertscale = {.x = g.size.w, .y = g.size.h}; + v2 vertoff = {.x = position.x + g.delta.x, .y = position.y + g.delta.y}; + push_char(rpb, &t->gl, vertscale, vertoff, texscale, (uv2){.x = colour.rgba}, glyph_idx); + position.x += monospaced? single_space_width : g.size.w; + } +} + +static void +draw_debug_overlay(Term *t, RenderPushBuffer *rpb) +{ + static struct { + char *line1, *line2; + } fmts[CC_LAST] = { + [CC_RENDER_FRAMEBUFFER] = {.line1 = "Render FB: %ld cyc | %d hit", + .line2 = " %0.2f cyc/h\n"}, + [CC_RENDER_GLYPH] = {.line1 = "Render Glyph: %ld cyc | %d hit", + .line2 = " %0.2f cyc/h\n"}, + [CC_BLIT_LINES] = {.line1 = "Blit Lines: %ld cyc | %d hit", + .line2 = " %0.2f cyc/h\n"}, + [CC_SPLIT_LINES] = {.line1 = "Split Lines: %ld cyc | %d hit", + .line2 = " %0.2f cyc/h\n"}, + }; + + static i64 cycs[CC_LAST]; + static i64 hits[CC_LAST]; + + for (u32 i = 0; i < CC_LAST; i++) { + if (g_debug_clock_counts.total_cycles[i] == 0) + continue; + cycs[i] = g_debug_clock_counts.total_cycles[i]; + hits[i] = g_debug_clock_counts.hit_count[i]; + g_debug_clock_counts.hit_count[i] = 0; + g_debug_clock_counts.total_cycles[i] = 0; + } + + if (!(t->gl.flags & DRAW_DEBUG_OVERLAY)) + return; + + glUniform1i(t->gl.render.texslot, 1); + + v2 ws = t->gl.window_size; + s8 buf = s8alloc(&t->arena_for_frame, 128); + static Rect r; + r.pos.x = 0.8 * ws.w; + r.size.x = 0.2 * ws.w; + + draw_rectangle(rpb, &t->gl, r, (Colour){.rgba = 0x222222ff}); + + f32 line_pad = 5; + v2 txt_pos = {.x = (u32)(r.pos.x + 5), .y = ws.h}; + + { + s8 txt = buf; + txt.len = snprintf((char *)txt.data, buf.len, "Render Time: %0.02f ms/f", dt_for_frame * 1e3); + v2 ts = debug_measure_text(t, &t->debug_font, txt, 1); + txt_pos.y = (u32)(txt_pos.y - ts.y - line_pad); + debug_draw_text(t, rpb, txt, txt_pos, (Colour){.rgba = 0x1e9e33ff}, 1); + } + + for (u32 i = 0; i < CC_LAST; i++) { + if (hits[i] == 0) + continue; + s8 txt = buf; + txt.len = snprintf((char *)txt.data, buf.len, fmts[i].line1, cycs[i], hits[i]); + v2 ts = debug_measure_text(t, &t->debug_font, txt, 1); + txt_pos.y = (u32)(txt_pos.y - ts.y - line_pad); + debug_draw_text(t, rpb, txt, txt_pos, (Colour){.rgba = 0x1e9e33ff}, 1); + + txt.len = snprintf((char *)txt.data, buf.len, fmts[i].line2, (f32)cycs[i]/(f32)hits[i]); + ts = debug_measure_text(t, &t->debug_font, txt, 1); + txt_pos.y = (u32)(txt_pos.y - ts.y - line_pad); + debug_draw_text(t, rpb, txt, txt_pos, (Colour){.rgba = 0x1e9e33ff}, 1); + } + r.pos.y = txt_pos.y - 2 * line_pad; + r.size.y = ws.h - r.pos.y; +} diff --git a/debug.h b/debug.h @@ -0,0 +1,36 @@ +#ifndef _DEBUG +#define ASSERT(c) do { (void)(c); } while(0) +#define DEBUG_EXPORT static + +#define BEGIN_CYCLE_COUNT(a) +#define END_CYCLE_COUNT(a) + +#else + +#define ASSERT(c) do { if (!(c)) asm("int3; nop"); } while(0) +#define DEBUG_EXPORT + +/* NOTE: Performance Counters */ +enum clock_counts { + CC_RENDER_FRAMEBUFFER, + CC_RENDER_GLYPH, + CC_BLIT_LINES, + CC_SPLIT_LINES, + CC_LAST +}; + +static struct { + i64 cpu_cycles[CC_LAST]; + i64 total_cycles[CC_LAST]; + i64 hit_count[CC_LAST]; +} g_debug_clock_counts; + +#define BEGIN_CYCLE_COUNT(cc_name) \ + g_debug_clock_counts.cpu_cycles[cc_name] = __rdtsc(); \ + g_debug_clock_counts.hit_count[cc_name]++ + +#define END_CYCLE_COUNT(cc_name) \ + g_debug_clock_counts.cpu_cycles[cc_name] = __rdtsc() - g_debug_clock_counts.cpu_cycles[cc_name]; \ + g_debug_clock_counts.total_cycles[cc_name] += g_debug_clock_counts.cpu_cycles[cc_name] + +#endif diff --git a/font.c b/font.c @@ -1,6 +1,6 @@ /* See LICENSE for copyright details */ static void -init_font(FontAtlas *fa, Font *f, FontDesc *fdesc) +init_font(Font *f, FontDesc *fdesc) { os_mapped_file map = os_map_file(fdesc->path, OS_MAP_READ, OS_MAP_PRIVATE); @@ -122,6 +122,8 @@ get_and_clear_glyph_cache_stats(GlyphCache *gc) static u32 * render_glyph(Arena *a, FontAtlas *fa, u32 cp, enum face_style style, CachedGlyph **out_glyph, u32 *out_idx) { + BEGIN_CYCLE_COUNT(CC_RENDER_GLYPH); + /* NOTE: first check if glyph is in the cache and valid */ /* NOTE: 8 MSB are not used for UTF8 so we can use that to store the style of the glyph */ u32 idx = get_glyph_entry_index(&fa->glyph_cache, cp|(1 << (30 - style))); @@ -175,20 +177,22 @@ render_glyph(Arena *a, FontAtlas *fa, u32 cp, enum face_style style, CachedGlyph } /* NOTE: ' ' has 0 size in freetype but we need it to have a width! */ - if (cp == ' ') cg->g.size.w = fa->size.w; + if (cp == ' ') cg->g.size.w = fa->info.w; + + END_CYCLE_COUNT(CC_RENDER_GLYPH); return rgba_bitmap; } static void -update_font_metrics(FontAtlas *fa) +update_font_metrics(Font *font, FontInfo *info) { i32 x0, x1, y0, y1; - stbtt_GetFontBoundingBox(&fa->fonts[0][FS_NORMAL].font_info, &x0, &y0, &x1, &y1); - f32 scale = fa->fonts[0][FS_NORMAL].stbtt_scale; - fa->size.h = scale * (y1 - y0) + 0.5; - fa->size.w = scale * (x1 - x0) + 0.5; - fa->baseline = -scale * y0 + 0.5; + stbtt_GetFontBoundingBox(&font->font_info, &x0, &y0, &x1, &y1); + f32 scale = font->stbtt_scale; + info->h = scale * (y1 - y0) + 0.5; + info->w = scale * (x1 - x0) + 0.5; + info->baseline = -scale * y0 + 0.5; } static void @@ -200,7 +204,7 @@ font_atlas_update(FontAtlas *fa) for(u32 i = 0; i < gc->cache_len - 1; i++) gc->glyphs[i].next_with_same_hash = i + 1; get_and_clear_glyph_cache_stats(gc); - update_font_metrics(fa); + update_font_metrics(&fa->fonts[0][FS_NORMAL], &fa->info); } static i32 @@ -231,7 +235,7 @@ init_fonts(Term *t, Arena *a) for (u32 i = 0; i < FS_LAST; i++) { if (!g_fonts[fa->nfonts][i].path) continue; - init_font(fa, &fa->fonts[fa->nfonts][i], &g_fonts[fa->nfonts][i]); + init_font(&fa->fonts[fa->nfonts][i], &g_fonts[fa->nfonts][i]); } } diff --git a/main.c b/main.c @@ -20,7 +20,7 @@ static char *libname = "./vtgl.so"; static void *libhandle; -typedef void do_terminal_fn(Term *); +typedef void do_terminal_fn(Term *, f32); static do_terminal_fn *do_terminal; typedef void init_callbacks_fn(GLCtx *); @@ -190,6 +190,8 @@ init_window(Term *t, Arena arena, iv2 requested_size) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, t->gl.fb_tex, 0); + + t->gl.flags |= INIT_DEBUG; } static u32 @@ -350,13 +352,13 @@ main(i32 argc, char *argv[]) check_shaders(&term.gl, memory); f32 current_time = (f32)glfwGetTime(); - term.gl.dt = current_time - last_time; + f32 dt = current_time - last_time; last_time = current_time; term.arena_for_frame = memory; glfwPollEvents(); - do_terminal(&term); + do_terminal(&term, dt); glfwSwapBuffers(term.gl.window); } diff --git a/terminal.c b/terminal.c @@ -1,5 +1,4 @@ -#include <immintrin.h> - +/* See LICENSE for copyright details */ static const u8 utf8overhangmask[32] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -1005,6 +1004,8 @@ check_if_escape_moves_cursor(Term *t, s8 *raw) static size split_raw_input_to_lines(Term *t, s8 raw) { + BEGIN_CYCLE_COUNT(CC_SPLIT_LINES); + TermView *tv = t->views + t->view_idx; size parsed_lines = 0; __m128i nl = _mm_set1_epi8('\n'); @@ -1096,6 +1097,9 @@ split_raw_input_to_lines(Term *t, s8 raw) } } t->unprocessed_bytes = 0; + + END_CYCLE_COUNT(CC_SPLIT_LINES); + return parsed_lines; } @@ -1138,6 +1142,7 @@ push_line(Term *t, Line *line, Arena a) width = 1; } + /* NOTE: make this '>=' for fun in vis */ if (t->cursor.pos.x + width > t->size.w) { /* NOTE: make space for character if mode enabled else * clobber whatever was on the end of the line */ @@ -1182,6 +1187,8 @@ get_line_idx(LineBuf *lb, size off) static void blit_lines(Term *t, Arena a, size line_count) { + BEGIN_CYCLE_COUNT(CC_BLIT_LINES); + TermView *tv = t->views + t->view_idx; if (t->gl.flags & NEEDS_FULL_REFILL) { @@ -1204,4 +1211,6 @@ blit_lines(Term *t, Arena a, size line_count) t->gl.flags &= ~(NEEDS_FULL_REFILL|NEEDS_REFILL); t->gl.flags |= NEEDS_BLIT; + + END_CYCLE_COUNT(CC_BLIT_LINES); } diff --git a/util.h b/util.h @@ -5,18 +5,12 @@ #include <stdint.h> #include <stddef.h> +#include <immintrin.h> + #ifndef asm #define asm __asm__ #endif -#ifdef _DEBUG -#define ASSERT(c) do { if (!(c)) asm("int3; nop"); } while(0) -#define DEBUG_EXPORT -#else -#define ASSERT(c) do { (void)(c); } while(0) -#define DEBUG_EXPORT static -#endif - #ifndef static_assert #define static_assert _Static_assert #endif @@ -51,11 +45,12 @@ typedef float f32; typedef double f64; typedef int8_t i8; typedef uint8_t u8; -typedef uint16_t u16; typedef int16_t i16; +typedef uint16_t u16; typedef int32_t i32; typedef uint32_t u32; typedef uint32_t b32; +typedef int64_t i64; typedef uint64_t u64; typedef ptrdiff_t size; @@ -99,6 +94,8 @@ typedef struct { size len; u8 *data; } s8; typedef struct { iv2 start, end; } Range; #define INVALID_RANGE_END (iv2){.x = -1, .y = -1} +#include "debug.h" + enum cell_attribute { ATTR_NULL = 0, ATTR_BOLD = 1 << 0, @@ -203,8 +200,10 @@ enum gl_flags { NEEDS_REFILL = 1 << 2, NEEDS_FULL_REFILL = 1 << 3, - UPDATE_RENDER_UNIFORMS = 1 << 29, - UPDATE_POST_UNIFORMS = 1 << 30, + UPDATE_RENDER_UNIFORMS = 1 << 27, + UPDATE_POST_UNIFORMS = 1 << 28, + INIT_DEBUG = 1 << 29, + DRAW_DEBUG_OVERLAY = 1 << 30, }; enum win_mode { @@ -225,8 +224,6 @@ typedef struct { GLFWwindow *window; v2 window_size; - f32 dt; - u32 vao, vbo; u32 fb, fb_tex, fb_tex_unit; @@ -306,6 +303,11 @@ typedef struct { typedef Font FontFamily[FS_LAST]; +typedef struct { + u32 h, w; + i32 baseline; +} FontInfo; + #define GLYPH_CACHE_LEN PUSH_BUFFER_CAP typedef struct { /* distance to shift glyph from bounding box origin */ @@ -338,8 +340,7 @@ typedef struct { typedef struct { FontFamily *fonts; u32 nfonts; - uv2 size; - i32 baseline; + FontInfo info; GlyphCache glyph_cache; } FontAtlas; @@ -418,6 +419,14 @@ typedef struct { enum terminal_mode mode; char saved_title[1024]; + + #ifdef _DEBUG + Font debug_font; + Glyph debug_glyphs[0x7F - 0x20]; + u32 debug_glyph_texture; + #endif } Term; +static f32 dt_for_frame; + #endif /* _UTIL_H_ */ diff --git a/vtgl.c b/vtgl.c @@ -11,6 +11,9 @@ #include "terminal.c" #ifdef _DEBUG #include "debug.c" +#else +#define debug_init(...) +#define draw_debug_overlay(...) #endif #define REVERSE_VIDEO_MASK (Colour){.r = 0xff, .g = 0xff, .b = 0xff}.rgba @@ -64,7 +67,7 @@ set_projection_matrix(GLCtx *gl) static v2 get_cell_size(Term *t) { - v2 result = {.w = t->fa.size.w + g_cell_pad.w, .h = t->fa.size.h + g_cell_pad.h}; + v2 result = {.w = t->fa.info.w + g_cell_pad.w, .h = t->fa.info.h + g_cell_pad.h}; return result; } @@ -189,26 +192,11 @@ get_gpu_glyph_index(Arena a, FontAtlas *fa, u32 codepoint, enum face_style style return depth_idx; } -static v2 -measure_text(Arena a, FontAtlas *fa, s8 text, b32 monospaced) -{ - v2 result = {0}; - Glyph g; - get_gpu_glyph_index(a, fa, ' ', FS_NORMAL, &g); - f32 single_space_width = g.size.w; - for (size i = 0; i < text.len; i++) { - get_gpu_glyph_index(a, fa, text.data[i], FS_NORMAL, &g); - /* TODO: should we consider offset characters in y? */ - if (g.size.h > result.y) - result.y = g.size.h; - result.x += monospaced? single_space_width : g.size.w; - } - return result; -} - static void flush_render_push_buffer(RenderPushBuffer *rpb, GLCtx *gl) { + if (rpb->count == 0) + return; glUniform2fv(gl->render.vertscale, rpb->count, (f32 *)rpb->vertscales); glUniform2fv(gl->render.vertoff, rpb->count, (f32 *)rpb->vertoffsets); glUniform2fv(gl->render.texscale, rpb->count, (f32 *)rpb->texscales); @@ -255,23 +243,6 @@ push_empty_cell_rect(RenderPushBuffer *rpb, Term *t, u32 minrow, u32 maxrow, u32 } static void -draw_text(RenderPushBuffer *rpb, GLCtx *gl, Arena a, FontAtlas *fa, s8 text, v2 position, Colour colour, b32 monospaced) -{ - Glyph g; - get_gpu_glyph_index(a, fa, ' ', FS_NORMAL, &g); - f32 single_space_width = g.size.w; - for (size i = 0; i < text.len; i++) { - u32 cp = text.data[i]; - i32 glyph_idx = get_gpu_glyph_index(a, fa, cp, FS_NORMAL, &g); - v2 texscale = {.x = g.size.w / MAX_FONT_SIZE, .y = g.size.h / MAX_FONT_SIZE}; - v2 vertscale = {.x = g.size.w, .y = g.size.h}; - v2 vertoff = {.x = position.x + g.delta.x, .y = position.y + g.delta.y}; - push_char(rpb, gl, vertscale, vertoff, texscale, (uv2){.x = colour.rgba}, glyph_idx); - position.x += monospaced? single_space_width : g.size.w; - } -} - -static void draw_rectangle(RenderPushBuffer *rpb, GLCtx *gl, Rect r, Colour colour) { push_char(rpb, gl, r.size, r.pos, (v2){0}, (uv2){.y = colour.rgba}, 0); @@ -355,12 +326,14 @@ push_cell_row(RenderPushBuffer *rpb, GLCtx *gl, Arena a, FontAtlas *fa, Cell *ro static void render_framebuffer(Term *t, RenderPushBuffer *rpb) { + BEGIN_CYCLE_COUNT(CC_RENDER_FRAMEBUFFER); + v2 tl = get_terminal_top_left(t); v2 cs = get_cell_size(t); Rect cr = {.pos = {.x = tl.x, .y = tl.y - cs.h}, .size = cs}; v2 cell_font_delta = get_cell_pad_off(); - cell_font_delta.y += t->fa.baseline; + cell_font_delta.y += t->fa.info.baseline; TermView *tv = t->views + t->view_idx; /* NOTE: draw whole framebuffer */ @@ -405,6 +378,8 @@ render_framebuffer(Term *t, RenderPushBuffer *rpb) cursor.style.attr ^= ATTR_INVERSE; push_cell(rpb, &t->gl, t->arena_for_frame, &t->fa, cursor, cr, cell_font_delta); } + + END_CYCLE_COUNT(CC_RENDER_FRAMEBUFFER); } static iv2 @@ -429,7 +404,7 @@ update_selection(Term *t) Selection *sel = &t->selection; b32 held = glfwGetMouseButton(t->gl.window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS; - sel->click_param -= t->gl.dt; + sel->click_param -= dt_for_frame; if (sel->click_param < 0) { sel->click_param = 0; if (!held) @@ -610,6 +585,11 @@ key_callback(GLFWwindow *win, i32 key, i32 sc, i32 act, i32 mods) dump_glyph_cache_to_file(&t->fa); return; } + if (key == GLFW_KEY_F12 && act == GLFW_PRESS) { + t->gl.flags ^= DRAW_DEBUG_OVERLAY; + t->gl.flags |= NEEDS_BLIT; + return; + } #endif /* NOTE: handle mapped keybindings */ @@ -796,10 +776,9 @@ init_callbacks(GLCtx *gl) } DEBUG_EXPORT void -do_terminal(Term *t) +do_terminal(Term *t, f32 dt) { - static f32 last_frame_time; - f32 frame_start_time = (f32)glfwGetTime(); + dt_for_frame = dt; if (t->gl.flags & UPDATE_RENDER_UNIFORMS) update_uniforms(t, SHADER_RENDER); @@ -809,6 +788,11 @@ do_terminal(Term *t) if (t->gl.flags & NEEDS_RESIZE) resize(t); + if (t->gl.flags & INIT_DEBUG) { + debug_init(t, t->arena_for_frame); + t->gl.flags &= ~INIT_DEBUG; + } + size parsed_lines = 0; if (os_child_data_available(t->child)) { RingBuf *rb = &t->views[t->view_idx].log; @@ -832,66 +816,33 @@ do_terminal(Term *t) update_selection(t); - v2 ws = t->gl.window_size; - + RenderPushBuffer *rpb = alloc(&t->arena_for_frame, RenderPushBuffer, 1); + glUseProgram(t->gl.programs[SHADER_RENDER]); + glBindFramebuffer(GL_FRAMEBUFFER, t->gl.fb); if (t->gl.flags & NEEDS_BLIT) { - glUseProgram(t->gl.programs[SHADER_RENDER]); glUniform1i(t->gl.render.texslot, 0); - glBindFramebuffer(GL_FRAMEBUFFER, t->gl.fb); - - RenderPushBuffer *rpb = alloc(&t->arena_for_frame, RenderPushBuffer, 1); clear_colour(t->gl.mode & WIN_MODE_REVERSE); render_framebuffer(t, rpb); - - if (0) { - v2 cell_size = get_cell_size(t); - v2 cursor_pos = { - .x = t->cursor.pos.x * cell_size.w, - .y = ws.h - cell_size.h * (t->cursor.pos.y + 1), - }; - - v2 src_bl = {0}; - v2 src_tr = {.x = ws.w, .y = src_bl.y + ws.h}; - - if (t->cursor.pos.y > t->size.h) { - src_tr.y = cursor_pos.y + ws.h; - src_bl.y = cursor_pos.y; - } - - s8 fps = s8alloc(&t->arena_for_frame, 64); - fps.len = snprintf((char *)fps.data, fps.len, "Render Time: %0.02f ms/f", - last_frame_time * 1e3); - v2 ts = measure_text(t->arena_for_frame, &t->fa, fps, 1); - v2 pos = {.x = ws.w - ts.x - 10, .y = src_tr.y - ts.y - 10}; - - Rect r = { - .pos = {.x = pos.x - 0.05 * ts.x, .y = pos.y - 0.25 * ts.y}, - .size = {.w = ts.w * 1.1, .h = ts.h * 1.2}, - }; - - draw_rectangle(rpb, &t->gl, r, (Colour){.rgba = 0x303030ff}); - draw_text(rpb, &t->gl, t->arena_for_frame, &t->fa, fps, pos, - (Colour){.rgba = 0x1e9e33ff}, 1); - } - flush_render_push_buffer(rpb, &t->gl); t->gl.flags &= ~NEEDS_BLIT; } + draw_debug_overlay(t, rpb); + flush_render_push_buffer(rpb, &t->gl); static f32 param = 0; static f32 p_scale = 1; - param += p_scale * 0.005 * t->gl.dt; + param += p_scale * 0.005 * dt_for_frame; if (param > 1.0f || param < 0) p_scale *= -1.0f; glBindFramebuffer(GL_FRAMEBUFFER, 0); + v2 ws = t->gl.window_size; + clear_colour(t->gl.mode & WIN_MODE_REVERSE); glUseProgram(t->gl.programs[SHADER_POST]); glUniform1i(t->gl.post.texslot, t->gl.fb_tex_unit); glUniform1f(t->gl.post.param, param); glUniform2fv(t->gl.post.vertscale, 1, (f32 []){ws.w, ws.h}); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - last_frame_time = (f32)glfwGetTime() - frame_start_time; }