use uniform buffer, though glitchy

This commit is contained in:
jrkb 2023-05-29 15:43:56 +02:00
parent b107dbf57b
commit b2cfc9ffd8
4 changed files with 123 additions and 77 deletions

View file

@ -13,15 +13,20 @@ struct Glyph {
struct Curve { struct Curve {
vec2 p0, p1, p2; vec2 p0, p1, p2;
}; };
// CURVE_SIZE // CURVE_SIZE
// is the amount of vec2's in the curve // is the amount of vec2's in the curve
// we can hardcode this, as we can simply // we can hardcode this, as we can simply
// count the floats in the struct // count the floats in the struct
// 6 floats => 3 vec2's // 6 floats => 3 vec2's
#define CURVE_SIZE 3 #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 isampler2D glyphs;
uniform sampler2DArray curves;
ivec3 curvesTextureSize; ivec3 curvesTextureSize;
int curveBreakPoint; int curveBreakPoint;
//uniform sampler2D iChannel0; //uniform sampler2D iChannel0;
@ -57,16 +62,21 @@ Glyph loadGlyph(int index) {
} }
Curve loadCurve(int index) { Curve loadCurve(int index) {
Curve result; int index_a = int(floor((float(index) / 4.0) * 6.0));
//int dw = curveBreakPoint; // width including dead space int index_b = index_a + 1;
int dw = curvesTextureSize[0]; vec4 a = curves.data[index_a];
int w = dw - (dw % CURVE_SIZE); // effectual width vec4 b = curves.data[index_b];
int ix = (index * CURVE_SIZE) % w; Curve curve;
int iz = ((index * CURVE_SIZE) + 2) / w; if (index % 2 == 0) {
result.p0 = texelFetch(curves, ivec3(ix+0, 0, iz), 0).xy; curve.p0 = vec2(a[0], a[1]);
result.p1 = texelFetch(curves, ivec3(ix+1, 0, iz), 0).xy; curve.p1 = vec2(a[2], a[3]);
result.p2 = texelFetch(curves, ivec3(ix+2, 0, iz), 0).xy; curve.p2 = vec2(b[0], b[1]);
return result; } 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) { float computeCoverage(float inverseDiameter, vec2 p0, vec2 p1, vec2 p2) {
@ -124,10 +134,6 @@ vec2 rotate(vec2 v) {
void main() { void main() {
curvesTextureSize = textureSize(curves, 0);
curveBreakPoint = (curvesTextureSize[0] * 2) / 3;
//int w = curvesTextureSize[0]; // 16384 / 2 = 8192
float alpha = 0.0; float alpha = 0.0;
// Inverse of the diameter of a pixel in uv units for anti-aliasing. // Inverse of the diameter of a pixel in uv units for anti-aliasing.

View file

@ -7,6 +7,8 @@
#include "ofMain.h" #include "ofMain.h"
#include "ofUtils.h" #include "ofUtils.h"
#include "shader_catalog.hpp"
#include <GL/gl.h> #include <GL/gl.h>
#include <GL/glext.h> #include <GL/glext.h>
#ifdef TARGET_OPENGLES #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. // 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. // 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), face(face),
hinting(hinting), hinting(hinting),
BUFFER_TARGET_TYPE(bufferTargetType), BUFFER_TARGET_TYPE(bufferTargetType),
program(shaderProgram),
worldSize(worldSize){ worldSize(worldSize){
// TODO: modularize init, so we can initialize with settings and text // TODO: modularize init, so we can initialize with settings and text
if(gl_max_texture_size == -1){ if(gl_max_texture_size == -1){
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_max_texture_size); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_max_texture_size);
cout << "GL_MAX_TEXTURE_SIZE: " << ofToString(gl_max_texture_size) << endl; cout << "GL_MAX_TEXTURE_SIZE: " << ofToString(gl_max_texture_size) << endl;
@ -463,22 +465,7 @@ class Font {
emSize = face->units_per_EM; emSize = face->units_per_EM;
} }
//int amounters = 0; ubo_curves_index = glGetUniformBlockIndex(program, "curves_t");
//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;
//}
//}
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &vao);
@ -492,8 +479,13 @@ class Font {
glGenBuffers(1, &glyphBufferName); glGenBuffers(1, &glyphBufferName);
glGenBuffers(1, &curveBufferName); glGenBuffers(1, &curveBufferName);
#else #else
glGenTextures(1, &glyphBufferName); if(BUFFER_TARGET_TYPE == GL_TEXTURE_2D_ARRAY){
glGenTextures(1, &curveBufferName); glGenTextures(1, &glyphBufferName);
glGenTextures(1, &curveBufferName);
}else{
glGenTextures(1, &glyphBufferName);
glGenBuffers(1, &curveBufferName);
}
#endif #endif
glBindVertexArray(vao); glBindVertexArray(vao);
@ -526,7 +518,26 @@ class Font {
int widthCurveTextureLayer = 0; int widthCurveTextureLayer = 0;
int previousCurveBufferSize = 0; int previousCurveBufferSize = 0;
int bufferCurveSize = (sizeof(BufferCurve) / (sizeof(glm::float32_t) * 1)); 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){ void generateCurveTextureLayers(int amountCurves){
//cout << "generateCurveTextureLayers()" << endl; //cout << "generateCurveTextureLayers()" << endl;
int curveBufferSize = amountCurves * bufferCurveSize; int curveBufferSize = amountCurves * bufferCurveSize;
@ -575,6 +586,11 @@ class Font {
} }
previousCurveBufferSize = curveBufferSize; previousCurveBufferSize = curveBufferSize;
} }
void uploadCurveBuffer(){
glBindBufferBase(GL_UNIFORM_BUFFER, 0, curveBufferName);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(BufferCurve) * bufferCurves.size(), bufferCurves.data());
}
void uploadCurveTextureLayers(){ void uploadCurveTextureLayers(){
glActiveTexture(GL_TEXTURE0 + curveBufferUnit); glActiveTexture(GL_TEXTURE0 + curveBufferUnit);
glBindTexture(GL_TEXTURE_2D_ARRAY, curveBufferName); glBindTexture(GL_TEXTURE_2D_ARRAY, curveBufferName);
@ -673,6 +689,8 @@ class Font {
} }
void prepareGlyphsForText(const std::vector <GlyphIdentity> & variationText, void prepareGlyphsForText(const std::vector <GlyphIdentity> & variationText,
FT_Library & library, FT_Library & library,
shared_ptr <ShaderCatalog> shaderCatalog,
shared_ptr <ShaderCatalog::Entry> shader,
bool forceChange = false){ bool forceChange = false){
bool changed = false; bool changed = false;
@ -731,13 +749,50 @@ class Font {
dirtyBuffers = true; dirtyBuffers = true;
glyphBufferUnit = 1; glyphBufferUnit = 1;
curveBufferUnit = 2; curveBufferUnit = 2;
generateCurveTextureLayers(bufferCurves.size()); if(BUFFER_TARGET_TYPE == GL_UNIFORM_BUFFER){
// Reupload the full buffer contents. To make this even more int curvesBufferSize = getUboCurvesBufferSize(bufferCurves);
// dynamic, the buffers could be overallocated and only the added if(curvesBufferSize != shaderCurvesBufferSize){
// data could be uploaded. shaderCurvesBufferSize = curvesBufferSize;
uploadBuffers(); 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: private:
bool initializedGlyphsBufferTexture = false; bool initializedGlyphsBufferTexture = false;
@ -849,35 +904,12 @@ class Font {
GL_RG_INTEGER, GL_RG_INTEGER,
GL_INT, GL_INT,
bufferGlyphs.data()); 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); glActiveTexture(GL_TEXTURE0);
uploadCurveTextureLayers(); if(BUFFER_TARGET_TYPE == GL_TEXTURE_2D_ARRAY){
uploadCurveTextureLayers();
}else if(BUFFER_TARGET_TYPE == GL_UNIFORM_BUFFER){
uploadCurveBuffer();
}
#endif #endif
dirtyBuffers = false; dirtyBuffers = false;
} }
@ -1183,14 +1215,19 @@ class Font {
#else #else
glyphsUniformLocation = glGetUniformLocation(program, "glyphs"); glyphsUniformLocation = glGetUniformLocation(program, "glyphs");
glUniform1i(glyphsUniformLocation, glyphBufferUnit); glUniform1i(glyphsUniformLocation, glyphBufferUnit);
curvesUniformLocation = glGetUniformLocation(program, "curves");
glUniform1i(curvesUniformLocation, curveBufferUnit);
glActiveTexture(GL_TEXTURE0 + glyphBufferUnit); glActiveTexture(GL_TEXTURE0 + glyphBufferUnit);
glBindTexture(GL_TEXTURE_2D, glyphBufferName); glBindTexture(GL_TEXTURE_2D, glyphBufferName);
glActiveTexture(GL_TEXTURE0 + curveBufferUnit); if(BUFFER_TARGET_TYPE == GL_TEXTURE_2D_ARRAY){
glBindTexture(GL_TEXTURE_2D_ARRAY, curveBufferName); 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); glActiveTexture(GL_TEXTURE0);
#endif #endif
@ -1428,7 +1465,8 @@ class Font {
std::vector <BufferGlyph> bufferGlyphs; std::vector <BufferGlyph> bufferGlyphs;
std::vector <BufferCurve> bufferCurves; 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; std::unordered_map <GlyphIdentity, Glyph> glyphs;
static GLint gl_max_texture_size; static GLint gl_max_texture_size;
@ -1446,6 +1484,7 @@ class Font {
static std::shared_ptr <Font> loadFont(FT_Library & library, static std::shared_ptr <Font> loadFont(FT_Library & library,
const std::string & filename, const std::string & filename,
GLint bufferTargetType, GLint bufferTargetType,
GLuint shaderProgram,
float worldSize = 1.0f, float worldSize = 1.0f,
bool hinting = false){ bool hinting = false){
std::string error; 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; 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, static void initializeFont(FT_Library & library,
const std::string & filename, const std::string & filename,
shared_ptr <Font> & mainFont, shared_ptr <Font> & mainFont,
GLuint shaderProgram,
GLint bufferTargetType = GL_TEXTURE_2D_ARRAY){ GLint bufferTargetType = GL_TEXTURE_2D_ARRAY){
cout << "initializeFont" << endl; cout << "initializeFont" << endl;
auto font = loadFont(library, filename, bufferTargetType); auto font = loadFont(library, filename, bufferTargetType, shaderProgram);
if(!font){ if(!font){
return; return;
} }

View file

@ -208,7 +208,7 @@ class ShaderCatalog::Impl {
if(error != ""){ if(error != ""){
std::cerr << "[shader] " << error << std::endl; std::cerr << "[shader] " << error << std::endl;
}else{ }else{
std::cerr << "[shader] reloaded " << name << std::endl; //std::cerr << "[shader] reloaded " << name << std::endl;
glDeleteProgram(it->second->program); glDeleteProgram(it->second->program);
it->second->program = program; it->second->program = program;
} }

View file

@ -13,7 +13,7 @@ namespace ofxGPUFont {
class ShaderCatalog { class ShaderCatalog {
public: public:
struct Entry { struct Entry {
unsigned int program; GLuint program;
Entry() : program(0){ Entry() : program(0){
} }