PDA

View Full Version : Multithread texture loading (new facts)



GeorgeSarkisyan
05-11-2003, 09:37 PM
Hi.

Returning to my previous question about simultaneous rendering and texture loading.

Short remind.
I have two threads, two RC with shared texture names. In the first thread I in general call glBindTexture and glDrawElements in the second I call glBindTexture and glTexImage2D. Everything works perfectly. But very seldom some 5 seconds stalls occure. Debuggin shows that during these stalls the rendering thread is within glBindTexture and the loading thread is within glTexImage2D. Further investigation shows that stalls do not take place in the case of two processor system or one processor system and equal priority threads.
In the case of one processor system and loading thread priority that is one point below the rendering thread priority stalls occure.

So I would appreciate any comments from people who's aware of OpenGL drivers inner structure (particularly NVidia's).

Thanks.

knackered
05-11-2003, 11:43 PM
So you're saying that you've got 2 GL render contexts, which use glShareLists(?) to share texture objects? And you have these 2 contexts in 2 separate threads, one uploading texture data to the shared texture objects, the other one rendering geometry using the shared texture objects?
One question:
What synchronisation measures are you taking?
In other words, how are you guaranteeing that the texture uploading thread isn't context switched to the render thread in the middle of a texture upload procedure?

GeorgeSarkisyan
05-12-2003, 12:54 AM
What exactly do you mean?
OpenGL RC is not switched at all. Each thread has its own RC.
Do you mean switching of processor from one thread to another? Well what's the problem? Of course it depends on driver realization but from my point of view switching of processor resource to rendering thread while loading thread is within glTexImage2D should not be something inappropriate. I do not use the same TextureName in both tread simultaneously. Anyway driver could protect any possible collisions by critical sections and don't stall for 5 seconds (by the way may be this 5 sec is a value of some time restricted synchronization object?).
Remember that in the case of equal priority threads everything is ok. No texture corruption, nothing.

So what's your opinion?

Thanks

knackered
05-12-2003, 01:01 AM
Originally posted by GeorgeSarkisyan:
I do not use the same TextureName in both tread simultaneously. Anyway driver could protect any possible collisions by critical sections and don't stall for 5 seconds

Ok, that answers my question.
I'm afraid all I can do now is shrug my shoulders, and leave you to find answers from elsewhere or other people.
Sorry.

CAD_Swede
05-12-2003, 08:03 AM
Originally posted by GeorgeSarkisyan:
OpenGL RC is not switched at all. Each thread has its own RC.

I do believe you have to render the two (or more) RCs in a serial fashion. You can't just throw data from multiple threads into OpenGLs state machine and expect everything to work right. What if you, halfway through a glBindTexture call in thread 1, are switched over to thread 2 which also wants to do a glBindTexture.

I certainly hope that each OpenGL call isn't contained within a CriticalSection or Mutex... That would be just plain awful, I think.

Anyway, my advise is that you render the two or more views after one another. Yes it sucks, and makes dual CPU machines run only on one CPU.. Sorry.

/Henrik

knackered
05-12-2003, 08:09 AM
You can't just throw data from multiple threads into OpenGLs state machine and expect everything to work right

Well, that's the purpose of contexts, isn't it? Both contexts have separate sets of states.
I think because you're sharing lists/textures using wglsharelists, then you have to treat both threads as if they share a context - if they shared a context, then that context can only be current to one thread at a time....so maybe it's the same for shared resources such as textures...a shared texture can be current to only one context at a time (although the MSDN docs don't mention this).

CAD_Swede
05-12-2003, 10:23 AM
Originally posted by knackered:
Well, that's the purpose of contexts, isn't it? Both contexts have separate sets of states.

Bah...I should read the docs before I speak..LOL

Anyway, I've had nothing but trouble with multithreaded rendering, so I guess that's why I defaulted to Ignorance. :-)


