delay text rendering until end of frame which renders ALL text in one draw call

This commit is contained in:
2023-11-25 01:39:49 +02:00
parent 638c67a99e
commit 10f727cd28
8 changed files with 71 additions and 1974 deletions
-2
View File
@@ -1,4 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_DS_IMPLEMENTATION
#include "stb_ds.h"
-1895
View File
File diff suppressed because it is too large Load Diff
+5 -14
View File
@@ -59,14 +59,14 @@ void draw_win() {
/* set_height_constraint(&constraints, window.height, UI_CONSTRAINT_FIXED); */
Alignment align = ALIGN_TOP_LEFT;
int font_size = 84.0f;
int font_size = 72.0f;
Sizef text_size = calculate_text_size(win_text, font_size);
/* Sizef text_size = calculate_text_size(win_text, font_size); */
set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED);
set_y_constraint(&constraints, 0, UI_CONSTRAINT_FIXED);
set_width_constraint(&constraints, text_size.width, UI_CONSTRAINT_FIXED);
set_height_constraint(&constraints, text_size.height, UI_CONSTRAINT_FIXED);
/* set_width_constraint(&constraints, text_size.width, UI_CONSTRAINT_FIXED); */
/* set_height_constraint(&constraints, text_size.height, UI_CONSTRAINT_FIXED); */
/* set_rotation_constraint(&constraints, 0); */
/* UIConstraints circle_const; */
@@ -76,7 +76,7 @@ void draw_win() {
/* set_height_constraint(&circle_const, 90, UI_CONSTRAINT_FIXED); */
/* draw_circle(circle_const, NULL, ALIGN_LEFT_CENTER); */
draw_quad(constraints, &bg_color, 0.0, align);
/* draw_quad(constraints, &bg_color, 0.0, align); */
/* set_x_constraint(&constraints, -50, UI_CONSTRAINT_FIXED); */
/* draw_quad(constraints, &bg_color, 25.0, ALIGN_TOP_RIGHT); */
/* set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); */
@@ -89,15 +89,6 @@ void draw_win() {
set_height_constraint(&constraints, 1, UI_CONSTRAINT_FIXED);
/* set_rotation_constraint(&constraints, 0); */
draw_text(win_text, font_size, constraints, &text_color, align);
/* for (int i = 0; i < 100; i++) { */
/* int x = rand() % window.width; */
/* int y = rand() % window.height; */
/* set_x_constraint(&constraints, x, UI_CONSTRAINT_FIXED); */
/* set_y_constraint(&constraints, y, UI_CONSTRAINT_FIXED); */
/* draw_text(win_text, font_size, constraints, &text_color, align); */
/* } */
}
void set_scale_factor(int width, int height, float *x, float *y) {
+2
View File
@@ -203,6 +203,8 @@ int main(int argc, char *argv[]) {
/* float x = clampf(500.0f * timer_elapsed(&my_time), 0.0, window_size.width - size.width); */
/* draw_text("Bruh", 1.0f, (Vec2){0.0, size.height}, &(Color){255.f, 0.f, 0.f, 255.f}); */
zephr_batch_text_draw();
zephr_swap_buffers();
}
/* while (!quit) { */
+1 -1
View File
@@ -4,10 +4,10 @@ layout (location = 0) in vec2 vertex;
// per instance
layout (location = 1) in vec4 offset;
layout (location = 2) in int tex_index;
layout (location = 3) in mat4 model; // this takes locations 3,4,5,6
out vec2 v_TexCoords;
uniform mat4 projection;
uniform mat4 model;
// buffer for all the 96 ascii characters' texcoords
uniform vec2 texcoords[96 * 4];
+3 -16
View File
@@ -1,5 +1,6 @@
- maybe force the window to be a specific resolution
- border decorations for shapes
- "premade" (but also customizable) ui elements (buttons, text boxes, etc) with instanced rendering
- maybe force the window to be a specific resolution (for cudoku only? or all games?)
- border decorations for shapes (maybe. or maybe only for ui elements)
- remove the hardcoded 1920 and 1080 values when applying relative pixel constraints
and replace them with the screen's currently active resolution
@@ -28,17 +29,3 @@ text rendering improvements
instances of text in one draw call without exceeding any buffer limits. Of course this does mean that if we were to support
unicode we'd have to make the uniform array bigger and its size dynamic. So unicode is dropped for now
text tests / iGPU / Non-instaned rendering
- 10 texts / 72 font size
0.8-0.9ms per frame (1200-1300fps)
- 100 texts / 48 font size
1.2-1.3ms per frame (770-830fps)
- 1000 texts / 28 font size
9-9.5ms per frame (105-110fps)
- 10000 texts / 9 font size
80-85ms per frame (12-13fps)
+45 -45
View File
@@ -6,7 +6,6 @@
#include <freetype/ftmm.h>
#include <X11/Xlib.h>
#include <glad/glx.h>
#include <stb_ds.h>
#include "cudoku.h"
#include "shader.h"
@@ -19,11 +18,6 @@
Display *display;
Window window;
typedef struct InstanceData {
Vec4f position;
int tex_coords_index;
} InstanceData;
Context zephr_context;
Shader font_shader;
Shader ui_shader;
@@ -32,8 +26,6 @@ unsigned int ui_vao;
unsigned int font_instance_vbo;
unsigned int ui_vbo;
// TODO: instanced rendering of ui elements
int init_fonts(const char *font_path) {
FT_Library ft;
if (FT_Init_FreeType(&ft)) {
@@ -60,17 +52,10 @@ int init_fonts(const char *font_path) {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
/* uint max_dim = (1 + (face->size->metrics.height >> 6)) * ceilf(sqrtf(face->num_glyphs)); */
/* uint tex_width = 1; */
/* while (tex_width < max_dim) { */
/* tex_width <<= 1; */
/* } */
/* uint tex_height = tex_width; */
int pen_x = 0, pen_y = 0;
FT_UInt glyph_idx;
FT_ULong c = FT_Get_First_Char(face, &glyph_idx);
/* FT_UInt glyph_idx; */
/* FT_ULong c = FT_Get_First_Char(face, &glyph_idx); */
uint tex_width = 0, tex_height = 0;
for (uint i = 32; i < 128; i++) {
@@ -166,6 +151,9 @@ int init_ui(const char* font_path, Size window_size) {
zephr_context.window_size = window_size;
zephr_context.projection = orthographic_projection_2d(0.f, window_size.width, window_size.height, 0.f);
zephr_context.texts.instance_count = 0;
zephr_context.texts.instance_capacity = 16;
zephr_context.texts.instance_data = malloc(sizeof(TextInstance) * zephr_context.texts.instance_capacity);
int res = init_fonts(font_path);
if (res == -1) {
@@ -209,11 +197,23 @@ int init_ui(const char* font_path, Size window_size) {
// font instance vbo
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (void *)0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(TextInstance), (void *)0);
glVertexAttribDivisor(1, 1);
glEnableVertexAttribArray(2);
glVertexAttribIPointer(2, 1, GL_INT, sizeof(InstanceData), (void *)sizeof(Vec4f));
glVertexAttribIPointer(2, 1, GL_INT, sizeof(TextInstance), (void *)sizeof(Vec4f));
glVertexAttribDivisor(2, 1);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);
glEnableVertexAttribArray(6);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(TextInstance), (void *)(sizeof(Vec4f) + sizeof(int)));
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(TextInstance), (void *)(sizeof(Vec4f) * 2 + sizeof(int)));
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(TextInstance), (void *)(sizeof(Vec4f) * 3 + sizeof(int)));
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(TextInstance), (void *)(sizeof(Vec4f) * 4 + sizeof(int)));
glVertexAttribDivisor(3, 1);
glVertexAttribDivisor(4, 1);
glVertexAttribDivisor(5, 1);
glVertexAttribDivisor(6, 1);
// font ebo
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_ebo);
@@ -325,9 +325,17 @@ bool zephr_should_quit() {
// example of how to batch all text drawing in one drawcall
// this should be called at the end of the frame
/* void batch_text_draw(&zephr_context.texts) {
* do something with zephr_context.texts
}*/
void zephr_batch_text_draw() {
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(TextInstance) * zephr_context.texts.instance_count, zephr_context.texts.instance_data, GL_DYNAMIC_DRAW);
glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL, zephr_context.texts.instance_count);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
zephr_context.texts.instance_count = 0;
}
void zephr_swap_buffers() {
glXSwapBuffers(display, window);
@@ -621,8 +629,6 @@ void draw_text(const char* text, int font_size, UIConstraints constraints, Color
apply_translation(&model, pos);
set_mat4f(font_shader, "model", (float *)model.m);
int max_bearing_h = 0;
for (int i = 0; (i < text[i]) != '\0'; i++) {
Character ch = zephr_context.font.characters[(int)text[i]];
@@ -635,45 +641,39 @@ void draw_text(const char* text, int font_size, UIConstraints constraints, Color
glBindTexture(GL_TEXTURE_2D, zephr_context.font.atlas_texture_id);
glBindVertexArray(font_vao);
InstanceData* instance_data = malloc(sizeof(InstanceData) * strlen(text));
// we use the original text and character sizes in the loop and then we just
// scale up or down the model matrix to get the desired font size.
// this way everything works out fine and we get to transform the text using the
// model matrix
int c = 0;
int x = 0;
/* int line = 0; */
while (text[c] != '\0') {
Character ch = zephr_context.font.characters[(int)text[c]];
// subtract the bearing width of the first character to remove the extra space
// at the start of the text and move every char to the left by that width
float xpos = (x + (ch.bearing.width - first_char_bearing_w));
float ypos = /*(line * text_size.height) + */(text_size.height - ch.bearing.height - (text_size.height - max_bearing_h));
float ypos = (text_size.height - ch.bearing.height - (text_size.height - max_bearing_h));
/* if (text[c] == '\n') { */
/* line++; */
/* x = 0; */
/* c++; */
/* continue; */
/* } */
instance_data[c].position = (Vec4f){xpos, ypos, ch.size.width, ch.size.height};
instance_data[c].tex_coords_index = (int)text[c] - 32;
zephr_context.texts.instance_data[c + zephr_context.texts.instance_count].position = (Vec4f){xpos, ypos, ch.size.width, ch.size.height};
zephr_context.texts.instance_data[c + zephr_context.texts.instance_count].tex_coords_index = (int)text[c] - 32;
memcpy(zephr_context.texts.instance_data[c + zephr_context.texts.instance_count].model, model.m, sizeof(float[4][4]));
x += (ch.advance >> 6);
c++;
}
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(InstanceData) * strlen(text), instance_data, GL_DYNAMIC_DRAW);
zephr_context.texts.instance_count += strlen(text);
glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL, strlen(text));
free(instance_data);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
if (zephr_context.texts.instance_count >= zephr_context.texts.instance_capacity) {
zephr_context.texts.instance_capacity *= 2;
TextInstance* new_ptr = realloc(zephr_context.texts.instance_data, sizeof(TextInstance) * zephr_context.texts.instance_capacity);
if (!new_ptr) {
printf("Failed to reallocate memory for text instances\n");
exit(1);
} else {
zephr_context.texts.instance_data = new_ptr;
}
}
}
/* enum Element { */
+15 -1
View File
@@ -17,11 +17,24 @@ typedef struct ZephFont {
unsigned int atlas_texture_id;
} ZephFont;
typedef struct {
typedef struct TextInstance {
Vec4f position;
int tex_coords_index;
float model[4][4];
} TextInstance;
typedef struct Text {
TextInstance *instance_data;
int instance_count;
int instance_capacity;
} Text;
typedef struct Context {
bool should_quit;
Color clear_color;
Size window_size;
ZephFont font;
Text texts;
Matrix4x4 projection;
} Context;
@@ -58,6 +71,7 @@ void deinit_zephr();
bool zephr_should_quit();
void zephr_swap_buffers();
Size zephr_get_window_size();
void zephr_batch_text_draw();
void set_x_constraint(UIConstraints *constraints, float value, UIConstraint type);
void set_y_constraint(UIConstraints *constraints, float value, UIConstraint type);
void set_width_constraint(UIConstraints *constraints, float value, UIConstraint type);