how do to control async file loading
I have created a FileManager with async load, it loads some files in a different thread so that I can display an animated logo while loading so the user knows that the app is loading something... but how can I control when it should load a file and when to display the logo? I tested with a check in the renderloop where it controls if there are any files to be loaded, if so display logo and load them.. BUT what if I want to load a file in background while the game is still running?!
If you have a small number of larger files, it is best to load each block of the file in a separate thread, and make your file reader class start pre-fetching the next block when the calling code asks for the current one. That way you can have the CPU process the first block while the second one is loading. If you have a lot of smaller files, you can create a queue of files you want to load, and when one file is finished, it can automatically pre-fetch the first block of the next file. It should be generic enough that you can use this when the game is running or when pausing to load something large (like a level).
You may hear a lot of arguments as to whether the main loading routine, the one that controls the file readers and processes the blocks, should be in a separate thread or not. For certain parts of the game like loading levels, it doesn't really matter at all. When the game is running, it does matter, but it still depends on your implementation. There's no black or white answer for whether it's always right or always wrong.
On a single CPU machine single-threaded implementations generally run faster. Most developers complain about task switching, but the cost of that is almost always insignificant. The real cost lies in synchronization calls. If you have multiple threads and they're each locking/unlocking critical sections or mutexes hundreds of times per frame, it's going to cost a lot. Any time you use threads, you should design them to minimize the number of synchronization calls. In general it's better to have a thread wait for an event than to have it repeatedly check a lock.
Dual-core CPU's are coming soon, and when they become widespread, game developers will be forced to change unless they're writing a game that will run fine on older hardware.
You may hear a lot of arguments as to whether the main loading routine, the one that controls the file readers and processes the blocks, should be in a separate thread or not. For certain parts of the game like loading levels, it doesn't really matter at all. When the game is running, it does matter, but it still depends on your implementation. There's no black or white answer for whether it's always right or always wrong.
On a single CPU machine single-threaded implementations generally run faster. Most developers complain about task switching, but the cost of that is almost always insignificant. The real cost lies in synchronization calls. If you have multiple threads and they're each locking/unlocking critical sections or mutexes hundreds of times per frame, it's going to cost a lot. Any time you use threads, you should design them to minimize the number of synchronization calls. In general it's better to have a thread wait for an event than to have it repeatedly check a lock.
Dual-core CPU's are coming soon, and when they become widespread, game developers will be forced to change unless they're writing a game that will run fine on older hardware.
If you'd like to know more exactly how to set up a pre-fetching reader, let me know and I can give you details.
I would like to know more about pre-fetching readers, that would be helpfull.
but how is it posible to load files and display a (animated) loading logo at the same time? I have been fighting with this for a long time and then I tried the multithread aproach with a loading thread where I put files into a queue and then load them until the queue is empty, the problem I run into is that I have no real control if I should load the files in the background or if I should display the loading logo.
for exampel when I first load a level of a game I display a loading logo so that the user knows what is happening, but then when playing the game should be able to load stuff that wasn't needed to load at the beginning but is now, But without showing the loading logo.
but how is it posible to load files and display a (animated) loading logo at the same time? I have been fighting with this for a long time and then I tried the multithread aproach with a loading thread where I put files into a queue and then load them until the queue is empty, the problem I run into is that I have no real control if I should load the files in the background or if I should display the loading logo.
for exampel when I first load a level of a game I display a loading logo so that the user knows what is happening, but then when playing the game should be able to load stuff that wasn't needed to load at the beginning but is now, But without showing the loading logo.
Quote:Original post by McZ
I would like to know more about pre-fetching readers, that would be helpfull.
I'm assuming you're using C++. The way I did it was to create a generic interface (a class with all virtual methods) called IReader. It looks like this:
interface IReader{ // Read passes a reference to a char buffer in case the reader wants to swap buffers (which is quicker than a memcpy) virtual int Read(unsigned char *&pszBuffer) = 0; virtual int GetLastError() = 0; virtual int GetBlockSize() = 0; virtual LARGE_INTEGER GetFilePosition() = 0; virtual bool SetFilePosition(LARGE_INTEGER nPos) = 0;};
Then I created a class called CBufferedReader, which takes a pointer to an object derived from IReader. It looks a bit like this (without the functions implemented):
class CBufferedReader{protected: IReader *m_pReader; // The reader we want to buffer unsigned char *m_pszBuffer; // The current read buffer (for buffered I/O) int m_nBufferSize; // The size of m_pszBuffer int m_nBufferIndex; // The current read position in m_pszBuffer int m_nBytesRead; // The number of bytes currently read into m_pszBuffer bool m_bEOF; // A flag indicating that the reader has returned EOF bool m_bPastEOF; // A flag to indicate whether the caller has read past EOF}:
Next I created a class called CFileReader that is derived from IReader. It has an Open() method that opens the file, creates a buffer (which is separate from the one created by CBufferedReader), and launches a thread to start fetching the first block. It also has a Read() function that waits for the thread to finish, swaps read buffers, and launches the fetch thread again fot the next buffer. CBufferedReader calls the Read() method when it needs the next block of data.
CFileReader has one thread event object (manual reset, not auto) that gets reset immediately before the fetch thread is launched, and then set by the fetch thread when it's finished. The first part of the Read() method waits for this event to be set. If you'd like, you can have the Read() thread stay open until you close the file, but my tests have shown that it is not any faster. It appears that the cost of starting a thread is not significantly higher than the extra synchronization calls needed to keep it idling between block fetches.
EDIT: Let me know if you need more specifics, and I'll see what I can do.
[Edited by - s_p_oneil on September 15, 2004 3:02:14 PM]
Quote:Original post by McZ
but how is it posible to load files and display a (animated) loading logo at the same time? I have been fighting with this for a long time and then I tried the multithread aproach with a loading thread where I put files into a queue and then load them until the queue is empty, the problem I run into is that I have no real control if I should load the files in the background or if I should display the loading logo.
for exampel when I first load a level of a game I display a loading logo so that the user knows what is happening, but then when playing the game should be able to load stuff that wasn't needed to load at the beginning but is now, But without showing the loading logo.
Note that the reader classes I described above are completely separated from any sort of level loading or animation routine. Those would be done separately. Depending on the internals of the graphics API, you may need to keep all of the graphics API calls in one thread, so your animation should be driven from the main game loop.
Your level loader can be done in a few different ways. One would be to launch it in a separate thread, and have the game loop check an event that it would set when it was finished. Tasks that require graphics API calls, such as pushing a texture to the video card, can be put into a thread-safe queue of tasks, and the game loop can check the queue to see if it has anything to do at the beginning of each iteration.
You could also keep the level loader in the main game loop, but to keep the animation flowing you would break the level load routine into a number of steps. You would most likely create some sort of CLevelLoader class, and have it work through the steps when the game loop calls its Update() method.
Either way you can run into problems where either the animation isn't smooth or the level takes too long to load. It's up to you to balance everything correctly. I believe it would be easier to balance with a separate thread, which you might do by decreasing the thread priority of the loader thread and making sure there are sleeps in the animation loop to give the loader thread enough CPU time to do its work. You could also try giving the loader thread a higher priority. If it spends most of its time waiting for data to come from the hard drive, then the animation will be smooth. If you have any CPU-intensive tasks, you may need to put sleeps in them there to allow the animation enough time to update itself.
When you want to load something while the game is running, you do it in the same way, but don't tell the game loop to play the load animation. Just let the game loop keep running, start a load, and check it in subsequent iterations of the loop to see when it's done. When it is done, you do whatever you need to with the data. Again, the load can be split across multiple frames either with or without threads, and keeping it smooth may not be easy.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement