Sign in to follow this  

threaded texture loading

This topic is 3501 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey folks, I'm trying to do asynchronous loading of texture data and other resources from disk. The way I do this is to have a separate thread with an input queue where I put all the resource loading requests. When the data has been loaded in the data reader thread, the rendering thread can start using them. I guess this is a pretty common way of doing things. However, I'm experiencing big problems with frame rate stuttering. Even if the textures are loaded in a separate thread the rendering thread is suffering major fps loss when the data reader thread is busy. These problems are the same on a variety of test machines, many of them fast multicore computers. I have run this code on Linux, Windows and OSX with pretty much the same results. I have tried inserting sched_yield() calls and sleep/usleep() calls in the data reader thread, and then it runs smoother, but it seems to be heavily downprioritized by the kernel so that the data loader runs way too slow... Is there anything here I have missed, any tips or help would be highly appreciated. Cheers!

Share this post


Link to post
Share on other sites
Does your other thread need to access the HDD? If so, it will obviously be bottlenecked by the (sloooooow) access time to the disk.

Share this post


Link to post
Share on other sites
All HDD access is put in the data reader thread. There can be multiple reader threads that access the HDD, but the main rendering thread shouldn't need HDD access. It does a bit of disk IO during the initialization, but not after that.

Share this post


Link to post
Share on other sites
It depends on the Threading type that is used by the operating
system or library you are using.

There are 2 types of Threads:
Kernel-Level Threads and User-Level Threads.

i do not know how you access the harddisk but i think you use something
like fopen or fstream. these calls are blocking system calls so if
the created thread is a "User-Level" Thread the whole Process will have to
wait until the read function returns.

All blocking system calls are bad for "User-Level" Threads.

Kernel-Level implementations should not have such problems tough.(afaik)

Maybe you should lower the priority for the texture loading threads.

For more information:
http://en.wikipedia.org/wiki/Thread_%28computer_science%29

Share this post


Link to post
Share on other sites
I'm using pthreads on linux and OSX, which I think are kernel level. On Windows I use Windows threads (CreateThread, etc).

You are right that I'm using fopen/fstream, and it may look like these calls are blocking the process, so this explanation sounds plausible, even though I'm pretty sure I use kernel level threads.

I've tried lowering the priority of the data reader thread, but that just caused the reader thread to stop entirely.

Share this post


Link to post
Share on other sites
Maybe the rendering thread is starving, waiting for texture data to become available, refusing to render meanwhile the data is not ready... just a thought.

Share this post


Link to post
Share on other sites
No, it's not that. The render thread is rendering data even if we have long data loading queues, it just stutters terribly. It uses a dummy texture while the real data is loading. But it seems that the file reading operations are blocking the entire process.

Share this post


Link to post
Share on other sites
That sounds reasonable.I'm not quite sure how to go about it though. Would it help to use lower level file IO calls such as open() and read() instead of fopen() and fread()?

Share this post


Link to post
Share on other sites
I think for async read/write you will have to be platform specific.
so i don´t think you can write code for Linux/Windows that looks the same.

I found a site that describes async io for mainly POSIX 4 systems.

Hope it helps:
http://www.ibm.com/developerworks/linux/library/l-async/

Share this post


Link to post
Share on other sites
I would have expected that doing an asynchronous Read() call in your main thread versus doing a synchronous Read() call in a background thread would have about the same effect, namely, not stalling the main thread.

Any recent (< 10 years old) HDD controller uses DMA, so it can push data read directly into RAM on its own without anything but marginal CPU control. An asynchronous Read() call can thus be more resource-friendly.


Some things to check:

Just to make sure, when your thread isn't doing anything, you're waiting using WaitForMultipleObjects() (or the equivalent pthreads call), not burning the CPU with a while(queue.empty()) {}, right? Otherwise, maybe it might not be the loading that leads to glitches, but the times inbetween ;)

Another place to check would be resource generation. It might take some time to create graphics device resources, so you might want to use a time budget for creating the resources if you aren't already doing so.

Maybe it would even be sensible to use a two-layered approach, run a high-priority thread for loading files (this thread idles most of the times, waiting for new files to enter the queue or files being loaded to finish loading) and a low-priority thread that creates the graphics device resources.

Share this post


Link to post
Share on other sites
Pthreads is implemented on Linux by using processes. Each thread is actually a system process with shared memory. Blocking I/O should definitely block only the thread using it. Are you sure that the I/O is the issue? Maybe the reader thread is using a lot of CPU time for some reason? Have you tried monitoring CPU usage with tops or some other program? Also, you could be memory bandwidth limited and the HD access is cutting into that. Maybe you should use sched_yield() more sparsely?

Share this post


Link to post
Share on other sites
I have made a small test example that loads a huge file in a separate thread while doing some processing in the main thread, and verified that this works just as intended. The loader runs nicely in the background without blocking the processing thread. So I guess that means that the fopen/fread blocking theory wasn't right after all.

The data reader thread uses semaphores to wait for incoming data, and I have verified that it uses almost no CPU at all.

It might be that the texture upload is the bottleneck if a lot of textures finishes loading in the same frame, but I have also tried reducing the number of texture uploads per frame by putting all the finished textures in an output queue and processing only a few of them per frame. I will try to investigate this part a bit more though.

Are there any tools (on linux or windows) that shows when (and why) a thread is blocking?

Share this post


Link to post
Share on other sites

This topic is 3501 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this