I have an application that makes a beautiful solid model with OpenGL. When I close the window, the memory is not released. There must be a simple function call that will close everything and release it – but I cannot find it. Do I have to do a glDeleteBuffers(…) for everything individually? After many windows are opened and closed, the application crashes, likely because of the memory limit.
Destroying the context owning the buffer (or all contexts owning a buffer for shared contexts) should destroy the buffer. Likewise for textures.
The only things I create are two call lists:
glCallList(m_OGLraylistName);
glCallList(m_OGLlistName);
Each of these has many data items. When I close the window, I delete them:
glDeleteLists( m_OGLlistName,1 );
glDeleteLists( m_OGLraylistName,1 );
How does one destroy the context? I know very little about OpenGL. Can you give me an example?
Running my program in Debug mode, the Task Manager says I’m using 9.3 MB. When I display the OpenGL window, it says 74.4 MB. When I close the window, it says 65.0. So something is still hogging lots of memory.
You would have to have much more initiation-code to present something on the screen. I’m not very proficient on old style opengl. Popping a default old-style opengl project on my windows-pc ends the program with
void DisableOpenGL (HWND hwnd, HDC hDC, HGLRC hRC)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hRC);
ReleaseDC(hwnd, hDC);
}
Maybe you can tell us about the platform you use or more on how you make something appear on the screen in the first place.
What about the data you display? I would come from a file that could be open still?
Certainly. Here’s how I create the window:
BOOL CmyOGLView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
if (A.JDATSW[106] == 1) wndout("Create\r\n");
m_matrix[0] = 0.0;
m_matrix[1] = 0.0;
m_matrix[2] = 0.0;
m_matrix[3] = 0.0;
m_matrix[4] = 0.0;
m_matrix[5] = 0.0;
m_matrix[6] = 0.0;
m_matrix[7] = 0.0;
m_matrix[8] = 0.0;
m_matrix[9] = 0.0;
m_matrix[10] = 0.0;
m_matrix[11] = 0.0;
m_matrix[12] = 0.0;
m_matrix[13] = 0.0;
m_matrix[14] = 0.0;
m_matrix[15] = 0.0;
m_rotX = m_matrix[0];
m_rotY = m_matrix[4];
m_rotZ = m_matrix[8];
float tint = 1.0;
m_clearColor[0] = tint; // red
m_clearColor[1] = tint; // green
m_clearColor[2] = tint; // blue
m_clearColor[3] = tint; // alpha (says the book; but it must = tint to work!)
// local variables
HDC hDC ;
HGLRC hglrc ;
// obtain a device context for the window
hDC = ::GetDC(m_hWnd);
OGLhDC = hDC;
m_myParent = pParentWnd;
return CScrollView::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}
And here is how it is initialized:
void CmyOGLView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
if (A.JDATSW[106] == 1) wndout("OnInitialUpdate \r\n");
asmfixerror();
oglbugcount = 0;
CSize sizeTotal;
sizeTotal.cx = sizeTotal.cy = 100;
SetScrollSizes(MM_TEXT, sizeTotal);
GetWindowRect( &m_OGLarea );
ScreenToClient( &m_OGLarea );
float aspect = float( m_OGLarea.right - m_OGLarea.left )/float(m_OGLarea.bottom - m_OGLarea.top );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
GLdouble left = -5.5;
GLdouble right = 5.5;
GLdouble bottom = -5.5/aspect;
GLdouble top = 5.5/aspect;
GLdouble zNear = -10.0;
GLdouble zFar = 10.0;
glOrtho( left, right, bottom, top, zNear, zFar );
m_red = 1.0;
m_green = 1.0;
m_blue = 1.0;
m_w = 1;
m_isLdragging = false;
m_isRdragging = false;
m_isZooming = false;
m_FangleRot = 90.0; // degrees; click on arrow buttons does this
m_dialogScale = 1.0;
m_oldCx = 0;
m_lastMouseX = 0;
m_lastMouseY = 0;
m_zoomfactor = 1;
m_blackonwhite = GRBLACKONWHITE;
CClientDC ClientDC (this);
HDC hDC = ClientDC.m_hDC;
myOGLView = this;
LastClicked = this;
glFinish();
int nPixelFormat;
static PIXELFORMATDESCRIPTOR pfd = {
sizeof( PIXELFORMATDESCRIPTOR ),
1,
PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA, // PixelType
32, // ColorBits
// 16, // ColorBits
0,0, // RedBits, Redshift
0,0,0,0, // G, B
0,0, // AlphaBits, Shift
0,0,0,0,0, // AccumBits, R, G, B, A
16, // DepthBits
0, // StencilBits
0, // AuxBuffers
0, // iLayerType
0, // Reserved
0,0,0 // LayerMask, VisMask, DamageMask
};
nPixelFormat = ChoosePixelFormat( hDC, &pfd);
SetPixelFormat( hDC, nPixelFormat, &pfd );
hRC = wglCreateContext( hDC );
wglMakeCurrent( hDC, hRC );
glEnable( GL_DEPTH_TEST );
RECT rec;
int cx,cy;
AfxGetMainWnd()->GetClientRect( &rec );
int size = rec.right - rec.left; // width of screen
int tileX,tileY,tilenrows,thistile,tilepointx,tilepointy,indexY,indexX;
float tileSpace,xf;
thistile = A.ISFLAGS[252]; // index, this picture
if ( thistile > 0 ) { // TILE in effect
tileSpace = size*A.SFLAGS[214]*0.191; // spacing, pixels
tileX = size*A.SFLAGS[217]; // start, X, pixels
tileY = size*A.SFLAGS[218]; // start, Y, pixels
tilenrows = A.ISFLAGS[253]; // grid number in X
indexY = (thistile - 1)/tilenrows; // row, this picture
indexX = thistile - tilenrows*indexY ; // column, this picture
xf = 100.0;
tilepointy = tileY + indexY*(tileSpace + xf)*A.SFLAGS[216]; // row location; leave room for frame and toolbar
xf = (15.0 + 0.02645*tileSpace);
tilepointx = tileX + (indexX - 1)*(tileSpace + xf)*A.SFLAGS[216]; // column
rec.top = tilepointy;
rec.left = tilepointx;
rec.right = rec.left + tileSpace*1.1;
rec.bottom = rec.top + tileSpace*1.3;
A.ISFLAGS[252]++; // ready next
} else {
cx = 500 + (rec.right - rec.left)/2;
rec.top = 0;
rec.bottom = 640;
rec.left = cx - 593; // so circles come out round
rec.right = cx;
}
m_myParent->MoveWindow( &rec ); // set initial position of window
}
The actual data for the display are generated by Fortran programs that feed routines to OpenGL. Here is an example:
void CmyOGLView::OGLaddPolyStrip(float x, float y, float z)
{
if (A.JDATSW[106] == 1) wndout("OGLaddPolyStrip\r\n");
m_vertexCount += 1;
glEdgeFlag( TRUE );
if ( m_vertexCount == 1 ) { // 1st vertex, new panel
m_x1 = x;
m_y1 = y;
m_z1 = z;
} else if ( m_vertexCount == 2 ) {
m_x2 = x;
m_y2 = y;
m_z2 = z;
} else if ( m_vertexCount == 3 ) { // 2nd vertex
m_x3 = x;
m_y3 = y;
m_z3 = z;
} else if ( m_vertexCount == 4 ) { // need surface normals
m_x4 = x;
m_y4 = y;
m_z4 = z;
findNormal(); // from 2, 3, 4
glNormal3f( m_normalx, m_normaly, m_normalz );
glVertex3f( m_x1, m_y1, m_z1 );
glVertex3f( m_x2, m_y2, m_z2 );
glVertex3f( m_x3, m_y3, m_z3 );
glVertex3f( m_x4, m_y4, m_z4 );
m_x2 = m_x4;
m_y2 = m_y4;
m_z2 = m_z4;
} else if ( m_vertexCount == 5 ) {
m_x3 = x;
m_y3 = y;
m_z3 = z;
} else if ( m_vertexCount == 6 ) { // need surface normals
m_x4 = x;
m_y4 = y;
m_z4 = z;
findNormal(); // from 2, 3, 4
glNormal3f( m_normalx, m_normaly, m_normalz );
glVertex3f( m_x3, m_y3, m_z3 );
glVertex3f( m_x4, m_y4, m_z4 );
m_x2 = m_x4;
m_y2 = m_y4;
m_z2 = m_z4;
m_vertexCount = 4;
}
}
I initialize things here:
void CmyOGLView::IVme() // called once to initialize screen and display list
{
if (A.JDATSW[106] == 1) wndout("IVme\r\n");
float tint = 0.0;
if ( !m_blackonwhite ) {
m_clearColor[1] = ( graphicsBK & 0xff )/255.0;
m_clearColor[2] = (( graphicsBK & 0xff00 )/256.0 )/255.0;
m_clearColor[3] = (( graphicsBK & 0xff0000 )/65536.0 )/255.0;
m_clearColor[0] = 0.0; // alpha
} else {
tint = 1.0;
m_clearColor[0] = tint; // N/C
m_clearColor[1] = tint; // red
m_clearColor[2] = tint; // green
m_clearColor[3] = tint; // blue
}
m_dAlpha = 1.0; // opaque
// glShadeModel( GL_SMOOTH );
glShadeModel( GL_FLAT );
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glEnable( GL_LIGHT1 );
glEnable( GL_DEPTH_TEST );
glEnable( GL_BLEND ); // required for transparent effect
glEnable( GL_NORMALIZE );
glDisable( GL_COLOR_LOGIC_OP );
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
// glEnable( GL_LINE_SMOOTH ); // makes fat dull lines
// glEnable( GL_POLYGON_SMOOTH ); // makes gaps between panels
goHome(); // initializations mostly there
m_OGLlistName = glGenLists(1);
m_OGLraylistName = glGenLists(2);
glNewList( m_OGLlistName, GL_COMPILE_AND_EXECUTE );
}
And render the scene this way:
void CmyOGLView::RenderScene()
{
if (A.JDATSW[106] == 1) wndout("RenderScene\r\n");
try {
SwapBuffers( OGLhDC );
glGetFloatv( GL_MODELVIEW_MATRIX, m_matrix );
}
catch (char *ErrorMsg) {
wndout( ErrorMsg );
}
}
Here’s a sample of the display:
Does this tell you what you need to know?
Following your suggestion, I have added some code to the OnDestroy():
glDeleteLists( m_OGLlistName,1 );
glDeleteLists( m_OGLraylistName,1 );
HDC hDC ;
hDC = ::GetDC(m_hWnd);
wglMakeCurrent(hDC, NULL);
wglDeleteContext(hRC);
myOGLView = NULL;
CScrollView::OnClose();
CScrollView::OnDestroy();
This runs, but the memory is still not returned. What else can I try?
As you were. I think the
wglDeleteContext(hRC);
did the trick. Memory increases with each instance of the window – but only by a small amount. So I think the problem is fixed. Thank you very much!