Texture Unload Problem

I originally posted this to the beginners forum, but I received no help there:

I have hundreds of textures that are 1024x1024 in size. I only need to display around 10-20 of those textures at once. I am using texture compression as well. The program displaying the textures will be running on video hardware with at least 128 meg of RAM. I am employing culling code so that I only display what I need to. Here is my problem:
After I first start the program everything is really fast. However, if I pan around the window and view more than 50 of those 1024x1024 compressed textures my frame rate drops to the floor. I suppose that texture swapping is occuring but I only view 10-20 textures at once. It seems to me that the system is trying to load the other textures that I previously (but no longer need to) viewed. Why?
If (after viewing 50 or so textures) I only try to view one texture on screen at a time it is still very slow. However, if I delete all the textures except the ones that I need to view the speed kicks back up again. I thought that since I am culling the other textures and not trying to view them (IE…not calling glBindTexture(…)) the system would not attempt to load them (IE…the swapping I am experiencing).
Any suggestions?

PS
I am setting texture priorities and it appeared to make no difference at all. Maybe I’m doing something wrong. Everytime a texture passes all tests (culling tests, and some other custom tests to determine whether or not to draw a given texture) I bump it’s priority up by 0.1 (my docs say that texture priorities range from 0.0 - 1.0) and clamp it at 1.0. Whenever a attempt to draw a texture and that texture fails a culling test, etc…, I reduce its priority by 0.1.

I don’t know how effective texture priorities are in doing what they claim. In fact, I think that most drivers basically ignore them. It’s probably not worth dealing with.

One suggestiong that is more of a “workaround” than a real solution is to do some manual texture management (as opposed to what you’re trying to accomplish via texture priorities). Keep a “pool” of 10-20 texture handles. When a texture passes your cull tests, allocate a handle to it. If it fails, mark that slot in the pool as free. If you run out of texture handles, delete a texture handle marked as “free” and create a new texture object in that slot.

Perhaps it would also help to sort rendering by most recently used texture. So, on odd frames render in the order textures 1 to n, and on even frame from n to 1.

-Won

It sounds to me like you may be exhausting system memory. Each texture you load will have a copy in system memory whether it is being bound for rendering or not.

In regards to texture priorities: most drivers do not use this information or do not use it well. I suggest keeping your own priority array and deleting the textures when they drop off the list. You’ll then need to check if the texture you wish to bind is actually present in memory or needs to be read off disk, but it sounds like this is what you want to do…

Best of luck at any rate.
– Jeff

Won’t that be slow? I mean building/deleting those textures on the fly will kill my framerates won’t it? Also, I have a future need to use mipmapped textures.

Also, I’m not running out of system memory. I have over 700 meg of system RAM free while running my app.

Originally posted by cru:
I have hundreds of textures that are 1024x1024 in size. I only need to display around 10-20 of those textures at once.

and no mipmapping?
you need a very high resolution in order to show 10 to 20 textures in 1024^2 size… VERY high… use smaller textures or enable mipmapping now…

i dont know if the drivers can swap in/out only part of an texture (ie one mipmap level) but i hope they do, and then you get a nice speed boast… even if the driver cant do that i bet the cards works faster with the correct mipmap level than the maximum sized image.

Ok…say I go ahead and add mipmapping support now. I still can’t creature(gluBuild2DMipmaps(…))/delete textures on the fly.

Does anyone have any solutions? I still have no idea how to fix this problem.

Originally posted by cru:
[b]Ok…say I go ahead and add mipmapping support now. I still can’t creature(gluBuild2DMipmaps(…))/delete textures on the fly.

Does anyone have any solutions? I still have no idea how to fix this problem.[/b]

Hi

if you have OpenGL 1.4 or the GL_SGIS_generate_mipmap extension you can have the hw create your mipmaps on the fly. See the specs for details.
Its in hw on everything above GF3 or Radeon8500.

Bye
ScottManDeath

Originally posted by cru:
[b]Won’t that be slow? I mean building/deleting those textures on the fly will kill my framerates won’t it? Also, I have a future need to use mipmapped textures.

Also, I’m not running out of system memory. I have over 700 meg of system RAM free while running my app.[/b]

It’s worth a try as you won’t be assigning your textures every frame it’ll be a momentary impact “every now and then”. Depends on how much your scene alters. You may find that you only have to assign one or two textures every few seconds (which won’t have too much of an impact).

If you use glTexSubImage2D() then you just need to create your 10-20 textures to start with and then just modify them when you need to.

One more question. Is it possible to load textures in a background thread?

Have you picked up a calculator to see how much memory this needs?

Since you are using compression, you should atempt to approximate how much each will occupy, plus if you will be using mipmaping, it may consume 33% more memory.

Loading textures as a background thread means what? Upload to the video card? There is one video card and even if you have many …

One more unlikely guess, maybe the slowdown is related to texture compression, have you tried disabling it? I don’t know if that’s even possible, but it wouldn’t hurt to try.

Changes are you’ll have to write your own texture management. How you do that depends on what you use those textures for. I can imagine easy solutions for a huge terrain, but not for view-dependent texturing, which is the other application I can think of needing all those textures.

-Ilkka

Originally posted by cru:
One more question. Is it possible to load textures in a background thread?

You can load your texture from disk in another thread, which might be a good idea if you want to implement some advanced prediction/speculation algorithm to pre-load textures before they are actually used (doing it in a separate thread means that it can be done in the background while the main rendering thread is generating GL frames).

You can even upload your texture to texture memory from a second thread, BUT then you need a separate GL context for the second thread that shares lists/texture objects (e.g. wglShareLists) with the GL context for the rendering thread. Having one context per thread can be quite costly (potentially one GL context swicth every time you have a thread context swicth, i.e. every 10-20 ms or so!). This solution may actually hurt performance - so think twice before you do it.

BTW, I’m positive that mipmaps can help performance a great deal (several magnitudes of performance increase in some cases). Also, using GL_SGIS_generate_mipmap is very easy. Just do:

has_GL_SGIS_generate_mipmap = glfwExtensionSupported( "GL_SGIS_generate_mipmap" );

if( has_GL_SGIS_generate_mipmap )
{
    glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE );
    glTexImage2D( ... );
}
else
{
    gluBuild2DMipmaps( ... );
}

(or similar)

I think where was a discussion here some time ago, where the NVidia guys said that when using mipmaps, the entire mipmap pyramid is always kept in texture memory. So if you want to use them to save memory for distant objects, you may have to simulate mipmaps with seperate textures.

-Ilkka

Thanks.

I believe I’ll use a background thread to pull data from disk. I don’t think I’ll be using a seperate rendering context. Everything I’ve read says that will absolutely kill performance. I think I’ll look into GL_GENERATE_MIPMAP_SGIS as well. A doc on nVidia’s site states that this extension is only hardware accelerated when used with either GL_RGB8, GL_RGBA8, or GL_RGB5. Which may suit be just fine.

Google cache link: http://216.239.57.100/search?q=cache:a4F…&hl=en&ie=UTF-8

Thanks for all the info.