Texture and memory questions

hi all, i got a problem here about taking place 3D texture and release 3D texture.
The 1st is why after 3D large data set was uploaded into memory by glTexSubImage3D, the return value was 1285(out of memory) by glGetError, however the current video memory and os memory still remain enough space.
The 2nd is why the copy memory coming from 3D texture won’t be released when glDeleteTextures is invoked? How can I get back this memory. Is there any problem with this kind of API or anything else?
So, can anyone help me explain OpenGL mechanism between texture and memory.

Any answers will be appreciated, thanks all.

however the current video memory and os memory still remain enough space.

What are you using to determine this?

The 2nd is why the copy memory coming from 3D texture won’t be released when glDeleteTextures is invoked?

The driver will release memory when it feels that it should.

The aid tool name is RivaTuner which can monitor video memory & os memory, and other hardwares.

GPU memory is used for other purposes besides texture. Namely the display system, window framebuffers for your application and others, off-screen render targets, etc. It’s possible enough is already consumed to throw off your estimates as to what memory is actually free.

Perhaps others could help you if you described specifically your computations and method for determining the amount of memory you think the 3D texture will consume, and the amount of memory you think is free.

Also keep in mind that both a GPU and CPU copy of the data is maintained. So the failure to get sufficient memory could be a GPU-side thing or a CPU-side thing. You might also be exceeding the supported dimensions for a 3D texture on your GPU/driver.

The 2nd is why the copy memory coming from 3D texture won’t be released when glDeleteTextures is invoked? How can I get back this memory. Is there any problem with this kind of API or anything else?

How do you know that this memory isn’t being released?

If you’re talking CPU memory, what is possibly happening is that when you do the initial allocation, the memory is obtained from the OS and assigned to the application, added to the application heap, and then the application (driver) allocates that memory to maintain the texture data. When the texture is freed, the memory is merely put back on the application heap, but that total heap size is not “shrunk” by giving the memory back to the operating system.

…but this is all just a guess because you haven’t given us any details on your data gathering method or your calculations, for GPU or CPU base available space and space consumption.

For GPU memory monitoring, one good bet is to use OpenGL extensions such as NVX_gpu_memory_info and ATI_meminfo to probe and see what’s going on and how much memory things actually take. Using this, you might find a fault in your space estimate heuristics.

The aid tool name is RivaTuner which can monitor video memory & os memory, and other hardwares.

If you allocate another texture of the same size as the previous one, does the client memory size increase?

Thanks a lot, friends. I have found the reason about question 2, that the texture data format of glTexSubImage3D is not the same as glTexImage3D invoked.
About question 1, I just follow the order, that is from creating texture, to taking place texture, to deleting texture, seveal times later I can’t create texture or take place it successfully. Im realy confused.

Post a short test program that illustrates the problem, so folks can review it, try it, and provide feedback/advise.

The following is my partail code concern texture:

Create texture:


	GLenum err = GL_OUT_OF_MEMORY;
	m_iDivident = 0;
	glGenTextures(1, &m_iTex3D);
	glBindTexture(GL_TEXTURE_3D, m_iTex3D);
	while (err == GL_OUT_OF_MEMORY)
	{
		m_iDivident++;
		div_t div_layer = div(m_pData->numSlices[2], m_iDivident);
		m_pData->volTexSizes[2] = div_layer.quot + div_layer.rem;
		glTexImage3D(GL_TEXTURE_3D, 0, GL_COMPRESSED_ALPHA_ARB, m_pData->volTexSizes[0], m_pData->volTexSizes[1],
			m_pData->volTexSizes[2], 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
		err = glGetError();
	}
        glTexEnvi(GL_TEXTURE_3D, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

Take place texture:


	unsigned char *pchData = NULL;
	int di, idz, idy, idx, iNum;
	short nCT = 0;
	iNum = 1;
	div_t divPiece;
	while (!pchData)
	{
		iNum++;
		divPiece = div(m_pData->volTexSizes[2], iNum);
		pchData = (unsigned char*)calloc(m_pData->volTexSizes[0] *
						m_pData->volTexSizes[1] *
					        divPiece.quot+divPiece.rem), sizeof(unsigned char));
	}
	
    nCT = 0;
	
	float fCon = 0.0625f;
	NIL::CCubeCT* pCube = m_pData->volData;
	GLenum err;
	glBindTexture(GL_TEXTURE_3D, m_iTex3D);
	for (int i = 0; i < iNum; i++)
	{
		di = 0;
		int iLayerBegin = i*(divPiece.quot)*m_iDivident;
		int iLayerEnd = (i+1)*(divPiece.quot*m_iDivident+divPiece.rem);
		if (i == iNum-1)
		{
			iLayerEnd = m_pData->numSlices[2];
		}
		for (idz = iLayerBegin; idz < iLayerEnd; idz+=m_iDivident) {
			for (idy = 0; idy < m_pData->numSlices[1]; ++idy) {
				for (idx = 0; idx < m_pData->numSlices[0]; ++idx) {
				        nCT = pCube->GetFast(idx, idy, idz);
				        pchData[di] = (unsigned char)(nCT * fCon); 
                                        di++;
				}
			}
		} 
		glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, i*divPiece.quot, m_pData->volTexSizes[0], m_pData->volTexSizes[1], 
			divPiece.quot+divPiece.rem, GL_ALPHA, GL_UNSIGNED_BYTE, pchData);
		err = glGetError();
	}
	free(pchData);

Delete texture:


	if (m_iTex3D)
	{
		glDeleteTextures(1, &m_iTex3D);
		m_iTex3D = 0;
	}

