Hello Everyone! I have a question about function glTexImage2D.
There is some code that cause GL memory leak on the devices with mali gpu (t760) and force close android application.
....
struct Vertex
{
float x, y, z;
float u, v;
};
...
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, 1440, 2560);
while(true)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texID);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1440, 2560, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
glUseProgram(shader);
int position = glGetAttribLocation(shader, "aPosition");
glVertexAttribPointer(hPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertexBuffer[0]);
glEnableVertexAttribArray(position);
int texCoord = glGetAttribLocation(data.shader, "aTexCoord");
glVertexAttribPointer(texCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertexBuffer[0].u);
glEnableVertexAttribArray(texCoord);
int textureLocation = glGetUniformLocation(shader, "texture0");
glUniform1i(textureLocation, 0);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableVertexAttribArray(position);
glDisableVertexAttribArray(texCoord);
}
The shaders program is a trivial, just gets texture sampler and draws at the target FBO.
This code is just rendering texture into FBO. On each steps texture is updated by glTexImage2D call.
The question is why this code leads to memory leak?
I suppose, the reason is that glTexImage2D on each call allocates new chunk of memory for texture's data.
Texture memory that are used at previous rendering step is never released, until we call glFinish or glBindFramebuffer(GL_FRAMEBUFFER, 0).
It looks like some optimization on driver side, but is it standard behavior? Please, correct me if I'm wrong.
Thanks a lot!
P.S Code above works fine on the devices with Adreno GPU.
Hi, cgrant78!
Thanks for your answer.
I've added generating and deleting texture in the loop.
while(true) { glActiveTexture(GL_TEXTURE0); glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1440, 2560, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); glUseProgram(shader); int position = glGetAttribLocation(shader, "aPosition"); glVertexAttribPointer(hPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertexBuffer[0]); glEnableVertexAttribArray(position); int texCoord = glGetAttribLocation(data.shader, "aTexCoord"); glVertexAttribPointer(texCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertexBuffer[0].u); glEnableVertexAttribArray(texCoord); int textureLocation = glGetUniformLocation(shader, "texture0"); glUniform1i(textureLocation, 0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableVertexAttribArray(position); glDisableVertexAttribArray(texCoord); glDeleteTextures(1, &texID); }
This code works fine on the the device with PowerVR SGX 544MP (Galaxy S4), but on the device with Mali-T760 (Galaxy S6, OS Android 5.0.2) FC occur, (reason: gpu memory leak). Now texture are obviously deleted, but it change nothing. As Rich, said above, it happens due to deferred rendering, and glDeleteTextures calls just enqueue message and don't release resources immediately (as I understand). So, now driver knows that texture isn't needed at all, but memory leak still happens...
Good news...sorry I did miss that point about the TBDR..yeah without the frame terminator all those operations are going to keep queuing up. However, even though the behavior sounds right for such a GPU architecture and looks like in goes against the specification I think its behavior is valid ( though annoying ) since reading the documentation on glDeleteTextures, its only mention that the texture name is deleted free for reuse and nothing about the texture data store.So all the driver has to do is make the name available for re-use, but it may still hold internal references to the texture data.
Btw do you mind mentioning your use case? Just trying to see if I can suggest possible workaround since its unlikely the issue is going get resolve soon( I say this because driver releases on mobile platform is radically different from release on a PC, may have been mentioned already...as we are at the mercy of the device manufacturer and carriers..) -Though it may not be much..texture you are creating is ~3.5 MB in size, after 10 loop iteration thats 35 MB, 100 loop iteration 350 MB...you get the idea. So is it possible for your use case to use a
smaller texture? -Periodically flush ( this I think was mentioned before. ) so that the command queue get drained.
So, thanks guys for yours answers. It helps me understand how it works under hood.
All workaround was mentioned before (I think, the best one is periodically flush (for example, calls glFinish))
I believe, sometime we can see resolved this issue on the driver side
Kind regards,
Igor
Some general observations for "real app" behavior.
HTH, Pete