Hi.
I have been experiencing a memory leak when using pixel buffer objects to update textures. The leak seems to only occur on certain platforms with certain operating systems, and so we began to suspect the leak is occurring inside the Intel HD Series Windows 7 driver. Below is a summary of our testing on different platforms.
Can anyone tell if I’m doing something wrong in the code, or if this is potentially a driver leak?
Series 4 Chipset (Lenovo SL300), Windows XP SP3: No Leak
Series 4 Chipset (Lenovo SL300), Windows 7: Leaks ~500 kB/min
Intel HD Series (Lenovo X1), Windows 7: Leaks ~500 kB/min
Intel HD 3000 (11" MacBook Air) Mac OS 10.7.3: No Leak
Nvidia Quadro NVS, Windows XP: No Leak
Here is a stripped down version of the code to reproduce this issue (VS2008 project at http://www.viionsystems.com/Intel_HD_Series_Win7_Leak_Test_Case.zip). Extensive testing of this code shows no memory leaks detectable by VS2008’s memory leak detector, yet GPU memory seems to grow indefinitely (according to ProcessExplorer).
I would appreciate any thoughts from the community on this issue.
#include <stdio.h>
#include <windows.h>
#include "GL\GLee.h"
#include "GL\freeglut.h"
unsigned int w = 640;
unsigned int h = 480;
unsigned int s = 4;
char* img = NULL;
char* texData1 = NULL;
char* texData2 = NULL;
char* mappedBuf = NULL;
GLuint pixelbufferHandle;
void timerCallback(int value);
void initializeTextureBuffer();
void mapAndCopyToBuffer(char* img1);
void paintGL();
void changeSize(int w, int h);
GLuint errorCode;
#define checkForGLError() \
if ((errorCode = glGetError()) != GL_NO_ERROR) \
printf("OpenGL error at %s line %i: %s", __FILE__, __LINE__-1, gluErrorString(errorCode) );
int main(int argc, char **argv)
{
texData1 = new char[w * h * s];
texData2 = new char[w * h * s];
memset(texData1, 85, w * h * s);
memset(texData2, 170, w * h * s);
img = texData1;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(300, 300);
glutInitWindowSize(w, h);
glutCreateWindow("Window");
glutDisplayFunc(paintGL);
glutReshapeFunc(changeSize);
initializeTextureBuffer();
timerCallback(0);
glutMainLoop();
glDeleteBuffers(1, &pixelbufferHandle);
delete[] texData1;
delete[] texData2;
return 0;
}
void initializeTextureBuffer()
{
glGenBuffers(1, &pixelbufferHandle);
checkForGLError();
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelbufferHandle);
checkForGLError();
glBufferData(GL_PIXEL_UNPACK_BUFFER, w * h * s, 0, GL_DYNAMIC_DRAW);
checkForGLError();
// initialize and upload the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
checkForGLError();
// Specify filtering and edge actions
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_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
img = (char*) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
if (img == NULL){
return;
}
memset(img, 0, w * h * s);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
}
void mapAndCopyToBuffer(char* img1)
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pixelbufferHandle);
mappedBuf = (char*) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
memcpy(mappedBuf, img1, w * h * s);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
mappedBuf = NULL;
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelbufferHandle);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
}
void paintGL()
{
if (img == texData1) img = texData2;
else img = texData1; // swap images
mapAndCopyToBuffer(img);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glDisable(GL_BLEND);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_MULTISAMPLE);
glBegin(GL_QUADS);
{
glTexCoord2f(0,0); glVertex3f(-1, 1, 0);
glTexCoord2f(1,0); glVertex3f(1, 1, 0);
glTexCoord2f(1,1); glVertex3f(1, -1, 0);
glTexCoord2f(0,1); glVertex3f(-1, -1, 0);
}
glEnd();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glutSwapBuffers();
}
void changeSize(int w, int h)
{
glViewport(0, 0, w, h);
}
void timerCallback(int value)
{
glutPostRedisplay();
glutTimerFunc(5, timerCallback, 0);
}