Advertisement Jump to content
Sign in to follow this  
Noctumus

Is this a good idea? (D3D9, beginner)

This topic is 1861 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

Hello Forum
 
Suppose you wanted to make a loading module for your game displaying some object rotating on the screen while your game's resources were being loaded. My intuitive approach for this task would be to split it into two threads; one for rendering the animation (the main thread), and one for loading the resources in the background.
 
Unfortunately I learned that D3D9 doesn't allow you to share devices and resources (vertex buffers, textures, ...) between threads, which obviously killed that idea. However it did give me another idea of splitting the data into many small blocks and uploading1* them between each frame, like
 
upload block, render frame, upload block, render frame ...
 
in order to avoid the risk of stalling the rendering process due to the time it would take to upload a large portion of data at once.
 
The problem is that even if this would work it somehow feels like a "hack solution" to me. On the other hand I don't really see any other way of doing it since you have no choice but to keep everything in a single thread when using DirectX.
 
How would you do it?
 
1* By uploading I mean transferring data from local memory into a D3D object, eg. obtaining a pointer to the contents of a vertex buffer using IDirect3DVertexBuffer9::Lock and then copying the local data to that address.
Edited by Noctumus

Share this post


Link to post
Share on other sites
Advertisement

I learned that D3D9 doesn't allow you to share devices and resources (vertex buffers, textures, ...) between threads

As long as you build with the multi-threaded flag enabled, DirectX of any version has no problem with sharing resources across threads.
Perhaps you are thinking about OpenGL.


L. Spiro

Share this post


Link to post
Share on other sites

I'd try this first, without especially trying to split the assets into smaller pieces:

 

- Background thread processes the assets (textures, meshes) as far as possible, until it's data ready to be pushed to a GPU buffer. Each such prepared asset is pushed onto a queue

- Main (rendering) thread allows a certain amount of time each frame to be spent uploading the prepared assets to GPU. In pseudocode:

while (frameTimer.Elapsed() < 20ms)

  UploadNextPreparedAsset();

Share this post


Link to post
Share on other sites

I have not encountered multithreading issues as of yet. Here is how I do it:

  • The engine is aware if it is running normally, streaming data in (so it is still expected to run normally) and in full loading mode
  • The rendering, eventing and GUI thread are the normal main thread, so I don't create a new thread for that.
  • If in full loading mode I use short sleeps after presenting a frame to artificially limit the framerate.
  • A second thread is running and loading resources.
  • If some resources need to be only created in the main thread, the background thread still takes care of tasks that can still be run, like loading data from disk and computing, and once it is finished, in the main thread I create the structures based on the data prepared by the thread.

Share this post


Link to post
Share on other sites

If you're starting with a new project, I would consider using D3D11 instead.

Or: Load and prepare your resources in a worker thread, and then only pass the buffer data (in CPU RAM) to the main thread where you fill the data into the buffers. The latter step should be fast enough for the render loop.

Share this post


Link to post
Share on other sites

As long as you build with the multi-threaded flag enabled, DirectX of any version has no problem with sharing resources across threads.


Thanks for your feedback, and just to be clear: by the above you mean creating the device with the D3DCREATE_MULTITHREADED flag, right? If so, how much should I worry about the following from the MSDN documentation about this flag? Would you personally recommend using it?

"This makes a Direct3D thread take ownership of its global critical section more frequently, which can degrade performance"

Share this post


Link to post
Share on other sites

Normally what take most of the loading time are:

  1. I/O: Loading from disk and/or decompressing if it's compressed.
  2. Creating the D3D resources (be it a vertex buffer or texture, etc)

Uploading the data from RAM into VRAM is the least expensive. It's not free either, but you can load the data from disk into RAM in the background then from the main thread send to the GPU; and you have no way to decrease the cost of creating a D3D (even in D3D11), you can however, preallocate those resources to avoid the stall.

 

I agree it would be best (and certainly easier!) if you could load from disk into VRAM without any need for locking, but well, that's what we have to live with.

Share this post


Link to post
Share on other sites

Thanks a lot for all your really, really useful feedback, guys! smile.png

Thanks to you I'm now pretty sure I have all the knowledge I need to make a good and effective solution (which will most likely involve loading resource data into main memory from a working thread, add the address of the resource to a (linked) list, monitor the list from the main thread and transfer the data from the nodes to VRAM whenever something is pending).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!