Sign in to follow this  
Tispe

D3D resources and Multithreading

Recommended Posts

Tispe    1468
Hi

My program is using DX9 and can't share the Device among multiple threads. Which means I can't create resources on other threads.

I wanted to know if it is possible to create vertex, index buffers and textures on the main thread and then pass those resources to a worker thread that lock/read/write/unlock/release these resources while the main thread is rendering? These resources sent to the worker thread will not be in use intil the worker thread has finished and sent those resources back to the main thread.

Will this type of multithreading work for DX9? Or are resources created with the device unsafe for other threads?

Cheers!

Share this post


Link to post
Share on other sites
Krohm    5030
I'd be careful in doing that. Even if the API allows it (D3DCREATE_MULTITHREADED) drivers might malfunction.
Yes, it's not supposed to happen. They're also not supposed to garble textures nor to crash but sometimes it happens and if you're dealing with people still on D3D9, I'd give up every thing I consider certain.
Now, I have been told this is fixed but multithreading was in its early ages and the official documentation about D3DCREATE_MULTITHREADED isn't very encouraging. D3D9 was way, way crude in its effective multi-threading capability.

Personally I would map/unmap/interact with D3D9 in the main thread and then pass the raw memory blob to the worker thread. This way D3D9 is out of the equation.

Share this post


Link to post
Share on other sites
Tispe    1468
How do you "map/unmap" resources from main thread to worker thread? I have never heard of this before.

In my head I create a texture or a vertex buffer on the main thread, then push a pointer to the resource to a Critical_Section vector, retrieve that from the worker thread, copy data over send it back.

Some code might help me understand ;)


EDIT: Is it as simple as Addref(), Release() when sending and retrieving it? Edited by Tispe

Share this post


Link to post
Share on other sites
Washu    7829
When you map, or lock, a resource you typically get a pointer out of it. That pointer is not thread specific and thus you can pass it off to your worker thread for it to operate on.

Share this post


Link to post
Share on other sites
Hodgman    51234
Sorry, by map/unmap, I meant lock/unlock. All D3D9 calls must occur on your main thread. The worker can generate data in between a call to lock and unlock.
e.g.
[code]D3DLOCKED_RECT result = {};
texture->LockRect(0, &result, NULL, D3DLOCK_DISCARD);
SignalWorkerThreadToGenerateData( result );
... later ...
if( WorkerThreadIsDone() )
texture->UnlockRect(0);


void* result = 0;
buffer->Lock(0, 0, &result, 0);
SignalWorkerThreadToGenerateData( result );
... later ...
if( WorkerThreadIsDone() )
buffer->Unlock();[/code] Edited by Hodgman

Share this post


Link to post
Share on other sites
Tispe    1468
Will this work with Texture->GetSurfaceLevel (0, &Surface) and then sending the LPDIRECT3DSURFACE9 to the worker thread? I really wish to use D3DXLoadSurfaceFromMemory to convert DXTn to ARGB on the worker thread.

Will it also work with the ID3DXBaseMesh::LockVertexBuffer method if I use the ID3DXMesh wrapper?

Share this post


Link to post
Share on other sites
Evil Steve    2017
No, you shouldn't be passing any D3D resources to the worker thread, which means not using D3DXLoadSurfaceFromMemory(). One (messy) option is to create your own class that inherits from IDirect3DSurface9, and pass an instance of that class to D3DXLoadSurfaceFromMemory(). Your class should implement all of the IDirect3DSurface9 functions.

You can then implement your class to store the ARGB pixel data internally, and then after calling D3DXLoadSurfaceFromMemory(), you can copy that ARGB data into the real surface (Which should be locked in the D3D thread and the pointer passed to the worker thread).

Or, just not use D3DXLoadSurfaceFromMemory() :)

Share this post


Link to post
Share on other sites
Tispe    1468
Question: Will locking any resource block rendering, can a locked texture be locked for several frames if it is not in use?

Baw, it seems Microsoft didn't have multithreading in mind when implementng D3DXLoadSurfaceFromMemory(). I hope I can get away with calling this a few times each frame.

It seems that I will have to scrap the whole idea of passing mapped/locked resource pointers to worker threads to keep things simple. I guess I can use GetTickCount() after each resource I process and check if elapsed time is not too much, that way I can skip processing to next frame to avoid huge drops in frame rate.

Share this post


Link to post
Share on other sites

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