26

In my application I am using extensively glTexImage2D. I copy some image of an image and render it as a texture, I do it frequently at every mouse click. I give it as a byte array for rendering. The memory is being eaten up and the swap memory is also allocated. Is it a memory leak? or is it due to the fact that glTexImage2D holds any references or anything else.

Edit:

    //I allocate the memory once
    GLuint texName;
    texture_data = new GLubyte[width*height];

    // Each time user click I repeat the following code (this code in in callback)
    // Before this code the texture_data is modified to reflect the changes
    glGenTextures(3, &texname);
    glBindTexture(GL_TEXTURE_2D, texname);
    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);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE,texture_data);

I hope your close requests and down voting would stop now!

Shan
  • 18,563
  • 39
  • 97
  • 132

1 Answers1

53

Assuming you're generating a new texture with glGenTextures every time you call glTexImage2D, you are wasting memory, and leaking it if you don't keep track of all the textures you generate. glTexImage2D takes the input data and stores it video card memory. The texture name that you bind before calling glTexImage2D - the one you generate with glGenTextures is a handle to that chunk of video card memory.

If your texture is large and you're allocating new memory to store more and more copies of it every time you use it, then you will quickly run out of memory. The solution is to call glTexImage2D once during your application's initialization and only call glBindTexture when you want to use it. If you want to change the texture itself when you click, only call glBindTexture and glTexImage2D. If your new image is the same size as the previous image, you can call glTexSubImage2D to tell OpenGL to overwrite the old image data instead of deleting it and uploading the new one.

UPDATE

In response to your new code, I'm updating my answer with a more specific answer. You're dealing with OpenGL textures in the wrong way entirely The output of glGenTextures is a GLuint[] and not a String or char[]. For every texture you generate with glGenTextures, OpenGL gives you back a handle (as an unsigned integer) to a texture. This handle stores the state you give it with glTexParameteri as well a chunk of memory on the graphics card if you give it data with glTexImage[1/2/3]D. It's up to you to store the handle and send it new data when you want to update it. If you overwrite the handle or forget about it, the data still stays on the graphics card but you can't access it. You're also telling OpenGL to generate 3 textures when you only need 1.

Seeing as texture_data is of a fixed size, you can update the texture with glTexSubImage2D instead of glTexImage2D. Here is your code modified to avoid the memory leak from this issue:

texture_data = new GLubyte[width*height]();
GLuint texname; //handle to a texture
glGenTextures(1, &texname); //Gen a new texture and store the handle in texname

//These settings stick with the texture that's bound. You only need to set them
//once.
glBindTexture(GL_TEXTURE_2D, texname);
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);

//allocate memory on the graphics card for the texture. It's fine if
//texture_data doesn't have any data in it, the texture will just appear black
//until you update it.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB,
    GL_UNSIGNED_BYTE, texture_data);

...

//bind the texture again when you want to update it.
glBindTexture(GL_TEXTURE_2D, texname);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, 0, GL_RGB,
    GL_UNSIGNED_BYTE, texture_data);

...

//When you're done using the texture, delete it. This will set texname to 0 and
//delete all of the graphics card memory associated with the texture. If you
//don't call this method, the texture will stay in graphics card memory until you
//close the application.
glDeleteTextures(1, &texname);
Robert Rouhani
  • 14,512
  • 6
  • 44
  • 59
  • Thanks a lot, I have posted the code, So as you can see that I use the same memory just change the contents and always do the same thing. So according to your suggestion in above code snippet I only need to call "glGenTextures" once and then always call glBindTexture and glTexImage2D. It will prevent the memory leak. Am I correct? – Shan Jun 27 '12 at 06:00
  • 1
    @Shan updated my answer with code and (hopefully) enough explanation so that you understand where the leak is coming from within your code and how to fix it. Also use the OpenGL manual in the future, it's very helpful in explaining exactly what OpenGL methods do: http://www.opengl.org/sdk/docs/man/xhtml/glGenTextures.xml – Robert Rouhani Jun 27 '12 at 06:54
  • thanks a lot, Excellent answer!, actually i have updated the code, It was messed up, the type is GLuint for texname.Just a query, I have more than one textures, how glTexSubImage2D would know which one I am updating? or it is due to the call to glBindTexture. – Shan Jun 27 '12 at 07:07
  • 3
    Yes, all methods that deal with textures (and later with buffer objects, shaders, programs, etc... anything that requires a `glGen*` call) will only affect the texture that you bind with `glBindTexture`. That is the general structure of OpenGL. If you want to stop using that texture and you don't want to replace it with another texture, you can unbind by passing 0 to `glBindTexture` instead of your texture handle. – Robert Rouhani Jun 27 '12 at 07:12
  • You should add () after new GLubyte[width*height] to initialize the array to 9, otherwise the access inside glTexImage2D invokes undefined behaviour due to uninitialized access. – Jacob Parker Jun 30 '13 at 23:45
  • Very helpful answer. But, what if i have many different textures? I asked here http://stackoverflow.com/q/23943320/1374065, but no one answered. May you help me with this? I need some kind of map, to track existing textures by their handle, and call glDeleteTextures when texture is hidden and no longer used. – vanste25 Jun 10 '14 at 11:10
  • @vanste25 Your question is more of a high-level algorithm thing than an OpenGL thing, but I gave some of my thoughts anyways. – Robert Rouhani Jun 10 '14 at 15:31
  • Yes, i know, but it is tightly connected with openGL :) Thank you, i will consider your answer! – vanste25 Jun 10 '14 at 15:54