Multiple tasks

I would like to do a loading screen with moving objects, while the aplication is loading textures, sound, etc… I want an animated thing, not like Quake where the letters just appear… What is the best way to do it? Using the same RC with two threads writing/reading to OpenGL? That would mean syncronizing methods that, for example, if it took 2 minutes to load everything to VAR, the animation would stop. Creating two RC? I believe this is the best one, but I don’t know… For sure… Please give me an hint… Thanks…

wow double posting a topic is something new

Use asynchronous loading.

And/OR simply do your loading in a seperate thread, which makes sure the main thread has enuff time to do the rendering at a decent speed.

Nutty, I don’t think asynchronous disk reading is possible on Win 95/98/ME, it’s 2000/NT/XP only.

Asynchronous file I/O is supported in Win9x. It just isn’t as easy as it is with WinNT/2000/XP.

The “overlapped I/O” API isn’t supported on 16-bit Windows (Win98/ME) for disk devices. You can roll your own using threads, though.

Also, UNIX async I/O isn’t as standardized as you’d want (at least wasn’t when last I looked at it). So, again, you can roll your own using threads.

Write your GL application as usual. Whenever something needs to be loaded, allocate memory, enqueue a load operation, and poll the pending operation queue once every frame. Alternately, have the read completion move the pending operation into a queue of completed operations – but that’s less similar to “true” asynchronous I/O APIs, so it’ll port less well.

Each operation can have a callback (or implement a virtual interface, or whatever) to deal with the data once it’s arrived. Beware proper thread synchronization (mainly, protecting your pending-operations queue).

jwatte, it is my understanding that overlapped file I/O is supported on Win9x as long as you open the file with DeviceIoControl (which it what makes it a pain in Win9x) instead of CreateFile.

Interesting, DFrey. I’m assuming you mean that I open the “system driver” and issue int21-like controls to open a file and read it? I can’t find any documentation about how to do this on MSDN; they only document “supported” control codes such as getting battery status, testing whether a volume is compressed, etc.

Do you know where I can find documentation on how to do this?

Obligatory OpenGL content: can someone post NV_vertex_program or ATI_vertex_shader code for how to calculate the cube map reflection vector when using matrix palette skinning and object-space dot3 bump mapping? I already know how to reverse-skin the light vector, so I guess I could derive it myself, but I’m lazy :slight_smile:

jwatte, actually the MSDN material on this is quite confusing to me. In one sentence they plainly state that overlapped file I/O is not supported in Win9x, but in the next few sentences say that GetOverlappedResults will work in Win9x for serial devices (opened conventionally with CreateFile) and for files opened with DeviceIoControl. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/win32/chilimit_70vn.asp
The only way that document would make sense to me is either asynchronous I/O is supported if you use DeviceIOControl, or if you use DeviceIOControl to open a file, GetOverlappedResult will work but always blocks. I haven’t actually tried it myself to see what this document really means as it is so much easier to just spawn a new thread to do it via CreateFile.

DFrey,

It makes sense that overlapped I/O works for the serial driver but not for the file system, as it’s much easier to write an asynchronous serial driver than writing an asynchronous file system. The MacOS had this problem for a long time. Actually, the floppy disk would support async operation, but the SCSI driver wouldn’t :frowning:

Okay, so if nobody can show me how to open a file for async read using DeviceIoControl (which I can find no reference on) then I think a thread is the only way to go. You’re probably still well off emulating the async API in your threaded implementation, so you can easily use actual async (“overlapped”) operation on systems that support it.

I did some further reading on DeviceIoControl, and it turns out it always blocks on Win9x. So asynchronous file I/O in a single thread is not supported in Win9x after all. There is just an API hack that will let you use the same code as in WinNT, such that in WinNT you get real asynchronous behavior but only synchronous in Win9x.

Talking about device drivers… hummm… nice… lots of 3D… sweet… I know, I know, you got carried away… Didn’t help, but thanks anyway…

Oh and sorry about the double posting, don’t know how that happened…

no problem

well yeah you should try a loadingthread and a renderingthread… i’ve done this with my program wich simply presented a loadingscreen while loading up the plugins (no opengl there) to get the window redrawn while loading if someone drags another window over it (quite annoying in the splashscreens of other big programs like 3dsmax, visual studio etc… )

should work in gl without bigger problems…

and well, who uses winDOS anymore?

But what about cache utilization issues using multi-threading?

Isnt it better just to keep it single thread and go with chunk loading into RAM-file or something and then do any parsing from RAM in a single sweep?

Perhaps performance isn’t an issue when you are trying to do some animation at the same time?

But what about cache utilization issues using multi-threading?

It’s for loading. You aren’t doing much with the cache at that point anyway.

Isnt it better just to keep it single thread and go with chunk loading into RAM-file or something and then do any parsing from RAM in a single sweep?

Perhaps performance isn’t an issue when you are trying to do some animation at the same time?

As Davepermen mentioned, if you don’t have a second thread, then you have a problem: you can’t repaint the window if someone drags a window on top of it. Since your loading thread will be busy loading data from a file (and likely not bothering to look at the message queue), windows can’t get your application to repaint the window.

How about this:

//somewhere in WinMain():
...
//just your usual thing
while (whatever)
{
  //insert message queue stuff
  ...
  main_loop();
}

//somewhere else
int runlevel=0;        //gotta love these Linux folks
int chunks_total;
int chunks_loaded;

...

void
main_loop()
{
  switch(runlevel)
  {
  //we ain't done nothing yet
  case(0):
    //determine amount of 'work units' our loader can split the loading procedure into
    loader.prepare_loading(next_scene);
    chunks_total=loader.get_data_chunks();
    ++runlevel;
    break;
  case(1):
    loader.load_next_chunk();
    ++chunks_loaded;
    if (chunks_loaded==chunks_total) ++runlevel;
    display_loading_screen(chunks_total,chunks_loaded);
    swap_buffers();
    return;
    break;
  case(2):
    //we've finished loading
    hurray();
    break;
  ...
  }
  ...
}

This of course is assuming that your loader can split the loading process into bits and determine the amount of these bits early and quickly. Shouldn’t be much of a problem. You only need this kind of stuff for complex data structures anyway. Say, you load some kind of tree representation, you need to quickly asses how many nodes there are. You can then load them one by one.
Best of all: No need for threads!

I know what you all mean but I think the main question is: do the two threads use the same RC? That would mean that the drawing thread would have to wait for the loading one. The drawing would stop if the loading took to long, and I can’t stop for instance while loading a texture:

for each texture:
glGen
glBind
glTexture2D
roll

If the loading thread stopped between glBind and glTexture2D (totally completing glBind ), if I would in between draw something it would do a glBind, thus, by the time glTexture2D will be called, it would be with the wrong texture bind…

I think I explained myself, sorry about the poor english, I’m portuguese

Oh and thanks for all your replys…

Kronos, you should create TWO OpenGL contexts, the first one you should call your “resource” context in which you store all your textures, vertex programs, display lists etc., the second one is the context you use for drawing.
Use wglShareLists() to share the resources (textures etc.) created in the resources context with the drawing context.
Each context will have its own states at any one time (ie. any state changes are “in context”, if you’ll excuse the pun), so you needn’t worry that if context A binds to a particular texture object, context B will mess up - it won’t happen, they will work well together.