commit 8a5148e5771b02df1e2759a3ee5072148b7622fb
parent 7e8d64c03ab7597ce8b8805d7e39af2bd4273b59
Author: Brian Swetland <swetland@frotz.net>
Date: Thu, 5 Sep 2013 20:04:16 -0700
texturefont: stop using geometry shaders
Diffstat:
3 files changed, 124 insertions(+), 94 deletions(-)
diff --git a/common/assets/texturefont.glsl b/common/assets/texturefont.glsl
@@ -1,77 +1,39 @@
-#version 150
-#extension GL_ARB_separate_shader_objects : enable
+#version 140
+#extension GL_ARB_explicit_attrib_location : enable
-layout(std140) uniform udata0 {
- mat4 MVP;
- vec2 adj;
- float dim;
+uniform samplerBuffer sampler0; // character data
+uniform sampler2D sampler1; // glyph texture
+
+layout(std140) uniform block3 {
+ mat4 xMVP;
};
-- vs
-layout(location = 0) in ivec4 posn;
-layout(location = 1) in ivec2 texc;
-layout(location = 2) in vec4 color;
-
-out vec2 size;
-out vec2 tex;
-out vec4 vcolor;
-
-void main() {
- gl_Position = vec4(posn.x, posn.y, 0, 1);
- size = posn.zw;
- tex = texc;
- vcolor = color;
-}
-
--- gs
-
-layout (points) in;
-layout (triangle_strip, max_vertices=4) out;
+layout(location = 0) in ivec4 aData; // X, Y, ID, RGBA
-in vec2 size[1];
-in vec2 tex[1];
-in vec4 vcolor[1];
-
-out vec2 s0tc;
-out vec4 color;
+out vec2 vTexCoord;
+out vec4 vColor;
void main() {
- vec4 p = gl_in[0].gl_Position;
- vec2 sz = size[0];
- vec2 tsz = sz - vec2(1.0,1.0);
-
- gl_Position = MVP * vec4(p.x, p.y - sz.y, 0.0, 1.0);
- s0tc = tex[0] / dim + adj;
- color = vcolor[0];
- EmitVertex();
-
- gl_Position = MVP * vec4(p.x + sz.x, p.y - sz.y, 0.0, 1.0);
- s0tc = (tex[0] + vec2(tsz.x,0)) / dim + adj;
- color = vcolor[0];
- EmitVertex();
-
- gl_Position = MVP * vec4(p.x, p.y, 0.0, 1.0);
- s0tc = (tex[0] + vec2(0,tsz.y)) / dim + adj;
- color = vcolor[0];
- EmitVertex();
-
- gl_Position = MVP * vec4(p.x + sz.x, p.y, 0.0, 1.0);
- s0tc = (tex[0] + tsz) / dim + adj;
- color = vcolor[0];
- EmitVertex();
-
- EndPrimitive();
+ vec4 cdata = texelFetch(sampler0, aData.z + gl_VertexID);
+ vec4 pos = vec4(aData.x + cdata.x, aData.y + cdata.y, 0.0, 1.0);
+ vColor = vec4(
+ float(aData.w & 0xFF) / 255.0,
+ float((aData.w >> 8) & 0xFF) / 255.0,
+ float((aData.w >> 16) & 0xFF) / 255.0,
+ 1.0
+ );
+ vTexCoord = vec2(cdata.zw);
+ gl_Position = xMVP * pos;
}
-- fs
-uniform sampler2D s0glyphs;
-
-in vec2 s0tc;
-in vec4 color;
+in vec2 vTexCoord;
+in vec4 vColor;
void main() {
- vec4 c = texture2D(s0glyphs, s0tc);
- gl_FragColor = vec4(color.r, color.g, color.b, c.r);
+ vec4 c = texture2D(sampler1, vTexCoord);
+ gl_FragColor = vec4(vColor.rgb, c.r);
}
diff --git a/common/texturefont.cc b/common/texturefont.cc
@@ -20,20 +20,26 @@
#include "app.h"
#include "texturefont.h"
+/* performance experiments to try sometime:
+ * - pass color via vtx attr instead of unpacking in shader
+ * - pass character vertex table via uniform instead of texturebuffer
+ * - instead of DrawArraysInstanced:
+ * - call DrawElements with a fixed 1,1,1,1,1,1,2,2,2,2,2,2,3,... index buffer
+ * - call DrawArrays with unpacked vtx array (6 per character)
+ * - explore different vtx formats (int vs float vs short, etc)
+*/
+
// idx, src, dst, count, offset, stride, divisor
static VertexAttrDesc layout[] = {
- { 0, SRC_INT16, DST_INTEGER, 4, 0, 16, 0 },
- { 1, SRC_UINT16, DST_INTEGER, 2, 8, 16, 0 },
- { 2, SRC_UINT8, DST_NORMALIZED, 4, 12, 16, 0 },
+ { 0, SRC_INT32, DST_INTEGER, 4, 0, 16, 6 },
};
int TextureFont::init(App *app, const char *fontname) {
- VertexBuffer *vdata[] = {
- &vtx, &vtx, &vtx,
- };
+ VertexBuffer *vdata[] = { &vtx };
char tmp[256];
+ float *cdata, *cp;
+ float dim, adj;
unsigned sz;
-
header = NULL;
max = 128;
count = 0;
@@ -64,21 +70,62 @@ int TextureFont::init(App *app, const char *fontname) {
first = header->first;
last = first + header->count - 1;
- if (pgm.load("texturefont.vs", "texturefont.gs", "texturefont.fs"))
+ if (pgm.load("texturefont.vs", "texturefont.fs"))
goto fail;
- u.mvp.setOrtho(0, app->getWidth(), app->getHeight(), 0, -1, 1);
- u.dim = glyphs.width;
- u.adj[0] = 0.5 / float(glyphs.width);
- u.adj[1] = 0.5 / float(glyphs.width);
+ cp = cdata = (float*) malloc(sizeof(float) * 4 * 6 * header->count);
+
+ /* to adjust int coords to texture coords */
+ dim = glyphs.width;
+ adj = 0.5 / float(glyphs.width);
+
+ /* generate a 2d+uv quad for each character */
+ for (unsigned n = 0; n < header->count; n++) {
+ *cp++ = 0;
+ *cp++ = -info[n].h;
+ *cp++ = float(info[n].x) / dim + adj;
+ *cp++ = float(info[n].y) / dim + adj;
+
+ *cp++ = info[n].w;
+ *cp++ = -info[n].h;
+ *cp++ = float(info[n].x + info[n].w - 1) / dim + adj;
+ *cp++ = float(info[n].y) / dim + adj;
+
+ *cp++ = 0;
+ *cp++ = 0;
+ *cp++ = float(info[n].x) / dim + adj;
+ *cp++ = float(info[n].y + info[n].h - 1) / dim + adj;
+
+ *cp++ = info[n].w;
+ *cp++ = 0;
+ *cp++ = float(info[n].x + info[n].w - 1) / dim + adj;
+ *cp++ = float(info[n].y + info[n].h - 1) / dim + adj;
+
+ *cp++ = 0;
+ *cp++ = 0;
+ *cp++ = float(info[n].x) / dim + adj;
+ *cp++ = float(info[n].y + info[n].h - 1) / dim + adj;
+
+ *cp++ = info[n].w;
+ *cp++ = -info[n].h;
+ *cp++ = float(info[n].x + info[n].w - 1) / dim + adj;
+ *cp++ = float(info[n].y) / dim + adj;
+ }
+ cbuf.load(cdata, sizeof(float) * 4 * 6 * header->count);
vtx.load(data, sizeof(CharData) * max);
- ubuf.load(&u, sizeof(u));
- attr.init(layout, vdata, sizeof(layout) / sizeof(layout[0]));
+ mvp.setOrtho(0, app->getWidth(), app->getHeight(), 0, -1, 1);
+ ubuf.load(&mvp, sizeof(mvp));
+ attr.init(layout, vdata, sizeof(layout) / sizeof(layout[0]));
dirty = 0;
- color = RGBA(255,255,255,255);
+ glGenTextures(1, &tbid);
+ glActiveTexture(GL_TEXTURE0 + 15);
+ glBindTexture(GL_TEXTURE_BUFFER, tbid);
+ glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, cbuf.id);
+
+ color = RGBA(255,255,255,0);
return 0;
fail:
if (data) {
@@ -112,15 +159,40 @@ void TextureFont::render(App *app) {
}
pgm.use();
- ubuf.use(0);
+ ubuf.use(3);
attr.use();
- glyphs.use(0);
+ glyphs.use(1);
+ glActiveTexture(GL_TEXTURE0 + 0);
+ glBindTexture(GL_TEXTURE_BUFFER, tbid);
+ glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, cbuf.id);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDrawArrays(GL_POINTS, 0, count);
+ glDrawArraysInstanced(GL_TRIANGLES, 0, 6, count * 6);
glDisable(GL_BLEND);
}
+void TextureFont::measure(const char *s, unsigned *width, unsigned *height) {
+ unsigned w = 0;
+ unsigned h = 0;
+ while (*s) {
+ unsigned n = *s++;
+ if (n == 0)
+ break;
+ if ((n < first) || (n > last))
+ continue;
+ n -= first;
+ unsigned ch = info[n].h;
+ unsigned cw = info[n].w;
+ if (ch > h)
+ h = ch;
+ w += cw;
+ if (*s)
+ w += info[n].advance;
+ }
+ *width = w;
+ *height = h;
+}
+
void TextureFont::puts(int x, int y, const char *s) {
while (count < max) {
unsigned n = *s++;
@@ -131,11 +203,8 @@ void TextureFont::puts(int x, int y, const char *s) {
n -= first;
data[count].x = x + info[n].dx;
data[count].y = y - info[n].dy;
- data[count].w = info[n].w;
- data[count].h = info[n].h;
- data[count].s = info[n].x;
- data[count].t = info[n].y;
- data[count].rgba = color;
+ data[count].id = n * 6;
+ data[count].rgba = color & 0xFFFFFF; // strip alpha
count++;
x += info[n].advance;
}
diff --git a/common/texturefont.h b/common/texturefont.h
@@ -44,9 +44,10 @@ struct FontInfo {
#define TEXTUREFONT_MAGIC 0x746E6F46
struct CharData {
- u16 x, y, w, h;
- u16 s, t;
- u32 rgba;
+ int x;
+ int y;
+ int id;
+ int rgba;
};
class TextureFont {
@@ -57,18 +58,14 @@ public:
void printf(int x, int y, const char *fmt, ...);
void puts(int x, int y, const char *s);
void setColor(unsigned rgba);
+ void measure(const char *s, unsigned *width, unsigned *height);
private:
FontInfo *header;
CharInfo *info;
unsigned first;
unsigned last;
- struct {
- mat4 mvp;
- float adj[2];
- float dim;
- } u;
-
+ mat4 mvp;
UniformBuffer ubuf;
VertexBuffer vtx;
VertexBuffer cbuf;
@@ -79,6 +76,8 @@ private:
Texture2D glyphs;
VertexAttributes attr;
+ unsigned tbid;
+
CharData *data;
CharData *next;
unsigned count;