渲染字体时使用texelFetch更快吗?

时间:2014-03-20 08:33:00

标签: opengl fonts textures opengl-3

我正在OpenGL 3.3中编写一些字体绘图着色器。我将我的字体渲染到纹理图集中,然后为我想要绘制的一些文本生成一些显示列表。我希望渲染文本消耗最少的资源(CPU,GPU内存,GPU时间)。我怎么能做到这一点?

Freetype-gl,我发现作者每个角色生成6个索引和4个顶点。

由于我使用的是OpenGL 3.3,因此我有一些额外的自由。我的计划是每个字符生成1个顶点,每个字符生成一个整数“代码”。字符代码可用于texelFetch操作,以检索纹理coördinates和字符大小信息。几何着色器将大小信息和顶点转换为三角形条。

texelFetch是否比发送更多顶点/纹理coördinates慢?这值得吗?或者有没有理由说我在看过的字体库中没有这样做?


最终代码:

顶点着色器:

#version 330

uniform sampler2D font_atlas;
uniform sampler1D code_to_texture;
uniform mat4 projection;
uniform vec2 vertex_offset;  // in view space.
uniform vec4 color;
uniform float gamma;

in vec2 vertex;  // vertex in view space of each character adjusted for kerning, etc.
in int code;

out vec4 v_uv;

void main()
{
    v_uv = texelFetch(
            code_to_texture,
            code,
            0);
    gl_Position = projection * vec4(vertex_offset + vertex, 0.0, 1.0);
}

几何着色器:

#version 330

layout (points) in;
layout (triangle_strip, max_vertices = 4) out;

uniform sampler2D font_atlas;
uniform mat4 projection;

in vec4 v_uv[];

out vec2 g_uv;

void main()
{
    vec4 pos = gl_in[0].gl_Position;
    vec4 uv = v_uv[0];
    vec2 size = vec2(textureSize(font_atlas, 0)) * (uv.zw - uv.xy);
    vec2 pos_opposite = pos.xy + (mat2(projection) * size);

    gl_Position = vec4(pos.xy, 0, 1);
    g_uv = uv.xy;
    EmitVertex();

    gl_Position = vec4(pos.x, pos_opposite.y, 0, 1);
    g_uv = uv.xw;
    EmitVertex();

    gl_Position = vec4(pos_opposite.x, pos.y, 0, 1);
    g_uv = uv.zy;
    EmitVertex();

    gl_Position = vec4(pos_opposite.xy, 0, 1);
    g_uv = uv.zw;
    EmitVertex();

    EndPrimitive();
}

片段着色器:

#version 330

uniform sampler2D font_atlas;
uniform vec4 color;
uniform float gamma;

in vec2 g_uv;

layout (location = 0) out vec4 fragment_color;

void main()
{
    float a = texture(font_atlas, g_uv).r;
    fragment_color.rgb = color.rgb;
    fragment_color.a = color.a * pow(a, 1.0 / gamma);
}

2 个答案:

答案 0 :(得分:1)

也许您可以使用原子计数器来处理文本中的当前位置。

这是一篇关于内存带宽的有趣论文 GPU perf...

您可以将结果缓存在fbo中。

如你所说,为了真正快速渲染,你可以构建一个geom着色器,将点作为输入并输出四边形并对纹理进行采样以获得有关字形信息的更多信息。

这实际上是最好的解决方案......

答案 1 :(得分:1)

我不希望你提出的方法与顶点缓冲区中存储四边形顶点位置和纹理坐标之间存在显着的性能差异。一方面,您的方法需要较小的顶点缓冲区,而CPU的工作量较少。另一方面,texelFetch调用将在随机位置或多或少,并且不能充分利用缓存。最后一点可能不是很重要,因为我猜纹理不会很大。此外,几何着色器的执行模型意味着它们很快就会成为管道的瓶颈。

回答“这值得吗?” - 我怀疑不是出于性能原因。遗憾的是,在实施并测量性能之前,您无法分辨。我认为这是一个很酷的主意,所以我认为你不会浪费时间去尝试它。