gpt4 book ai didi

c++ - FreeType OpenGL 动态文本 = 糟糕的性能

转载 作者:行者123 更新时间:2023-11-30 00:48:48 24 4
gpt4 key购买 nike

我目前正在寻找我的代码中的瓶颈,结果发现 GUI 是其中之一。好吧,实际上不是 GUI,而是在那里绘制的动态文本。

初始化

        if (FT_Init_FreeType(&m_FreeType))
throw Helpers::ExceptionWithMsg("Could not init freetype lib");

if (FT_New_Face(m_FreeType, "res\\fonts\\FreeSans.ttf", 0, &m_FontFace))
throw Helpers::ExceptionWithMsg("Could not open font");

m_ShaderID = ... // Loads the corresponding shader
m_TextColorLocation = glGetUniformLocation(m_ShaderID, "color");
m_CoordinatesLocation = glGetAttribLocation(m_ShaderID, "coord");

glGenBuffers(1, &m_VBO);

FT_Set_Pixel_Sizes(m_FontFace, 0, m_FontSize);
glyph = m_FontFace->glyph;

glGenTextures(1, &m_Texture);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Texture);

// We require 1 byte alignment when uploading texture data
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

// Linear filtering usually looks best for text
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

// Clamping to edges is important to prevent artifacts when scaling
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glUseProgram(m_ShaderID);
glUniform4f(m_TextColorLocation, m_TextColor.x, m_TextColor.y, m_TextColor.z, m_TextColor.w);
glUseProgram(0);

我的工作:我初始化 FreeType,获取字体,初始化着色器和所有制服。

然后我为纹理坐标创建 vbo,为字体设置像素,获取字形。

现在我生成纹理,激活它,绑定(bind)它...我想设置所有参数,然后设置永不改变的制服。

渲染:

    glUseProgram(m_ShaderID);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Texture);

// Linear filtering usually looks best for text
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

// Set up the VBO for our vertex data
glEnableVertexAttribArray(m_CoordinatesLocation);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glVertexAttribPointer(m_CoordinatesLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);

GLfloat cursorPosX = m_X;
GLfloat cursorPosY = m_Y;
for (size_t i = 0; i < m_Text.size(); ++i)
{
// If Loading a char fails, just continue
if (FT_Load_Char(m_FontFace, m_Text[i], FT_LOAD_RENDER))
continue;

glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, glyph->bitmap.width, glyph->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, glyph->bitmap.buffer);

// Calculate the vertex and texture coordinates
GLfloat x2 = cursorPosX + glyph->bitmap_left * m_SX;
GLfloat y2 = -cursorPosY - glyph->bitmap_top * m_SY;
GLfloat w = glyph->bitmap.width * m_SX;
GLfloat h = glyph->bitmap.rows * m_SY;

PointStruct box[4] =
{
{ x2, -y2, 0, 0 },
{ x2 + w, -y2, 1, 0 },
{ x2, -y2 - h, 0, 1 },
{ x2 + w, -y2 - h, 1, 1 }
};

// Draw the character on the screen
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

// Advance the cursor to the start of the next character
cursorPosX += glyph->advance.x / 64 * m_SX;
cursorPosY += glyph->advance.y / 64 * m_SY;
}

glDisableVertexAttribArray(m_CoordinatesLocation);
glDeleteTextures(1, &m_Texture);
glDisable(GL_BLEND);
glUseProgram(0);

设置着色器和其他东西很明显。

对于每个渲染调用,我都会激活纹理,绑定(bind)它,启用我存储纹理坐标的 VBO。然后我遍历文本中的每个字符,用 FT_LOAD_CHAR 加载它。然后我使用 glTexImage2D 指定纹理,计算顶点和纹理坐标并绘制所有内容。

这似乎是非常低效的,但我发现没有办法提高性能并且文本可读。

我只想在初始化中设置一次文本参数 -> 所有字符都是框。

我想将 GL_DYNAMIC_DRAW 设置为 GL_STATIC_DRAW...区别不大。我还能做什么?

我渲染的文本是动态的,它会改变(或可能会改变)每一帧,所以我有点卡住了。

我用一个查询来查询这个东西的性能。如果我不渲染动态文本,它会非常低,但如果我渲染动态文本,它会变得非常高......在这个过程中没有太多其他事情发生,它只是绘制 GUI。

真正困扰我的是什么

有一件事我真的不明白(可能是晴天...)

如果我没有在 render-method() 中设置线性过滤,我会得到奇怪的立方体字形,但这是为什么呢? OpenGL 是一个状态机,纹理参数设置为当前绑定(bind)的参数。因此,如果我在初始化时将 Min 和 Mag 过滤器设置为 GL_LINEAR,为什么这还不够?

如果我在渲染中删除这两行,我会从查询中获得更好的性能(更低的数字),但它不会绘制任何可读的内容。

最佳答案

这绝对会很慢。

For each render call I activate the texture, bind it, enable the VBO I store my textureCoordinates in. Then I iterate over every character in the text load it with FT_LOAD_CHAR. I then specify the texture with glTexImage2D, calculate vertex and texture coordinates and draw everything.

不幸的是,这个问题很难。这是我使用的方法:

  • 有一张纹理,格式为 GL_RED8,用于存储字形。

  • 每当需要一个新的字形时,它就会被添加到纹理中。这是通过调用 FT_Render_Glyph() 并将结果复制到纹理缓冲区中来完成的。如果新字形不适合,整个字形纹理将调整大小并重新打包。 (我使用天际线算法来打包字形,因为它很简单。)

  • 如果添加了任何新的字形,我将调用 glTexSubImage2D()。代码的结构应确保每帧仅调用一次。

  • 为了渲染文本,我创建了一个 VBO,其中包含渲染一段文本所需的所有四边形的顶点和纹理坐标。 (请理解“quad”是指两个三角形,而不是 GL_QUAD)。

因此,当您更改要呈现的文本时,

  • 您必须更新 VBO,但每帧只更新一次

  • 您可能必须更新纹理,但每帧只更新一次,而且随着字形纹理填满您使用的字形,这种情况发生的频率可能会降低。

制作这种系统原型(prototype)的一个好方法是首先将字体中的所有 字形渲染到纹理中,但是如果您最终使用多种字体并且样式,或者如果您想呈现中文、韩文或日文文本。

其他注意事项包括换行、字形替换、字距调整、bidi、国际文本的一般问题、如何指定样式等。我建议将 HarfBuzz 与 FreeType 结合使用。 HarfBuzz 处理困难的字形替换和定位问题。如果您的程序只有英文文本,则这些都不是绝对必要的。

有一些库可以完成所有这些,但我没有使用过它们。

如果您想快刀斩乱麻,另一种方法是在您的应用程序中嵌入网络浏览器,如 Chromium(Awesomium、WebKit、Gecko——多种选择),然后将所有文本渲染外包给它。

关于c++ - FreeType OpenGL 动态文本 = 糟糕的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30644979/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com