But, on a side note, wglShareLists seems to only be valid for display lists? MSDN doesn't seem to be mentioning textures per se.

Oh well, I would at least be cautious when using multiple threads to render to multiple contexts. I'm sure it's not the rendering path the driver makers optimize the most. Most apps use one context in one thread and I bet there's a ton of driver optimizations that can be done if you decide to support that path only.

Anyway, I'm ranting..Tell me to shut up.

/Henrik

jwatte
05-12-2003, 11:03 AM
This sounds like priority inversion. The normal-priority thread waits on some lock that the lower-priority thread has acquired. The lower-priority thread is not releasing the lock, because it's pre-empted by something else.

Your task is to figure out what "something else" is. This is really hard if you don't have kernel sources and a reproducible test case, although it can be done. My suggestion is hooking up two-machine debugging, and when the stall happens, immediately break into the kernel. See what thread is currently active, and/or who's holding whatever lock the low-priority thread is waiting on.

If there is nobody else running, then there's a bug or "design choice" somewhere; perhaps the kernel only context switches in lower priority threads every so often, or perhaps the driver uses a time-out of some sort.

Anyway, I don't see why the texture loading thread needs to be lower priority. In fact, I don't see how you need to thread texture loading at all -- the CPU will be busy doing one thing, or the other, and the driver is likely to hold a lock while texture memory is being pushed to, so it seems to me to be mostly pointless to use threading for this case.

GeorgeSarkisyan
05-12-2003, 08:17 PM
Why threading? The original purpose is to provide gradual data loading simultaneously keeping more or less constant FPS rate. The main consumers of my visualization system are large area navy and aircraft simulators. So any "Please wait we're loading..." during training exercise is inappropriate. Loading thread do a lot of work. One part of it is texture loading from resources, may be some texture data processing and uploading the data to texture object. Multithreading ( provided it works Ok) seems to me to be more natural method than organizing some kind of queues for final textures uploading to OpenGL by rendering thread, dividing large textures by small parts for smooth loading and so on.

Why different priorities? Well ideally I would like to divide CPU resources something like 90% for rendering and 10% for unhurried loading. Unfortunately under Win32 it's not an easy thing to do. Or fifty-fifty for equal priority threads case or "all and nothing" for different priority. So my rendering thread (in case of one processor system) sleeps for 10% of frame rendering time letting loading thread (with less priority) to breath.
May be it would be possible to get this 90 to 10 relation for equal priority threads too, but a little bit more complicated.

Thanks for reply.

CAD_Swede
05-12-2003, 09:30 PM
Originally posted by GeorgeSarkisyan:

May be it would be possible to get this 90 to 10 relation for equal priority threads too, but a little bit more complicated.


Ok, I think I understand what you want to do now. If I don't, I apologize.

I would recommend you to don't worry too much about separate 90-10 priorities and do something simple like this:

Two threads: one renderer and one file loader thread.

When you encounter a situation where you need to load new geometry/textures, you let the file loader thread load the data, then once the data is loaded, hand over the new data to the renderer. Then the renderer does all the uploading to the card, etc, with minimum interference.

Letting the file loader thread upload the data to the card as well will just make things more complex.

Maybe this is too simple and I just haven't groked the problem. Then again, I haven't had my coffee yet :-)

For multiple rendering contexts/graphical views, you should have one file loader thread and two rendering threads, and let the file loader thread just hand over the data to both the renderers...

Again, tell me to shut up if I'm talking about something completely different.

/Henrik

V-man
05-13-2003, 04:09 AM
What you are doing is clever, but you have to realize that you are dependent on the opengl drivers. Some drivers work smarter with multiple contexts sharing resources and such, and some are made to work better with a single RC (they dont have to deal with switchs).

You are using some NVidia product as I remember from your last thread on this matter. I think it's best to register with Nvidia as a developer (developer.nvidia.com) and ask them, if you havent done so.

One of the main questions is, what happens to a low priority thread who is uploading a "big" texture?