use uniform buffer, though glitchy
This commit is contained in:
parent
b107dbf57b
commit
b2cfc9ffd8
4 changed files with 123 additions and 77 deletions
|
@ -13,15 +13,20 @@ struct Glyph {
|
|||
struct Curve {
|
||||
vec2 p0, p1, p2;
|
||||
};
|
||||
|
||||
// CURVE_SIZE
|
||||
// is the amount of vec2's in the curve
|
||||
// we can hardcode this, as we can simply
|
||||
// count the floats in the struct
|
||||
// 6 floats => 3 vec2's
|
||||
#define CURVE_SIZE 3
|
||||
const int CURVES_BUFFER_SIZE = {{CURVES_BUFFER_SIZE}};
|
||||
|
||||
layout(std140) uniform curves_t {
|
||||
vec4 data[{{CURVES_BUFFER_SIZE}}];
|
||||
} curves;
|
||||
|
||||
uniform isampler2D glyphs;
|
||||
uniform sampler2DArray curves;
|
||||
ivec3 curvesTextureSize;
|
||||
int curveBreakPoint;
|
||||
//uniform sampler2D iChannel0;
|
||||
|
@ -57,16 +62,21 @@ Glyph loadGlyph(int index) {
|
|||
}
|
||||
|
||||
Curve loadCurve(int index) {
|
||||
Curve result;
|
||||
//int dw = curveBreakPoint; // width including dead space
|
||||
int dw = curvesTextureSize[0];
|
||||
int w = dw - (dw % CURVE_SIZE); // effectual width
|
||||
int ix = (index * CURVE_SIZE) % w;
|
||||
int iz = ((index * CURVE_SIZE) + 2) / w;
|
||||
result.p0 = texelFetch(curves, ivec3(ix+0, 0, iz), 0).xy;
|
||||
result.p1 = texelFetch(curves, ivec3(ix+1, 0, iz), 0).xy;
|
||||
result.p2 = texelFetch(curves, ivec3(ix+2, 0, iz), 0).xy;
|
||||
return result;
|
||||
int index_a = int(floor((float(index) / 4.0) * 6.0));
|
||||
int index_b = index_a + 1;
|
||||
vec4 a = curves.data[index_a];
|
||||
vec4 b = curves.data[index_b];
|
||||
Curve curve;
|
||||
if (index % 2 == 0) {
|
||||
curve.p0 = vec2(a[0], a[1]);
|
||||
curve.p1 = vec2(a[2], a[3]);
|
||||
curve.p2 = vec2(b[0], b[1]);
|
||||
} else {
|
||||
curve.p0 = vec2(a[2], a[3]);
|
||||
curve.p1 = vec2(b[0], b[1]);
|
||||
curve.p2 = vec2(b[2], b[3]);
|
||||
}
|
||||
return curve;
|
||||
}
|
||||
|
||||
float computeCoverage(float inverseDiameter, vec2 p0, vec2 p1, vec2 p2) {
|
||||
|
@ -124,10 +134,6 @@ vec2 rotate(vec2 v) {
|
|||
|
||||
void main() {
|
||||
|
||||
curvesTextureSize = textureSize(curves, 0);
|
||||
curveBreakPoint = (curvesTextureSize[0] * 2) / 3;
|
||||
//int w = curvesTextureSize[0]; // 16384 / 2 = 8192
|
||||
|
||||
float alpha = 0.0;
|
||||
|
||||
// Inverse of the diameter of a pixel in uv units for anti-aliasing.
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "ofMain.h"
|
||||
#include "ofUtils.h"
|
||||
|
||||
#include "shader_catalog.hpp"
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
#ifdef TARGET_OPENGLES
|
||||
|
@ -429,14 +431,14 @@ class Font {
|
|||
|
||||
// If hinting is enabled, worldSize must be an integer and defines the font size in pixels used for hinting.
|
||||
// Otherwise, worldSize can be an arbitrary floating-point value.
|
||||
Font(FT_Face face, float worldSize = 1.0f, bool hinting = false, GLint bufferTargetType = GL_TEXTURE_2D_ARRAY) :
|
||||
Font(FT_Face face, float worldSize = 1.0f, bool hinting = false, GLint bufferTargetType = GL_TEXTURE_2D_ARRAY, GLuint shaderProgram = 0) :
|
||||
face(face),
|
||||
hinting(hinting),
|
||||
BUFFER_TARGET_TYPE(bufferTargetType),
|
||||
program(shaderProgram),
|
||||
worldSize(worldSize){
|
||||
// TODO: modularize init, so we can initialize with settings and text
|
||||
|
||||
|
||||
if(gl_max_texture_size == -1){
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_max_texture_size);
|
||||
cout << "GL_MAX_TEXTURE_SIZE: " << ofToString(gl_max_texture_size) << endl;
|
||||
|
@ -463,22 +465,7 @@ class Font {
|
|||
emSize = face->units_per_EM;
|
||||
}
|
||||
|
||||
//int amounters = 0;
|
||||
//for(int i = 0; i < 1024; i++){
|
||||
//testGL(10 + i);
|
||||
//amounters = i + 1;
|
||||
//cout << "added " << ofToString(amounters) << " LOL" << endl;
|
||||
//bool hasError = false;
|
||||
//GLenum err;
|
||||
//while((err = glGetError()) != GL_NO_ERROR){
|
||||
//hasError = true;
|
||||
//// Process/log the error.
|
||||
//}
|
||||
//if(hasError){
|
||||
//cout << "WHOOOPS" << endl;
|
||||
//break;
|
||||
//}
|
||||
//}
|
||||
ubo_curves_index = glGetUniformBlockIndex(program, "curves_t");
|
||||
|
||||
glGenVertexArrays(1, &vao);
|
||||
|
||||
|
@ -492,8 +479,13 @@ class Font {
|
|||
glGenBuffers(1, &glyphBufferName);
|
||||
glGenBuffers(1, &curveBufferName);
|
||||
#else
|
||||
glGenTextures(1, &glyphBufferName);
|
||||
glGenTextures(1, &curveBufferName);
|
||||
if(BUFFER_TARGET_TYPE == GL_TEXTURE_2D_ARRAY){
|
||||
glGenTextures(1, &glyphBufferName);
|
||||
glGenTextures(1, &curveBufferName);
|
||||
}else{
|
||||
glGenTextures(1, &glyphBufferName);
|
||||
glGenBuffers(1, &curveBufferName);
|
||||
}
|
||||
#endif
|
||||
|
||||
glBindVertexArray(vao);
|
||||
|
@ -526,7 +518,26 @@ class Font {
|
|||
int widthCurveTextureLayer = 0;
|
||||
int previousCurveBufferSize = 0;
|
||||
int bufferCurveSize = (sizeof(BufferCurve) / (sizeof(glm::float32_t) * 1));
|
||||
int shaderCurvesBufferSize = -1;
|
||||
GLint ubo_curves_index;
|
||||
|
||||
void generateCurveBuffers(){
|
||||
int shaderBufferByteSize = sizeof(BufferCurve) * shaderCurvesBufferSize;
|
||||
shaderBufferCurves = bufferCurves;
|
||||
shaderBufferCurves.resize(shaderCurvesBufferSize);
|
||||
|
||||
//cout << "generate curve buffer" << endl
|
||||
//<< "\t shaderBufferByteSize: " << ofToString(shaderBufferByteSize)
|
||||
//<< "\t bufferCurves.size(): " << ofToString(bufferCurves.size())
|
||||
//<< "\t shaderBufferCurves.size(): " << ofToString(shaderBufferCurves.size())
|
||||
//<< endl;
|
||||
|
||||
ubo_curves_index = glGetUniformBlockIndex(program, "curves_t");
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, 0, curveBufferName);
|
||||
glBufferData(GL_UNIFORM_BUFFER, shaderBufferByteSize, shaderBufferCurves.data(), GL_DYNAMIC_DRAW);
|
||||
glUniformBlockBinding(program, ubo_curves_index, 0);
|
||||
|
||||
}
|
||||
void generateCurveTextureLayers(int amountCurves){
|
||||
//cout << "generateCurveTextureLayers()" << endl;
|
||||
int curveBufferSize = amountCurves * bufferCurveSize;
|
||||
|
@ -575,6 +586,11 @@ class Font {
|
|||
}
|
||||
previousCurveBufferSize = curveBufferSize;
|
||||
}
|
||||
void uploadCurveBuffer(){
|
||||
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, 0, curveBufferName);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(BufferCurve) * bufferCurves.size(), bufferCurves.data());
|
||||
}
|
||||
void uploadCurveTextureLayers(){
|
||||
glActiveTexture(GL_TEXTURE0 + curveBufferUnit);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, curveBufferName);
|
||||
|
@ -673,6 +689,8 @@ class Font {
|
|||
}
|
||||
void prepareGlyphsForText(const std::vector <GlyphIdentity> & variationText,
|
||||
FT_Library & library,
|
||||
shared_ptr <ShaderCatalog> shaderCatalog,
|
||||
shared_ptr <ShaderCatalog::Entry> shader,
|
||||
bool forceChange = false){
|
||||
bool changed = false;
|
||||
|
||||
|
@ -731,13 +749,50 @@ class Font {
|
|||
dirtyBuffers = true;
|
||||
glyphBufferUnit = 1;
|
||||
curveBufferUnit = 2;
|
||||
generateCurveTextureLayers(bufferCurves.size());
|
||||
// Reupload the full buffer contents. To make this even more
|
||||
// dynamic, the buffers could be overallocated and only the added
|
||||
// data could be uploaded.
|
||||
uploadBuffers();
|
||||
if(BUFFER_TARGET_TYPE == GL_UNIFORM_BUFFER){
|
||||
int curvesBufferSize = getUboCurvesBufferSize(bufferCurves);
|
||||
if(curvesBufferSize != shaderCurvesBufferSize){
|
||||
shaderCurvesBufferSize = curvesBufferSize;
|
||||
shaderCatalog->setReplacement("{{CURVES_BUFFER_SIZE}}", std::to_string(shaderCurvesBufferSize));
|
||||
//cout << shaderCatalog->getReplacement("{{CURVES_BUFFER_SIZE}}") << " <<<< _ replacement for curves buffer size " << endl;
|
||||
shaderCatalog->requestUpdate("font_ub", true);
|
||||
shaderCatalog->update();
|
||||
shader = shaderCatalog->get("font_ub");
|
||||
program = shader->program;
|
||||
generateCurveBuffers();
|
||||
uploadBuffers();
|
||||
}else{
|
||||
uploadBuffers();
|
||||
}
|
||||
}else{
|
||||
generateCurveTextureLayers(bufferCurves.size());
|
||||
// Reupload the full buffer contents. To make this even more
|
||||
// dynamic, the buffers could be overallocated and only the added
|
||||
// data could be uploaded.
|
||||
uploadBuffers();
|
||||
}
|
||||
}
|
||||
}
|
||||
int getUboCurvesBufferSize(const std::vector <BufferCurve> & bc){
|
||||
int actualShaderBufferSize = ceil((bc.size() * 6.0) / 4.0);
|
||||
int thresholdBase = 2048;
|
||||
int n_max = gl_max_uniform_block_size / thresholdBase;
|
||||
for(int i = 0; i < n_max + 1; i++){
|
||||
int levelSize = thresholdBase * i;
|
||||
// prevent flattering around a threshold
|
||||
// when going a level down
|
||||
// but immediately
|
||||
if(actualShaderBufferSize <= levelSize){
|
||||
if(shaderCurvesBufferSize == levelSize + thresholdBase){
|
||||
return shaderCurvesBufferSize;
|
||||
}
|
||||
return levelSize;
|
||||
}
|
||||
}
|
||||
// you want more? well, we don't have it :(
|
||||
return gl_max_uniform_block_size;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
bool initializedGlyphsBufferTexture = false;
|
||||
|
@ -849,35 +904,12 @@ class Font {
|
|||
GL_RG_INTEGER,
|
||||
GL_INT,
|
||||
bufferGlyphs.data());
|
||||
|
||||
//int bufferCurvesSize = bufferCurves.size() * bufferCurveSize;
|
||||
//if(!isPowerOfTwo(bufferCurvesSize)){
|
||||
//bufferCurvesSize = calculateUpperPowerOfTwo(bufferCurvesSize);
|
||||
//}
|
||||
//glActiveTexture(GL_TEXTURE0 + curveBufferUnit);
|
||||
//glBindTexture(GL_TEXTURE_2D, curveBufferName);
|
||||
//if(!initializedCurvesBufferTexture){
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
//GL_NEAREST);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
//GL_NEAREST);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
//initializedCurvesBufferTexture = true;
|
||||
//}
|
||||
//glTexImage2D(GL_TEXTURE_2D,
|
||||
//0,
|
||||
//GL_RG32F,
|
||||
//bufferCurvesSize,
|
||||
//1,
|
||||
//0,
|
||||
//GL_RG,
|
||||
//GL_FLOAT,
|
||||
//bufferCurves.data());
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
uploadCurveTextureLayers();
|
||||
if(BUFFER_TARGET_TYPE == GL_TEXTURE_2D_ARRAY){
|
||||
uploadCurveTextureLayers();
|
||||
}else if(BUFFER_TARGET_TYPE == GL_UNIFORM_BUFFER){
|
||||
uploadCurveBuffer();
|
||||
}
|
||||
#endif
|
||||
dirtyBuffers = false;
|
||||
}
|
||||
|
@ -1183,14 +1215,19 @@ class Font {
|
|||
#else
|
||||
glyphsUniformLocation = glGetUniformLocation(program, "glyphs");
|
||||
glUniform1i(glyphsUniformLocation, glyphBufferUnit);
|
||||
curvesUniformLocation = glGetUniformLocation(program, "curves");
|
||||
glUniform1i(curvesUniformLocation, curveBufferUnit);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + glyphBufferUnit);
|
||||
glBindTexture(GL_TEXTURE_2D, glyphBufferName);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + curveBufferUnit);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, curveBufferName);
|
||||
if(BUFFER_TARGET_TYPE == GL_TEXTURE_2D_ARRAY){
|
||||
curvesUniformLocation = glGetUniformLocation(program, "curves");
|
||||
glUniform1i(curvesUniformLocation, curveBufferUnit);
|
||||
glActiveTexture(GL_TEXTURE0 + curveBufferUnit);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, curveBufferName);
|
||||
}else if(BUFFER_TARGET_TYPE == GL_UNIFORM_BUFFER){
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, curveBufferName);
|
||||
glUniformBlockBinding(program, ubo_curves_index, 0);
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
#endif
|
||||
|
@ -1428,7 +1465,8 @@ class Font {
|
|||
|
||||
std::vector <BufferGlyph> bufferGlyphs;
|
||||
std::vector <BufferCurve> bufferCurves;
|
||||
std::vector <int> bufferCurveLayerPointers = {0};
|
||||
std::vector <BufferCurve> shaderBufferCurves; // ubo
|
||||
std::vector <int> bufferCurveLayerPointers = {0}; // t2a
|
||||
std::unordered_map <GlyphIdentity, Glyph> glyphs;
|
||||
|
||||
static GLint gl_max_texture_size;
|
||||
|
@ -1446,6 +1484,7 @@ class Font {
|
|||
static std::shared_ptr <Font> loadFont(FT_Library & library,
|
||||
const std::string & filename,
|
||||
GLint bufferTargetType,
|
||||
GLuint shaderProgram,
|
||||
float worldSize = 1.0f,
|
||||
bool hinting = false){
|
||||
std::string error;
|
||||
|
@ -1457,16 +1496,17 @@ static std::shared_ptr <Font> loadFont(FT_Library & library,
|
|||
std::cout << "ofxGPUFont::font.hpp[" << __LINE__ << "] FT loaded " << filename << ": " << error << std::endl;
|
||||
}
|
||||
|
||||
return std::make_shared <Font>(face, worldSize, hinting, bufferTargetType);
|
||||
return std::make_shared <Font>(face, worldSize, hinting, bufferTargetType, shaderProgram);
|
||||
}
|
||||
|
||||
|
||||
static void initializeFont(FT_Library & library,
|
||||
const std::string & filename,
|
||||
shared_ptr <Font> & mainFont,
|
||||
GLuint shaderProgram,
|
||||
GLint bufferTargetType = GL_TEXTURE_2D_ARRAY){
|
||||
cout << "initializeFont" << endl;
|
||||
auto font = loadFont(library, filename, bufferTargetType);
|
||||
auto font = loadFont(library, filename, bufferTargetType, shaderProgram);
|
||||
if(!font){
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ class ShaderCatalog::Impl {
|
|||
if(error != ""){
|
||||
std::cerr << "[shader] " << error << std::endl;
|
||||
}else{
|
||||
std::cerr << "[shader] reloaded " << name << std::endl;
|
||||
//std::cerr << "[shader] reloaded " << name << std::endl;
|
||||
glDeleteProgram(it->second->program);
|
||||
it->second->program = program;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace ofxGPUFont {
|
|||
class ShaderCatalog {
|
||||
public:
|
||||
struct Entry {
|
||||
unsigned int program;
|
||||
GLuint program;
|
||||
|
||||
Entry() : program(0){
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue