Memory leak in glDrawArrays?

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?

I’m having a memory leak as well with some OpenGL code using Ati drivers (HD4870). I haven’t been able to track down the problem yet, but I’m 95% sure it is not my own code that causes the leak. Unfortunately using a tool like memgrind isn’t possible with Ati drivers (it generates millions of errors because the drivers themselves do some tricky things with memory allocation which are not understood by memgrind).

Should I have put this somewhere else?

Most regular readers will probably read this topic, however if nobody shares your experience, there is not much too comment. You could try to create a minimal example program that demonstrates the bug which can be downloaded by others. That way they can test it for themselves (and maybe provide usefull feedback).

There is also a drivers section on these boards. If you would have placed it overthere, the chances some AMD guy would see it would have been slightly better I think. You can also try and PM the AMD employees who have an account on this forum (Pierre Boudier, frank li, maybe others).

Maybe I could get a moderator to shuffle this over to the driver section in their own time, then? It’s not urgent, at the current rate of memory consuption and under ideal conditions the leak would take something like 582 hours to crash a program that’ll probably be run for 2, unless I’ve got the math wrong. Would it be considered proper to use the notify button to make the request?

I was actually more concerned when I posted this that I’d done something stupid with glDrawArrays, but after scrathing my head for a while, I can’t see that I have.

I don’t think there’s a problem with it being here, my (perhaps flawed) understanding is that drivers is more oriented towards end users looking for drivers. Then again this is probably isolated to a specific class of driver. Having it here is a reasonable sanity check.

Indeed, that is a flawed understanding :slight_smile:
End users should go to End users forum section.

Having it here is a reasonable sanity check.

Agreed.

I encounter the same behaviour, no idea if glDrawElements ‘leaks’ too. Nvidia 9600GT

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.