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:
M | config.def.h | | | 4 | ++++ |
M | debug.c | | | 155 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | debug.h | | | 36 | ++++++++++++++++++++++++++++++++++++ |
M | font.c | | | 24 | ++++++++++++++---------- |
M | main.c | | | 8 | +++++--- |
M | terminal.c | | | 13 | +++++++++++-- |
M | util.h | | | 39 | ++++++++++++++++++++++++--------------- |
M | vtgl.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;
}