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:
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