vtgl

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

Commit: 8bf48859b5e39e7bce1c9bd8260621863c0c71f6
Parent: eefea3d75f758700c76af83c46e742684a7e927d
Author: Randy Palamar
Date:   Mon, 21 Oct 2024 21:44:40 -0600

set up pipeline for drawing more arbitray rectangles

Diffstat:
Mfrag_post.glsl | 6++++--
Mfrag_render.glsl | 7+++++--
Mmain.c | 45++++++++++++++++++++++++++++++++++-----------
Mutil.h | 26++++++++++----------------
Mvert_for_rects.glsl | 22+++++++++++-----------
Mvtgl.c | 72+++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
6 files changed, 119 insertions(+), 59 deletions(-)

diff --git a/frag_post.glsl b/frag_post.glsl @@ -1,7 +1,8 @@ #version 430 core -layout(location = 0) in vec2 pixel_coord; -layout(location = 1) in vec2 texture_coord; +layout(location = 0) in vec2 fragment_pixel_coordinate; +layout(location = 1) in vec2 fragment_texture_coordinate; +layout(location = 2) in vec4 fragment_colour; layout(location = 0) out vec4 colour; @@ -10,6 +11,7 @@ layout(location = 4) uniform float u_param; void main() { + vec2 texture_coord = fragment_texture_coordinate; //if (mod(tex_coord.y + u_param, 0.005) < 0.0005) { if (false) { vec4 tint = vec4(0.1, 0.1, 0.1, 1); diff --git a/frag_render.glsl b/frag_render.glsl @@ -1,7 +1,8 @@ #version 430 core -layout(location = 0) in vec2 pixel_coord; -layout(location = 1) in vec2 texture_coord; +layout(location = 0) in vec2 fragment_pixel_coordinate; +layout(location = 1) in vec2 fragment_texture_coordinate; +layout(location = 2) in vec4 fragment_colour; layout(location = 0) out vec4 colour; @@ -51,6 +52,8 @@ unpack_glyph_position(uint glyph_position) void main() { + vec2 pixel_coord = fragment_pixel_coordinate; + uvec2 cell_index = uvec2((pixel_coord - top_left_margin) / cell_size); vec2 cell_pos = mod((pixel_coord - top_left_margin), cell_size); diff --git a/main.c b/main.c @@ -129,18 +129,40 @@ init_window(Term *t, Arena arena, iv2 window_size) glGenVertexArrays(1, &t->gl.vao); glBindVertexArray(t->gl.vao); - glGenBuffers(1, &t->gl.vbo); - glBindBuffer(GL_ARRAY_BUFFER, t->gl.vbo); - - f32 verts[] = { - 0.0f, 1.0f, - 0.0f, 0.0f, - 1.0f, 1.0f, - 1.0f, 0.0f, - }; + glGenBuffers(ARRAY_COUNT(t->gl.vbos), t->gl.vbos); + + RenderPushBuffer *rpb = NULL; + /* NOTE: vertex position buffer */ + glBindBuffer(GL_ARRAY_BUFFER, t->gl.vbos[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(rpb->positions), 0, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); - glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); + glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, 0); + + /* NOTE: vertex texture coordinate buffer */ + glBindBuffer(GL_ARRAY_BUFFER, t->gl.vbos[1]); + glBufferData(GL_ARRAY_BUFFER, sizeof(rpb->texture_coordinates), 0, GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0); + + /* NOTE: vertex colour buffer */ + glBindBuffer(GL_ARRAY_BUFFER, t->gl.vbos[2]); + glBufferData(GL_ARRAY_BUFFER, sizeof(rpb->colours), 0, GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 4, GL_FLOAT, 0, 0, 0); + + /* NOTE: fill in element index buffer */ + i32 *element_indices = alloc(&arena, i32, 6 * ARRAY_COUNT(rpb->positions)); + for (i32 i = 0, j = 0; i < 6 * ARRAY_COUNT(rpb->positions); i += 6, j++) { + element_indices[i + 0] = 4 * j; + element_indices[i + 1] = 4 * j + 1; + element_indices[i + 2] = 4 * j + 2; + element_indices[i + 3] = 4 * j; + element_indices[i + 4] = 4 * j + 2; + element_indices[i + 5] = 4 * j + 3; + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, t->gl.vbos[4]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * ARRAY_COUNT(rpb->positions) * sizeof(i32), + element_indices, GL_STATIC_DRAW); glGenTextures(1, &t->gl.glyph_bitmap_tex); glBindTexture(GL_TEXTURE_2D, t->gl.glyph_bitmap_tex); @@ -215,6 +237,7 @@ program_from_shader_text(s8 vertex, s8 fragment, Arena a) u32 fid = compile_shader(a, GL_FRAGMENT_SHADER, fragment); if (fid == 0) { + glDeleteShader(vid); glDeleteProgram(pid); return 0; } diff --git a/util.h b/util.h @@ -184,14 +184,12 @@ typedef struct { } TermView; #define GL_RENDER_UNIFORMS \ - X(Pmat) \ - X(vertscale) + X(Pmat) #define GL_POST_UNIFORMS \ X(Pmat) \ X(param) \ - X(texslot) \ - X(vertscale) + X(texslot) enum gl_flags { NEEDS_RESIZE = 1 << 0, @@ -242,7 +240,7 @@ typedef struct { GLFWwindow *window; v2 window_size; - u32 vao, vbo; + u32 vao, vbos[5]; u32 fb, fb_tex, fb_tex_unit; @@ -275,21 +273,17 @@ typedef struct { u32 bg; } RenderCell; -/* NOTE: This must match the number in the shaders & the number glyphs in - * the gpu glyph cache. By doing this we ensure that filling a single push buffer - * will not evict a needed glyph texture from the GPU */ -#define PUSH_BUFFER_CAP 512 +/* TODO: try different sizes; largely depends on how many things we want to batch together */ +#define RENDER_PUSH_BUFFER_CAP 8192 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]; + v2 positions[RENDER_PUSH_BUFFER_CAP]; + v2 texture_coordinates[RENDER_PUSH_BUFFER_CAP]; + v4 colours[RENDER_PUSH_BUFFER_CAP]; u32 count; } RenderPushBuffer; -#define MIN_FONT_SIZE 8 -#define MAX_FONT_SIZE 128 +#define MIN_FONT_SIZE 8 +#define MAX_FONT_SIZE 128 enum conversion_status { CR_FAILURE, CR_SUCCESS }; struct conversion_result { diff --git a/vert_for_rects.glsl b/vert_for_rects.glsl @@ -1,21 +1,21 @@ #version 430 core -layout(location = 0) in vec2 position; +layout(location = 0) in vec2 vertex_position; +layout(location = 1) in vec2 vertex_texture_coordinate; +layout(location = 2) in vec4 vertex_colour; -layout(location = 0) out vec2 pixel_coord; -layout(location = 1) out vec2 texture_coord; +layout(location = 0) out vec2 fragment_pixel_coordinate; +layout(location = 1) out vec2 fragment_texture_coordinate; +layout(location = 2) out vec4 fragment_colour; +layout(location = 3) out flat int fragment_texture_index; layout(location = 0) uniform mat4 u_Pmat; -layout(location = 1) uniform vec2 u_vertscale; void main() { - vec2 pos = position.xy; - vec2 scale = u_vertscale; + fragment_texture_coordinate = vertex_texture_coordinate; + fragment_pixel_coordinate = vertex_position * vertex_texture_coordinate; + fragment_colour = vertex_colour; - texture_coord = pos; - pixel_coord = pos; - pixel_coord.y = 1 - pixel_coord.y; - pixel_coord *= scale; - gl_Position = u_Pmat * vec4(pos * scale, 0.0, 1.0); + gl_Position = u_Pmat * vec4(vertex_position, 0.0, 1.0); } diff --git a/vtgl.c b/vtgl.c @@ -176,25 +176,30 @@ get_gpu_glyph_index(Arena a, GLCtx *gl, FontAtlas *fa, u32 codepoint, enum face_ return cg->gpu_tile_index; } -#if 0 +/* NOTE: this function assumes we are drawing quads */ 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); - 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); + if (rpb->count > 0) { + u32 n = rpb->count; + ASSERT((n % 4) == 0); + + glBindBuffer(GL_ARRAY_BUFFER, gl->vbos[0]); + glBufferSubData(GL_ARRAY_BUFFER, 0, n * sizeof(*rpb->positions), rpb->positions); + glBindBuffer(GL_ARRAY_BUFFER, gl->vbos[1]); + glBufferSubData(GL_ARRAY_BUFFER, 0, n * sizeof(*rpb->texture_coordinates), rpb->texture_coordinates); + glBindBuffer(GL_ARRAY_BUFFER, gl->vbos[2]); + glBufferSubData(GL_ARRAY_BUFFER, 0, n * sizeof(*rpb->colours), rpb->colours); + + glDrawElements(GL_TRIANGLES, 6 * n / 4, GL_UNSIGNED_INT, 0); + } rpb->count = 0; } static u32 get_render_push_buffer_idx(RenderPushBuffer *rpb, GLCtx *gl, u32 count) { - if (rpb->count + count > PUSH_BUFFER_CAP) + if (rpb->count + count > RENDER_PUSH_BUFFER_CAP) flush_render_push_buffer(rpb, gl); u32 result = rpb->count; rpb->count += count; @@ -202,6 +207,39 @@ get_render_push_buffer_idx(RenderPushBuffer *rpb, GLCtx *gl, u32 count) } static void +push_rect(RenderPushBuffer *rpb, GLCtx *gl, Rect r, v4 colour, b32 flip_texture) +{ + u32 idx = get_render_push_buffer_idx(rpb, gl, 4); + v2 start = r.pos; + v2 end = {.x = r.pos.x + r.size.w, .y = r.pos.y + r.size.h}; + + 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}; + rpb->positions[idx + 3] = (v2){.x = start.x, .y = end.y }; + + /* TODO: cleanup */ + if (!flip_texture) { + rpb->texture_coordinates[idx + 0] = (v2){.x = 1.0f, .y = 1.0f}; + rpb->texture_coordinates[idx + 1] = (v2){.x = 1.0f, .y = 0.0f}; + rpb->texture_coordinates[idx + 2] = (v2){.x = 0.0f, .y = 0.0f}; + rpb->texture_coordinates[idx + 3] = (v2){.x = 0.0f, .y = 1.0f}; + } else { + rpb->texture_coordinates[idx + 0] = (v2){.x = 1.0f, .y = 0.0f}; + rpb->texture_coordinates[idx + 1] = (v2){.x = 1.0f, .y = 1.0f}; + rpb->texture_coordinates[idx + 2] = (v2){.x = 0.0f, .y = 1.0f}; + rpb->texture_coordinates[idx + 3] = (v2){.x = 0.0f, .y = 0.0f}; + } + + rpb->colours[idx + 0] = colour; + rpb->colours[idx + 1] = colour; + rpb->colours[idx + 2] = colour; + rpb->colours[idx + 3] = colour; +} + +#if 0 + +static void push_char(RenderPushBuffer *rpb, GLCtx *gl, v2 vertscale, v2 vertoff, v2 texscale, uv2 colours, i32 char_idx) { @@ -771,6 +809,8 @@ do_terminal(Term *t, f32 dt) update_selection(t); + RenderPushBuffer *rpb = alloc(&t->arena_for_frame, RenderPushBuffer, 1); + glUseProgram(t->gl.programs[SHADER_RENDER]); glBindFramebuffer(GL_FRAMEBUFFER, t->gl.fb); clear_colour(t->gl.mode & WIN_MODE_REVERSE); @@ -794,13 +834,12 @@ do_terminal(Term *t, f32 dt) sp->underline_min = (0.89 * t->fa.info.h); sp->underline_max = (0.96 * t->fa.info.h); - glUniform2fv(t->gl.render.vertscale, 1, t->gl.window_size.E); - glBindBuffer(GL_UNIFORM_BUFFER, t->gl.render_shader_ubo); glBindBufferBase(GL_UNIFORM_BUFFER, 0, t->gl.render_shader_ubo); glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(*sp), sp); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + push_rect(rpb, &t->gl, (Rect){.size = t->gl.window_size}, (v4){0}, 0); + flush_render_push_buffer(rpb, &t->gl); static f32 param = 0; static f32 p_scale = 1; @@ -810,14 +849,13 @@ do_terminal(Term *t, f32 dt) 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, ws.E); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + push_rect(rpb, &t->gl, (Rect){.size = t->gl.window_size}, (v4){0}, 1); + flush_render_push_buffer(rpb, &t->gl); } #ifdef _DEBUG