Commit: 157e7b8e182a21d809e6578a0a88f2ee4ebb021d
Parent: 5396fbf72d4e7ed0384f542a8e4a34b61514b015
Author: Randy Palamar
Date: Sat, 6 Jul 2024 16:25:19 -0600
use push buffer to reduce draw calls
Diffstat:
4 files changed, 90 insertions(+), 59 deletions(-)
diff --git a/frag_render.glsl b/frag_render.glsl
@@ -8,9 +8,9 @@ in VS_OUT {
} fs_in;
uniform sampler2DArray u_texslot;
-uniform int u_charmap[512];
-uniform vec2 u_texscale[512];
-uniform uvec2 u_texcolour[512];
+uniform int u_charmap[256];
+uniform vec2 u_texscale[256];
+uniform uvec2 u_texcolour[256];
void main()
{
diff --git a/util.h b/util.h
@@ -202,6 +202,17 @@ typedef struct {
Glyph *glyph_cache;
} GLCtx;
+/* NOTE: must match count in render shaders */
+#define PUSH_BUFFER_CAP 256
+typedef struct {
+ v2 vertscales[PUSH_BUFFER_CAP];
+ v2 vertoffsets[PUSH_BUFFER_CAP];
+ v2 texscales[PUSH_BUFFER_CAP];
+ uv2 texcolours[PUSH_BUFFER_CAP];
+ i32 charmap[PUSH_BUFFER_CAP];
+ u32 count;
+} RenderPushBuffer;
+
#include <ft2build.h>
#include FT_FREETYPE_H
#include "util.c"
diff --git a/vert_render.glsl b/vert_render.glsl
@@ -3,8 +3,8 @@
in vec2 position;
uniform mat4 u_Pmat;
-uniform vec2 u_vertscale[512];
-uniform vec2 u_vertoff[512];
+uniform vec2 u_vertscale[256];
+uniform vec2 u_vertoff[256];
out VS_OUT {
vec2 tex_coord;
diff --git a/vtgl.c b/vtgl.c
@@ -7,7 +7,7 @@
#include "util.h"
#define MAX_FONT_SIZE 128.0f
-#define TEXTURE_GLYPH_COUNT 128
+#define TEXTURE_GLYPH_COUNT PUSH_BUFFER_CAP
#define X(name) "u_"#name,
static char *render_uniform_names[] = { GL_RENDER_UNIFORMS };
@@ -118,19 +118,41 @@ measure_text(GLCtx *gl, s8 text, b32 monospaced)
}
static void
-push_char(GLCtx *gl, v2 vertscale, v2 vertoff, v2 texscale, uv2 colours, i32 char_idx)
+flush_render_push_buffer(RenderPushBuffer *rpb, GLCtx *gl)
{
- glUniform2uiv(gl->render.texcolour, 1, colours.E);
- glUniform1iv(gl->render.charmap, 1, &char_idx);
- glUniform2fv(gl->render.texscale, 1, texscale.E);
- glUniform2fv(gl->render.vertscale, 1, vertscale.E);
- glUniform2fv(gl->render.vertoff, 1, vertoff.E);
+ 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);
+ glUniform2uiv(gl->render.texcolour, rpb->count, (u32 *)rpb->texcolours);
+ glUniform1iv(gl->render.charmap, rpb->count, (i32 *)rpb->charmap);
+ glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, rpb->count);
+ rpb->count = 0;
+}
+
+static u32
+get_render_push_buffer_idx(RenderPushBuffer *rpb, GLCtx *gl, u32 count)
+{
+ if (rpb->count + count > PUSH_BUFFER_CAP)
+ flush_render_push_buffer(rpb, gl);
+ u32 result = rpb->count;
+ rpb->count += count;
+ return result;
+}
- glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
+static void
+push_char(RenderPushBuffer *rpb, GLCtx *gl, v2 vertscale, v2 vertoff, v2 texscale,
+ uv2 colours, i32 char_idx)
+{
+ u32 idx = get_render_push_buffer_idx(rpb, gl, 1);
+ rpb->vertscales[idx] = vertscale;
+ rpb->vertoffsets[idx] = vertoff;
+ rpb->texscales[idx] = texscale;
+ rpb->texcolours[idx] = colours;
+ rpb->charmap[idx] = char_idx;
}
static void
-push_empty_cell_rect(Term *t, u32 minrow, u32 maxrow, u32 mincol, u32 maxcol)
+push_empty_cell_rect(RenderPushBuffer *rpb, Term *t, u32 minrow, u32 maxrow, u32 mincol, u32 maxcol)
{
ASSERT(minrow <= maxrow && mincol <= maxcol);
ASSERT(maxrow <= t->size.h && maxcol <= t->size.w);
@@ -141,11 +163,11 @@ push_empty_cell_rect(Term *t, u32 minrow, u32 maxrow, u32 mincol, u32 maxcol)
/* TODO: global colour table */
Colour colour = {.r = 20, .g = 20, .b = 20, .a = 255};
- push_char(&t->gl, size, pos, (v2){0}, (uv2){.y = colour.rgba}, 0);
+ push_char(rpb, &t->gl, size, pos, (v2){0}, (uv2){.y = colour.rgba}, 0);
}
static void
-draw_text(GLCtx *gl, s8 text, v2 position, Colour colour, b32 monospaced)
+draw_text(RenderPushBuffer *rpb, GLCtx *gl, s8 text, v2 position, Colour colour, b32 monospaced)
{
f32 single_space_width = gl->glyph_cache[0].size.w;
for (size i = 0; i < text.len; i++) {
@@ -157,73 +179,63 @@ draw_text(GLCtx *gl, s8 text, v2 position, Colour colour, b32 monospaced)
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(gl, vertscale, vertoff, texscale, (uv2){.x = colour.rgba}, glyph_idx);
+ 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(GLCtx *gl, Rect r, Colour colour)
+draw_rectangle(RenderPushBuffer *rpb, GLCtx *gl, Rect r, Colour colour)
{
- push_char(gl, r.size, r.pos, (v2){0}, (uv2){.y = colour.rgba}, 0);
+ push_char(rpb, gl, r.size, r.pos, (v2){0}, (uv2){.y = colour.rgba}, 0);
}
static void
-push_cell(GLCtx *gl, Cell c, Rect r, f32 font_text_dy)
+push_cell(RenderPushBuffer *rpb, GLCtx *gl, Cell c, Rect r, f32 font_text_dy)
{
+ u32 idx = get_render_push_buffer_idx(rpb, gl, 2);
+
Glyph g;
i32 depth_idx = get_gpu_glyph_index(gl, c.cp, &g);
- v2 texscale[2];
- texscale[0] = (v2){0};
- texscale[1] = (v2){
+ rpb->vertscales[idx + 0] = r.size;
+ rpb->vertscales[idx + 1] = (v2){.x = g.size.w, .y = g.size.h};
+
+ rpb->vertoffsets[idx + 0] = r.pos;
+ rpb->vertoffsets[idx + 1] = (v2){
+ .x = r.pos.x + g.delta.x,
+ .y = r.pos.y + g.delta.y + font_text_dy,
+ };
+
+ rpb->texscales[idx] = (v2){0};
+ rpb->texscales[idx + 1] = (v2){
.x = g.size.w / MAX_FONT_SIZE,
.y = g.size.h / MAX_FONT_SIZE,
};
- i32 charmap[2];
- charmap[0] = depth_idx;
- charmap[1] = depth_idx;
-
- v2 vertscale[2];
- v2 vertoff[2];
- vertscale[0] = r.size;
- vertoff[0] = r.pos;
-
- v2 texture_position;
- texture_position.x = r.pos.x + g.delta.x;
- texture_position.y = r.pos.y + g.delta.y + font_text_dy;
-
- vertscale[1] = (v2){.x = g.size.w, .y = g.size.h};
- vertoff[1] = texture_position;
-
- u32 colours[4];
- colours[0] = (c.style.attr & ATTR_INVERSE)? c.style.bg.rgba : c.style.fg.rgba;
- colours[1] = (c.style.attr & ATTR_INVERSE)? c.style.fg.rgba : c.style.bg.rgba;
- colours[2] = (c.style.attr & ATTR_INVERSE)? c.style.bg.rgba : c.style.fg.rgba;
- colours[3] = (c.style.attr & ATTR_INVERSE)? c.style.fg.rgba : c.style.bg.rgba;
+ rpb->charmap[idx + 0] = depth_idx;
+ rpb->charmap[idx + 1] = depth_idx;
- if (c.style.attr & ATTR_FAINT)
- c.style.fg.a = 0.5 * 255;
+ CellStyle cs = c.style;
+ /* TODO: what should this be if the cell is inverse? */
+ if (cs.attr & ATTR_FAINT)
+ cs.fg.a = 0.5 * 255;
- glUniform2uiv(gl->render.texcolour, 2, colours);
- glUniform1iv(gl->render.charmap, 2, charmap);
- glUniform2fv(gl->render.texscale, 2, (f32 *)texscale);
- glUniform2fv(gl->render.vertscale, 2, (f32 *)vertscale);
- glUniform2fv(gl->render.vertoff, 2, (f32 *)vertoff);
-
- glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 2);
+ rpb->texcolours[idx + 0].x = (cs.attr & ATTR_INVERSE)? cs.bg.rgba : cs.fg.rgba;
+ rpb->texcolours[idx + 0].y = (cs.attr & ATTR_INVERSE)? cs.fg.rgba : cs.bg.rgba;
+ rpb->texcolours[idx + 1].x = (cs.attr & ATTR_INVERSE)? cs.bg.rgba : cs.fg.rgba;
+ rpb->texcolours[idx + 1].y = (cs.attr & ATTR_INVERSE)? cs.fg.rgba : cs.bg.rgba;
}
static void
-render_framebuffer(Term *t)
+render_framebuffer(Term *t, RenderPushBuffer *rpb)
{
v2 cs = get_cell_size(t);
Rect cr = {.pos = { .y = t->gl.window_size.h - cs.h }, .size = cs};
for (u32 r = 0; r < t->size.h; r++) {
for (u32 c = 0; c < t->size.w; c++) {
- push_cell(&t->gl, t->fb.rows[r][c], cr, t->fa.deltay);
+ push_cell(rpb, &t->gl, t->fb.rows[r][c], cr, t->fa.deltay);
cr.pos.x += cs.w;
}
cr.pos.x = 0;
@@ -322,11 +334,15 @@ init_callbacks(GLCtx *gl)
DEBUG_EXPORT void
do_terminal(Term *t, Arena a)
{
+ static f32 last_frame_time;
+ f32 frame_start_time = (f32)glfwGetTime();
if (t->gl.flags & UPDATE_RENDER_UNIFORMS)
update_uniforms(t, SHADER_RENDER);
if (t->gl.flags & UPDATE_POST_UNIFORMS)
update_uniforms(t, SHADER_POST);
+ RenderPushBuffer *rpb = alloc(&a, RenderPushBuffer, 1);
+
/* TODO: don't let the input splitting cause draw calls */
glUseProgram(t->gl.programs[SHADER_RENDER]);
@@ -356,7 +372,7 @@ do_terminal(Term *t, Arena a)
clear_colour();
blit_lines(t);
- render_framebuffer(t);
+ render_framebuffer(t, rpb);
v2 cell_size = get_cell_size(t);
v2 cursor_pos = {
@@ -374,7 +390,7 @@ do_terminal(Term *t, Arena a)
{
s8 fps = s8alloc(&a, 64);
- fps.len = snprintf((char *)fps.data, fps.len, "%0.01f ms/f", t->gl.dt * 1e3);
+ fps.len = snprintf((char *)fps.data, fps.len, "Render Time: %0.02f ms/f", last_frame_time * 1e3);
v2 ts = measure_text(&t->gl, fps, 1);
v2 pos = {
.x = ws.w - ts.x - 10,
@@ -386,10 +402,12 @@ do_terminal(Term *t, Arena a)
.size = {.w = ts.w * 1.1, .h = ts.h * 1.2},
};
- draw_rectangle(&t->gl, r, (Colour){.rgba = 0x303030ff});
- draw_text(&t->gl, fps, pos, (Colour){.rgba = 0x1e9e33ff}, 1);
+ draw_rectangle(rpb, &t->gl, r, (Colour){.rgba = 0x303030ff});
+ draw_text(rpb, &t->gl, fps, pos, (Colour){.rgba = 0x1e9e33ff}, 1);
}
+ flush_render_push_buffer(rpb, &t->gl);
+
static f32 param = 0;
static f32 p_scale = 1;
param += p_scale * 0.005 * t->gl.dt;
@@ -404,4 +422,6 @@ do_terminal(Term *t, Arena a)
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;
}