No, I mean “really”. Post a short test “program” that illustrates the problem, so folks can review it and try it (without having to waste the time cooking one themselves).

Here’s a template to pop your code into and verify that its still broken. It could be very well be something else in your code that’s causing the problem, and cooking a short test program eliminates that possibility.

#include <stdio.h>
#include <stdlib.h>
#define GL_GLEXT_PROTOTYPES 1
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

void checkGLErrors( const char *s )
{
  while ( 1 )
  {
    int x = glGetError() ;

    if ( x == GL_NO_ERROR )
      return;

    fprintf( stderr, "%s: OpenGL error: %s", 
             s ? s : "", gluErrorString ( x ) ) ;
  }
}


void keybd ( unsigned char, int, int )
{
  exit ( 0 ) ;
}


void reshape(int wid, int ht)
{
  glViewport(0, 0, wid, ht);
}

void showGLerror ()
{
  GLenum err ;

  while ( (err = glGetError()) != GL_NO_ERROR )
    fprintf ( stderr, "OpenGL Error: %s
", gluErrorString ( err ) )  ;
}


void display ( void )
{
  static float a = 0.0f ;

  a += 0.3f ;

  glMatrixMode      ( GL_PROJECTION ) ;
  glLoadIdentity    () ;
  glFrustum         ( -1.0f, 1.0f,
                      -1.0f / (640.0f/480.0f), 1.0f / (640.0f/480.0f),
                      3.0f, 10.0f) ;

  glMatrixMode      ( GL_MODELVIEW ) ;
  glLoadIdentity    () ;
  glTranslatef      ( 0.0, 0.0, -5.0 ) ;
  glRotatef         ( a, 0.2, 0.7, 0 ) ;

  glEnable          ( GL_DEPTH_TEST ) ;
  glEnable          ( GL_CULL_FACE  ) ;
  glCullFace        ( GL_FRONT ) ;

  glClearColor      ( 0.0f, 0.0f, 0.0f, 1.0f ) ;
  glClear           ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;

  glutSolidTeapot   ( 1.0f ) ;

  glutSwapBuffers   () ;
  glutPostRedisplay () ;

  checkGLErrors     ( "display" ) ;
}


int main ( int argc, char **argv )
{
  // Init GL context
  glutInit            ( &argc, argv ) ;
  glutInitDisplayMode ( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE ) ;
  glutInitWindowSize  ( 500, 500 ) ;
  glutCreateWindow    ( "GL Test" ) ;
  glutDisplayFunc     ( display  ) ;
  glutKeyboardFunc    ( keybd    ) ;
  glutReshapeFunc     ( reshape  ) ;

  // Put create/setup code here

  checkGLErrors       ( "end of setup" ) ;

  // Draw with shader
  glutMainLoop () ;
  return 0 ;
}

I think if you do this, and sprinkle some checkGLError() calls around, you’ll find that this:

glTexEnvi(GL_TEXTURE_3D, GL_TEXTURE_ENV_MODE, GL_REPLACE);

trips an invalid enumerant. The first argument to glTexEnvi must be GL_TEXTURE_ENV.

Thanks for your advice, however I have already debugged the program by glGetError on necessary place. There is no error return.

I forgot to give my large data details.
Everything is ok when I upload normal data which is around 512512512 byte. In contrast, the program got errors after I uploaded large data which is 5125121624 byte.

Everything is ok when I upload normal data which is around 512512512 byte. In contrast, the program got errors after I uploaded large data which is 5125121624 byte.

Of course you got an error. GL_MAX_3D_TEXTURE_SIZE is 512 for most hardware. So you can’t have a 512x512x1624 texture.

Also, 5125121624 is 406 MegaTexels. Even as a 16-bit texture, this is over 800 megatexels. 24-bit or 32-bit blows past 1GB just for this one texture alone. One of the reasons why most cards cap 3D texture sizes to 512 is due to the sheer quantity of space that such textures take.

Yeah, that’s crazy to try 5125121624.

That’s basically 1,624 512x512 textures all mapped to one mega texture.

I don’t know what you are trying to do, but similarly to working with mega textures you have to figure how to break it up for selective use (at least on current hardware).

My video card is 9800 GTX, and I have gotten the max 3D texture size that is 2048.

I am tring volume rendering on huge data. Sometimes the texture data was selected accroding to interlayer, but it will make the image quality reduce. How did u break up the texture to use?

My video card is 9800 GTX, and I have gotten the max 3D texture size that is 2048.

And what about the memory size? Just because you can allocate a texture with dimensions that large doesn’t mean that memory limitations will permit it. As I pointed out, even at 16bpp, that’s an 800MB texture. 24bpp is 1.2GB, which is probably more than a 9800GTX has space for.

My video memory size is 512MB. As I mentioned above, per pixel is stored by the type of unsigned byte, so the total texture size is around 406MB.

Well, does 5125122048 work if you have enough memory?

What about 5125121024?

Maybe your card requires it to be pow sized.

No, it won’t work when 2 sets of data you mentioned are uploaded into texture, but such as 512512362, 512512461 and 512512520 are OK!

So, I suspect whether the limitation of current application thread, that only can access the maximum 2GB memory, affects OpenGL operation or not?

So, I suspect whether the limitation of current application thread, that only can access the maximum 2GB memory, affects OpenGL operation or not?

Threads all share memory; it is the process that is limited to 2GB (on 32-bit machines).

And yes, this affects OpenGL. However, what more than likely also affects OpenGL is trying to allocate 4/5ths of the GPU’s total memory in one texture.

Just because something theoretically fits doesn’t mean it actually fits.