G’day, long time lurker, first time poster.
I’ve been tinkering with OpenGL on a more or less hobby basis for several years after learning how to use the fixed-function stuff in university, but I only recently began seriously studying the more modern version of the API with the eventual intent of updating my custom 2D game engine.
Currently I’ve just finished re-tooling the sprite system to render using GLSL 1.2 shaders and competely custom attribute buffers with a homemade matrix system similar to the original OpenGL functionality (using CML). Everything draws fine, but when I examined the process in Task Manager, I noticed the memory use was increasing at about 4KB a second.
Selectively commenting out lines allowed me to zero in on the problem, which turned out to be specific to only two types of sprite and correspondongly to three of the drawing routines.
In the engine I have drawing routines for:
*Monochrome lines
*Bicoloured lines
*Convex polygons
*Line loops
*Textured quads (this will eventually be updated since quads have been deprecated, I believe)
The sprites that cause the problems are the monochrome line sprite and the polygon sprite that uses the polygon routine plus the loop routine for an optional border.
That is to say, these snippets of code don’t cause a leak:
inline void SLRenderer::drawBiLine(GLuint colour_index, Uint32 thickness, GLuint vertex_index)
{
SL_ASSERT(SLShaderProgram::getCurrentShader() != NULL, "ERROR: Current shader is null for some reason.");
static GLuint vertex_loc;
static string v_name("vertex_in");
vertex_loc = SLShaderProgram::getCurrentShader()->getAttributeLocation(v_name);
glBindBuffer(GL_ARRAY_BUFFER, SLVBOManager::SLVertexManager.VBOID());
glEnableVertexAttribArray(vertex_loc);
glVertexAttribPointer(vertex_loc, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)vertex_index);
static GLuint colour_loc;
static string c_name("colour_in");
colour_loc = SLShaderProgram::getCurrentShader()->getAttributeLocation(c_name);
glBindBuffer(GL_ARRAY_BUFFER, SLVBOManager::SLColourManager.VBOID());
glEnableVertexAttribArray(colour_loc);
glVertexAttribPointer(colour_loc, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*)colour_index);
static string MVM_Name("transform.model_view_matrix");
static string PVM_Name("transform.projection_matrix");
SLShaderProgram::getCurrentShader()->uniformM4(MVM_Name, SLGL::getModVMatrix());
SLShaderProgram::getCurrentShader()->uniformM4(PVM_Name, SLGL::getProjMatrix());
SLRenderer::switchTextures(false);
glEnable(GL_LINE_SMOOTH);
glLineWidth((GLfloat)thickness);
glDrawArrays(GL_LINES, 0, 2);
glDisable(GL_LINE_SMOOTH);
glLineWidth(1.0);
glDisableVertexAttribArray(vertex_loc);
glDisableVertexAttribArray(colour_loc);
}
inline void SLRenderer::drawTQuad(cml::vector4f& col, SLTexSampleList& list, GLuint v_offset, GLuint t_offset)
{
SL_ASSERT(SLShaderProgram::getCurrentShader() != NULL, "ERROR: Current shader is null for some reason.");
static GLuint vertex_loc;
static string v_name("vertex_in");
vertex_loc = SLShaderProgram::getCurrentShader()->getAttributeLocation(v_name);
static GLuint t_coord_loc;
static string t_name("t_coord_in");
t_coord_loc = SLShaderProgram::getCurrentShader()->getAttributeLocation(t_name);
glBindBuffer(GL_ARRAY_BUFFER, SLVBOManager::SLVertexManager.VBOID());
glEnableVertexAttribArray(vertex_loc);
glVertexAttribPointer(vertex_loc, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)v_offset);
glBindBuffer(GL_ARRAY_BUFFER, SLVBOManager::SLTCoordManager.VBOID());
glEnableVertexAttribArray(t_coord_loc);
glVertexAttribPointer(t_coord_loc, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)t_offset);
static string MVM_Name("transform.model_view_matrix");
static string PVM_Name("transform.projection_matrix");
static string col_name("colour_in");
SLShaderProgram::getCurrentShader()->uniformM4(MVM_Name, SLGL::getModVMatrix());
SLShaderProgram::getCurrentShader()->uniformM4(PVM_Name, SLGL::getProjMatrix());
SLShaderProgram::getCurrentShader()->uniformVF4(col_name, col);
SLRenderer::switchTextures(true);
foreach(SLTexSamplePair p, list)
{
p.second->setActive();
//SL_LOG("Setting sampler %s to use texture %s in texture unit %i", p.first.c_str(), p.second->getName().c_str(), p.second->getTextureUnit());
SLShaderProgram::getCurrentShader()->texture(p.first, p.second->getTextureUnit());
}
glDrawArrays(GL_QUADS, 0, 4);
foreach(SLTexSamplePair p, list)
{
p.second->setInactive();
}
glDisableVertexAttribArray(vertex_loc);
glDisableVertexAttribArray(t_coord_loc);
}
And these routines do cause a leak:
inline void SLRenderer::drawLine(cml::vector4f& colour, Uint32 thickness, GLuint index)
{
SL_ASSERT(SLShaderProgram::getCurrentShader() != NULL, "ERROR: Current shader is null for some reason.");
static GLuint vertex_loc;
static string v_name("vertex_in");
vertex_loc = SLShaderProgram::getCurrentShader()->getAttributeLocation(v_name);
glBindBuffer(GL_ARRAY_BUFFER, SLVBOManager::SLVertexManager.VBOID());
glEnableVertexAttribArray(vertex_loc);
glVertexAttribPointer(vertex_loc, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)index);
static string MVM_Name("transform.model_view_matrix");
static string PVM_Name("transform.projection_matrix");
static string col_name("colour_in");
SLShaderProgram::getCurrentShader()->uniformM4(MVM_Name, SLGL::getModVMatrix());
SLShaderProgram::getCurrentShader()->uniformM4(PVM_Name, SLGL::getProjMatrix());
SLShaderProgram::getCurrentShader()->uniformVF4(col_name, colour);
SLRenderer::switchTextures(false);
glEnable(GL_LINE_SMOOTH);
glLineWidth((GLfloat)thickness);
glDrawArrays(GL_LINES, 0, 2); // <-- Offending line, if commented out the memory leak doesn't occur (and, obviously, no drawing is performed)
glDisable(GL_LINE_SMOOTH);
glLineWidth(1.0);
glDisableVertexAttribArray(vertex_loc);
}
inline void SLRenderer::drawPoly(cml::vector4f& col, GLuint offset, int num_points)
{
SL_ASSERT(SLShaderProgram::getCurrentShader() != NULL, "ERROR: Current shader is null for some reason.");
static GLuint vertex_loc;
static string v_name("vertex_in");
vertex_loc = SLShaderProgram::getCurrentShader()->getAttributeLocation(v_name);
glBindBuffer(GL_ARRAY_BUFFER, SLVBOManager::SLVertexManager.VBOID());
glEnableVertexAttribArray(vertex_loc);
glVertexAttribPointer(vertex_loc, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset);
static string MVM_Name("transform.model_view_matrix");
static string PVM_Name("transform.projection_matrix");
static string col_name("colour_in");
SLShaderProgram::getCurrentShader()->uniformM4(MVM_Name, SLGL::getModVMatrix());
SLShaderProgram::getCurrentShader()->uniformM4(PVM_Name, SLGL::getProjMatrix());
SLShaderProgram::getCurrentShader()->uniformVF4(col_name, col);
SLRenderer::switchTextures(false);
glEnable(GL_LINE_SMOOTH);
glDrawArrays(GL_POLYGON, 0, num_points); // <-- another cuplrit
glDisable(GL_LINE_SMOOTH);
glDisableVertexAttribArray(vertex_loc);
}
inline void SLRenderer::drawLoop(cml::vector4f& col, Uint32 thickness, GLuint offset, int num_points)
{
SL_ASSERT(SLShaderProgram::getCurrentShader() != NULL, "ERROR: Current shader is null for some reason.");
static GLuint vertex_loc;
static string v_name("vertex_in");
vertex_loc = SLShaderProgram::getCurrentShader()->getAttributeLocation(v_name);
glBindBuffer(GL_ARRAY_BUFFER, SLVBOManager::SLVertexManager.VBOID());
glEnableVertexAttribArray(vertex_loc);
glVertexAttribPointer(vertex_loc, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)offset);
static string MVM_Name("transform.model_view_matrix");
static string PVM_Name("transform.projection_matrix");
static string col_name("colour_in");
SLShaderProgram::getCurrentShader()->uniformM4(MVM_Name, SLGL::getModVMatrix());
SLShaderProgram::getCurrentShader()->uniformM4(PVM_Name, SLGL::getProjMatrix());
SLShaderProgram::getCurrentShader()->uniformVF4(col_name, col);
SLRenderer::switchTextures(false);
glEnable(GL_LINE_SMOOTH);
glLineWidth((GLfloat)thickness);
glDrawArrays(GL_LINE_LOOP, 0, num_points); // <--Again, same thing
glLineWidth(1.0);
glDisable(GL_LINE_SMOOTH);
glDisableVertexAttribArray(vertex_loc);
}
Now, I’m using a 5000HD series Radeon card, and I have encountered bugs in AMD/ATI’s OpenGL implementation before (most recently the new shader-utilising version of the engine was drawing quads with bizarre faded-out edges until I upgraded the drivers). Is this a known bug, or am I just doing something stupid?