« Debugging OpenGL on OS X | Main

June 28, 2006

Running out of VRAM on OS X

OpenGL on OS X virtualizes texture memory. This means you can allocate an almost unlimited amount of textures, and the OS will keep them in system memory, and only copy them up to the graphics card when they're needed. This is a lot better than the old model of keeping all textures only in VRAM, and texture creation failing once you run out of memory there. But there's still cases where you have to worry about how much VRAM is available.

The OS will swap out any textures that aren't being used in the current drawing operation to make room in VRAM for the currently active textures. This means that if you're multi-texturing, or using a fragment program to read from multiple textures, the textures that you've assigned to a texture unit and are enabled can't be swapped out. It's important to make clear that the swapping is very aggressive, anything it can remove it will, but if you're doing a texture fetch from a texture in the current operation, it needs to keep that texture around.

This becomes a problem when you have a lot of textures enabled at once, or when they're very large, or when they're high-bit depth, because if they won't fit in VRAM, the current drawing operation will fail and you'll end up with garbage drawn instead. There isn't an error condition or log message output when this happens, so it can be tricky to track down.

To avoid this, you need to work out if your textures will fit in the currently available VRAM before you draw. You can calculate the VRAM usage of an individual texture with

width * height * 4 * bytes per channel

So, a 2048x2048 eight bit per channel texture takes up 2048*2048*4*1 = 16,77,216 bytes, or 16 MB of VRAM.

To work out if you'll run out of VRAM, take all the active texture's memory, add them together, and do the same for the area (pbuffer/window size) that you're drawing to, since that also needs to be in the graphics card while you're drawing.

For a 64 MB graphics card, you can fit four 16 MB textures in at once, so that means you can use three 2048*2048 input textures, if you're drawing into a 2048*2048 pbuffer.

To figure out how much VRAM is available on the card, you need to call


long getAvailableVRAM(void)
{
CGOpenGLDisplayMask displayMask = CGDisplayIDToOpenGLDisplayMask(CGMainDisplayID());
CGLRendererInfoObj info;
CGLQueryRendererInfo(displayMask, &info, &_numRenderers);
long availableVRAM;
CGLDescribeRenderer(_info, 0, kCGLRPVideoMemory, &availableVRAM);
return availableVRAM;
}

and then divide by the number of displays connected to the card, since at least ATI evenly partitions the VRAM between each display.

Posted by petewarden at June 28, 2006 12:31 PM

Comments

You do not need to divide by the number of displays. They allocate the display's framebuffers in separate, possibly non-contiguous, regions of memory but all remaining memory is available for use by contexts connected to either display.

Posted by: Antonio Carpio at September 10, 2006 08:47 AM

Post a comment




Remember Me?