From a7c42f249db817a18516e35bc76e01941032d886 Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Sat, 28 Mar 2026 16:22:38 +0800 Subject: [PATCH] perf: optimize text rendering performance --- include/Cubed/config.hpp | 2 +- include/Cubed/tools/font.hpp | 9 ++- src/renderer.cpp | 3 +- src/shaders/text_f_shader.glsl | 10 ++-- src/shaders/text_v_shader.glsl | 12 ++-- src/tools/font.cpp | 100 +++++++++++++++++++++------------ 6 files changed, 89 insertions(+), 47 deletions(-) diff --git a/include/Cubed/config.hpp b/include/Cubed/config.hpp index c63c3f7..596a77a 100644 --- a/include/Cubed/config.hpp +++ b/include/Cubed/config.hpp @@ -8,7 +8,7 @@ constexpr int MAX_UI_NUM = 1; constexpr int CHUCK_SIZE = 16; constexpr int DISTANCE = 8; constexpr int MAX_BLOCK_STATUS = 1; - +constexpr int MAX_CHARACTER = 128; constexpr float FOV = 70.0f; constexpr float VERTICES_POS[6][6][3] = { diff --git a/include/Cubed/tools/font.hpp b/include/Cubed/tools/font.hpp index 7a69bd4..3a0fee5 100644 --- a/include/Cubed/tools/font.hpp +++ b/include/Cubed/tools/font.hpp @@ -9,7 +9,8 @@ #include struct Character { - GLuint texture_id; + glm::vec2 uv_min; + glm::vec2 uv_max; glm::ivec2 size; glm::ivec2 bearing; GLuint advance; @@ -20,12 +21,16 @@ public: Font(); ~Font(); - static void render_text(GLuint program, GLuint vbo, const std::string& text, float x, float y, float scale, const glm::vec3& color); + static void render_text(GLuint program, const std::string& text, float x, float y, float scale, const glm::vec3& color); private: FT_Library m_ft; FT_Face m_face; + float m_texture_width = 64; + float m_texture_height = 64; + + GLuint m_text_texture; std::unordered_map m_characters; void load_character(char8_t c); diff --git a/src/renderer.cpp b/src/renderer.cpp index 8b27d68..84806fc 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -187,7 +187,8 @@ void Renderer::render_text() { m_proj_loc = glGetUniformLocation(m_text_program, "projection"); glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_ui_proj)); - Font::render_text(m_text_program, m_text_vbo, std::string{"fps" + std::to_string(static_cast(App::get_fps()))}, 0.0f, 50.0f, 1.0f, glm::vec3(1.0f, 1.0f, 1.0f)); + Font::render_text(m_text_program, std::string{"FPS: " + std::to_string(static_cast(App::get_fps()))}, 0.0f, 50.0f, 1.0f, glm::vec3(1.0f, 1.0f, 1.0f)); + Font::render_text(m_text_program, "Version: v0.0.1-Debug", 0.0f, 100.0f, 0.8f, glm::vec3(1.0f, 1.0f, 1.0f)); glEnable(GL_DEPTH_TEST); } diff --git a/src/shaders/text_f_shader.glsl b/src/shaders/text_f_shader.glsl index 3756dd4..08a88f5 100644 --- a/src/shaders/text_f_shader.glsl +++ b/src/shaders/text_f_shader.glsl @@ -1,12 +1,14 @@ #version 460 -in vec2 texCoord; -out vec4 color; +in vec2 tc; +flat in int tex_layer; -layout (binding = 0) uniform sampler2D text; +layout (binding = 0) uniform sampler2DArray text; uniform vec3 textColor; +out vec4 color; + void main(void) { - vec4 smapled = vec4(1.0, 1.0, 1.0, texture(text, texCoord).r); + vec4 smapled = vec4(1.0, 1.0, 1.0, texture(text, vec3(tc, tex_layer)).r); color = vec4(textColor, 1.0) * smapled; } \ No newline at end of file diff --git a/src/shaders/text_v_shader.glsl b/src/shaders/text_v_shader.glsl index 60d2663..d9d8d16 100644 --- a/src/shaders/text_v_shader.glsl +++ b/src/shaders/text_v_shader.glsl @@ -1,11 +1,15 @@ #version 460 -layout (location = 0) in vec4 vertex; -out vec2 texCoord; +layout (location = 0) in vec2 pos; +layout (location = 1) in vec2 texCoord; +layout (location = 2) in float layer; +out vec2 tc; +flat out int tex_layer; uniform mat4 projection; void main(void) { - gl_Position = projection * vec4(vertex.xy, 0.0, 1.0); - texCoord = vec2(vertex.zw); + gl_Position = projection * vec4(pos, 0.0, 1.0); + tc = texCoord; + tex_layer = int(layer); } \ No newline at end of file diff --git a/src/tools/font.cpp b/src/tools/font.cpp index 175880c..3da5b66 100644 --- a/src/tools/font.cpp +++ b/src/tools/font.cpp @@ -1,5 +1,4 @@ - - +#include #include #include @@ -24,7 +23,7 @@ Font::~Font() { FT_Done_Face(m_face); FT_Done_FreeType(m_ft); for (const auto& [key, character] : m_characters) { - glDeleteTextures(1, &character.texture_id); + glDeleteTextures(1, &m_text_texture); } } @@ -33,27 +32,25 @@ void Font::load_character(char8_t c) { LOG::error("FREETYTPE: Failed to load Glyph"); return; } - GLuint texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexImage2D( - GL_TEXTURE_2D, + const auto& width = m_face->glyph->bitmap.width; + const auto& height = m_face->glyph->bitmap.rows; + glTexSubImage3D( + GL_TEXTURE_2D_ARRAY, 0, - GL_RED, - m_face->glyph->bitmap.width, - m_face->glyph->bitmap.rows, 0, + 0, + static_cast(c), + width, + height, + 1, GL_RED, GL_UNSIGNED_BYTE, m_face->glyph->bitmap.buffer ); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); Character character = { - texture, + glm::vec2{0.0f, 0.0f}, + glm::vec2{static_cast(width) / m_texture_width, static_cast(height) / m_texture_height}, glm::ivec2(m_face->glyph->bitmap.width, m_face->glyph->bitmap.rows), glm::ivec2(m_face->glyph->bitmap_left, m_face->glyph->bitmap_top), static_cast(m_face->glyph->advance.x) @@ -63,19 +60,44 @@ void Font::load_character(char8_t c) { } void Font::setup_font_character() { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glGenTextures(1, &m_text_texture); + glBindTexture(GL_TEXTURE_2D_ARRAY, m_text_texture); + glTexImage3D( + GL_TEXTURE_2D_ARRAY, + 0, + GL_RED, + m_texture_width, + m_texture_height, + MAX_CHARACTER, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + nullptr + ); + for (char8_t c = 0; c < 128; c++) { load_character(c); } + + 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); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); } -void Font::render_text(GLuint program, GLuint vbo, const std::string& text, float x, float y, float scale, const glm::vec3& color) { +void Font::render_text(GLuint program, const std::string& text, float x, float y, float scale, const glm::vec3& color) { static Font font; glUseProgram(program); glUniform3f(glGetUniformLocation(program, "textColor"), color.x, color.y, color.z); glActiveTexture(GL_TEXTURE0); + + std::vector vertices; + for (char8_t c : text) { auto it = font.m_characters.find(c); if (it == font.m_characters.end()) { @@ -89,24 +111,32 @@ void Font::render_text(GLuint program, GLuint vbo, const std::string& text, floa float w = ch.size.x * scale; float h = ch.size.y * scale; - float vertices[6][4] { - { xpos, ypos + h, 0.0, 1.0 }, - { xpos, ypos, 0.0, 0.0 }, - { xpos + w, ypos, 1.0, 0.0 }, - - { xpos, ypos + h, 0.0, 1.0 }, - { xpos + w, ypos, 1.0, 0.0 }, - { xpos + w, ypos + h, 1.0, 1.0 } - }; - glBindTexture(GL_TEXTURE_2D, ch.texture_id); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0); - glEnableVertexAttribArray(0); - glDrawArrays(GL_TRIANGLES, 0, 6); + vertices.emplace_back(xpos, ypos + h, ch.uv_min.x, ch.uv_max.y, static_cast(c)); + vertices.emplace_back(xpos, ypos, ch.uv_min.x, ch.uv_min.y, static_cast(c)); + vertices.emplace_back(xpos + w, ypos, ch.uv_max.x, ch.uv_min.y, static_cast(c)); + vertices.emplace_back(xpos, ypos + h, ch.uv_min.x, ch.uv_max.y, static_cast(c)); + vertices.emplace_back(xpos + w, ypos, ch.uv_max.x, ch.uv_min.y, static_cast(c)); + vertices.emplace_back(xpos + w, ypos + h, ch.uv_max.x, ch.uv_max.y, static_cast(c)); + x += (ch.advance >> 6) * scale; - glBindBuffer(GL_ARRAY_BUFFER, 0); + } - glBindTexture(GL_TEXTURE_2D, 0); + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex2D), vertices.data(), GL_STATIC_DRAW); + glBindTexture(GL_TEXTURE_2D_ARRAY, font.m_text_texture); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, s)); + glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, layer)); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + glDrawArrays(GL_TRIANGLES, 0, vertices.size() * 6); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); + glDeleteBuffers(1, &vbo); }