GLFont temporary string compiling/caching with garbage collect

This commit is contained in:
Charles J. Cliffe 2016-03-15 01:12:31 -04:00
parent cfdbcf9bc3
commit 297e35ebf7
5 changed files with 238 additions and 16 deletions

View File

@ -254,7 +254,7 @@ void SpectrumPanel::drawPanelContents() {
glColor4f(ThemeMgr::mgr.currentTheme->text.r, ThemeMgr::mgr.currentTheme->text.g, ThemeMgr::mgr.currentTheme->text.b,1.0);
GLFont::getFont(fontEnumSize).drawString(label.str(), m, hPos, fontSize, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(fontEnumSize).drawString(label.str(), m, hPos, fontSize, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true);
label.str(std::string());

View File

@ -3,6 +3,8 @@
#include <iostream>
#include <fstream>
#include <algorithm>
#include "cubic_math.h"
#ifdef _MSC_VER
#include <windows.h>
@ -27,6 +29,9 @@ static std::string getExePath(void)
#define RES_FOLDER ""
#endif
GLFontStringCache::GLFontStringCache() {
gc = 0;
}
GLFont GLFont::fonts[GLFONT_MAX];
@ -122,7 +127,7 @@ int GLFontChar::getIndex() {
}
GLFont::GLFont() :
lineHeight(0), base(0), imageWidth(0), imageHeight(0), loaded(false), texId(0) {
lineHeight(0), base(0), imageWidth(0), imageHeight(0), loaded(false), texId(0), gcCounter(0) {
}
@ -423,11 +428,11 @@ float GLFont::getStringWidth(std::string str, float size, float viewAspect) {
return width;
}
void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign, Align vAlign, int vpx, int vpy) {
// Draw string, immediate
void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign, Align vAlign, int vpx, int vpy, bool cacheable) {
pxHeight *= 2;
if (!vpx || !vpy) {
GLint vp[4];
glGetIntegerv( GL_VIEWPORT, vp);
@ -435,6 +440,49 @@ void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, A
vpy = vp[3];
}
if (cacheable) {
gcCounter++;
std::lock_guard<std::mutex> lock(cache_busy);
if (gcCounter > 200) {
doCacheGC();
gcCounter = 0;
}
GLFontStringCache *fc = nullptr;
std::map<int, std::map<int, std::map<int, std::map<std::string, GLFontStringCache * > > > >::iterator i1;
std::map<int, std::map<int, std::map<std::string, GLFontStringCache * > > >::iterator i2;
std::map<int, std::map<std::string, GLFontStringCache * > >::iterator i3;
std::map<std::string, GLFontStringCache * >::iterator i4;
i1 = stringCache.find(vpx);
if (i1 != stringCache.end()) {
i2 = i1->second.find(vpy);
if (i2 != i1->second.end()) {
i3 = i2->second.find(pxHeight);
if (i3 != i2->second.end()) {
i4 = i3->second.find(str);
if (i4 != i3->second.end()) {
fc = i4->second;
fc->gc = 0;
}
}
}
}
if (fc == nullptr) {
// std::cout << "cache miss" << std::endl;
fc = cacheString(str, pxHeight, vpx, vpy);
stringCache[vpx][vpy][pxHeight][str] = fc;
}
drawCacheString(fc, xpos, ypos, hAlign, vAlign);
return;
}
float size = (float) pxHeight / (float) vpy;
float viewAspect = (float) vpx / (float) vpy;
float msgWidth = getStringWidth(str, size, viewAspect);
@ -499,6 +547,9 @@ void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, A
glTranslatef(fchar->getAspect() + advx, 0.0, 0.0);
}
glVertexPointer(2, GL_FLOAT, 0, nullptr);
glTexCoordPointer(2, GL_FLOAT, 0, nullptr);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
@ -508,6 +559,157 @@ void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, A
glDisable(GL_TEXTURE_2D);
}
// Draw cached GLFontCacheString
void GLFont::drawCacheString(GLFontStringCache *fc, float xpos, float ypos, Align hAlign, Align vAlign) {
float size = (float) fc->pxHeight / (float) fc->vpy;
glPushMatrix();
glTranslatef(xpos, ypos, 0.0f);
switch (vAlign) {
case GLFONT_ALIGN_TOP:
glTranslatef(0.0, -size, 0.0);
break;
case GLFONT_ALIGN_CENTER:
glTranslatef(0.0, -size/2.0, 0.0);
break;
default:
break;
}
switch (hAlign) {
case GLFONT_ALIGN_RIGHT:
glTranslatef(-fc->msgWidth, 0.0, 0.0);
break;
case GLFONT_ALIGN_CENTER:
glTranslatef(-fc->msgWidth / 2.0, 0.0, 0.0);
break;
default:
break;
}
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texId);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, &fc->gl_vertices[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &fc->gl_uv[0]);
glDrawArrays(GL_QUADS, 0, 4 * fc->drawlen);
glVertexPointer(2, GL_FLOAT, 0, nullptr);
glTexCoordPointer(2, GL_FLOAT, 0, nullptr);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
}
// Compile optimized GLFontCacheString
GLFontStringCache *GLFont::cacheString(std::string str, int pxHeight, int vpx, int vpy) {
GLFontStringCache *fc = new GLFontStringCache;
fc->pxHeight = pxHeight;
fc->vpx = vpx;
fc->vpy = vpy;
float size = (float) pxHeight / (float) vpy;
float viewAspect = (float) vpx / (float) vpy;
fc->msgWidth = getStringWidth(str, size, viewAspect);
int nChar = 0;
for (int i = 0, iMax = str.length(); i < iMax; i++) {
int charId = str.at(i);
if (characters.find(charId) == characters.end()) {
continue;
}
nChar++;
}
fc->drawlen = nChar;
fc->gl_vertices.resize(nChar*8);
fc->gl_uv.resize(nChar*8);
CubicVR::mat4 trans = CubicVR::mat4::scale(size / viewAspect, size, 1.0f);
int c = 0;
for (int i = 0, iMax = str.length(); i < iMax; i++) {
int charId = str.at(i);
if (characters.find(charId) == characters.end()) {
continue;
}
GLFontChar *fchar = characters[charId];
float ofsx = (float) fchar->getXOffset() / (float) imageWidth;
float advx = (float) fchar->getXAdvance() / (float) imageWidth;
if (charId == 32) {
advx = characters['_']->getAspect();
}
// freeze transform to buffer
trans *= CubicVR::mat4::translate(ofsx, 0.0, 0.0);
int charIdx = fchar->getIndex();
for (int j = 0; j < 8; j+=2) {
CubicVR::vec3 pt(gl_vertices[charIdx + j],gl_vertices[charIdx + j + 1], 0.0);
pt = CubicVR::mat4::multiply(trans, pt, true);
fc->gl_vertices[c * 8 + j] = pt[0];
fc->gl_vertices[c * 8 + j + 1] = pt[1];
fc->gl_uv[c * 8 + j] = gl_uv[charIdx + j];
fc->gl_uv[c * 8 + j + 1] = gl_uv[charIdx + j + 1];
}
trans *= CubicVR::mat4::translate(fchar->getAspect() + advx, 0.0, 0.0);
c++;
}
return fc;
}
void GLFont::doCacheGC() {
std::map<int, std::map<int, std::map<int, std::map<std::string, GLFontStringCache * > > > >::iterator i1;
std::map<int, std::map<int, std::map<std::string, GLFontStringCache * > > >::iterator i2;
std::map<int, std::map<std::string, GLFontStringCache * > >::iterator i3;
std::map<std::string, GLFontStringCache * >::iterator i4;
std::vector<std::map<std::string, GLFontStringCache * >::iterator> removals;
std::vector<std::map<std::string, GLFontStringCache * >::iterator>::iterator removals_i;
for (i1 = stringCache.begin(); i1 != stringCache.end(); i1++) {
for (i2 = i1->second.begin(); i2 != i1->second.end(); i2++) {
for (i3 = i2->second.begin(); i3 != i2->second.end(); i3++) {
for (i4 = i3->second.begin(); i4 != i3->second.end(); i4++) {
i4->second->gc--;
if (i4->second->gc < -10) {
removals.push_back(i4);
}
}
}
}
}
if (removals.size()) {
for (removals_i = removals.begin(); removals_i != removals.end(); removals_i++) {
// std::cout << "gc'd " << (*removals_i)->first << std::endl;
GLFontStringCache *fc = (*removals_i)->second;
stringCache[fc->vpx][fc->vpy][fc->pxHeight].erase(*removals_i);
delete (*removals_i)->second;
}
}
}
GLFont &GLFont::getFont(GLFontSize esize) {

View File

@ -8,6 +8,18 @@
#include "wx/filename.h"
#include "wx/stdpaths.h"
class GLFontStringCache {
public:
GLFontStringCache();
int drawlen;
int vpx, vpy;
int pxHeight;
float msgWidth;
int gc;
std::vector<float> gl_vertices;
std::vector<float> gl_uv;
};
class GLFontChar {
public:
GLFontChar();
@ -66,12 +78,18 @@ public:
bool isLoaded();
float getStringWidth(std::string str, float size, float viewAspect);
void drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign = GLFONT_ALIGN_LEFT, Align vAlign = GLFONT_ALIGN_TOP, int vpx=0, int vpy=0);
void drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign = GLFONT_ALIGN_LEFT, Align vAlign = GLFONT_ALIGN_TOP, int vpx=0, int vpy=0, bool cacheable = false);
static GLFont fonts[GLFONT_MAX];
static GLFont &getFont(GLFontSize esize);
GLFontStringCache *cacheString(std::string str, int pxHeight, int vpx, int vpy);
void drawCacheString(GLFontStringCache *fc, float xpos, float ypos, Align hAlign, Align vAlign);
void doCacheGC();
private:
std::map<int, std::map<int, std::map<int, std::map<std::string, GLFontStringCache * > > > > stringCache;
std::string nextParam(std::istringstream &str);
std::string getParamKey(std::string param_str);
std::string getParamValue(std::string param_str);
@ -90,4 +108,6 @@ private:
std::string imageFile;
std::string fontFileSource;
GLuint texId;
int gcCounter;
std::mutex cache_busy;
};

View File

@ -166,11 +166,11 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGBA4f color, l
}
if (demod->getDemodulatorType() == "USB") {
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true);
} else if (demod->getDemodulatorType() == "LSB") {
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true);
} else {
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true);
}
glDisable(GL_BLEND);
@ -381,9 +381,9 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGBA4f color, long
glColor3f(0, 0, 0);
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5) + xOfs, -1.0 + hPos - yOfs, 16, demodAlign,
GLFont::GLFONT_ALIGN_CENTER);
GLFont::GLFONT_ALIGN_CENTER, 0, 0, true);
glColor3f(1, 1, 1);
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5), -1.0 + hPos, 16, demodAlign, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5), -1.0 + hPos, 16, demodAlign, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true);
glDisable(GL_BLEND);

View File

@ -35,9 +35,9 @@ void ScopeContext::DrawTunerTitles(bool ppmMode) {
glColor3f(0.65, 0.65, 0.65);
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString(ppmMode?"Device PPM":"Frequency", -0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString("Bandwidth", 0.0, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString("Center Frequency", 0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString(ppmMode?"Device PPM":"Frequency", -0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true);
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString("Bandwidth", 0.0, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true);
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString("Center Frequency", 0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true);
}
void ScopeContext::DrawDeviceName(std::string deviceName) {
@ -47,7 +47,7 @@ void ScopeContext::DrawDeviceName(std::string deviceName) {
float hPos = (float) (viewHeight - 20) / viewHeight;
glColor3f(0.65, 0.65, 0.65);
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString(deviceName.c_str(), 1.0, hPos, 12, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER);
GLFont::getFont(GLFont::GLFONT_SIZE12).drawString(deviceName.c_str(), 1.0, hPos, 12, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true);
}
void ScopeContext::DrawEnd() {