multi-threading

Started by
8 comments, last by scope 14 years, 1 month ago
Hello everyone, I'm wondering what makes directX not thread safe? i think its because of using two or more functions from IDirect3DDevice9 at once ( one from each thread ), so i'm wondering, how can i avoid this, without losing FPS? e.g. i can do the following, make a variables ( bool rendering ), and while rendering the scene, the value is true, and another variable stating that device is being used ( bool usingdevice ), used like this: render cant start while its true, its turned on while using the device, it can't be turned on while rendering this slows down the FPS by a huge ammount, almost like not using another thread, so i'm wondering if you can make an instance for the device and use it to load objects and stuff from the other thread? Thanks for reading regards -Hassan
Advertisement
DirectX (9) is thread safe as long as you specify the multithreaded flag when creating the device.

When the device is created with the multithreaded flag, that each state changing function call will be wrapped by a critical section.

There's no good way around this. Some people (including me) have tried by using the singlethreaded version + adding critical section where necessary. This works and improves performance a little (because multiple dx calls can be batched together into one critical section), but will produce warnings when using the debug runtime (easy enough to ignore). Also, it will fail completely on Vista and 7, so this isn't a good solution.

Alternatively you can do the rendering in 1 thread and all the other threads merely "record" their draw calls, which then are replayed by the rendering thread at the appropriate time. It's quite a bit of work, but may be worth it, depending on your use cases.

Finally, if you think you can make something thread safe, by manipulating a shared bool variable, you should read up on thread synchronization.
multithreading flag totally kills the FPS

Quote:Alternatively you can do the rendering in 1 thread and all the other threads merely "record" their draw calls, which then are replayed by the rendering thread at the appropriate time. It's quite a bit of work, but may be worth it, depending on your use cases.


mind explaining a bit more? how can they record their draw calls?

Thanks.
well, all i want to do is to load some objects while rendering, without losing much fps, is there any function that does, like load an X file into a variable without touching the IDirect3DDevice object, and the variable can be used to create the mesh and textures?

i hope i wont end up using my own file format to load vertex buffer, index buffer and textures info =/
Quote:Original post by Hassanbasil
well, all i want to do is to load some objects while rendering, without losing much fps, is there any function that does, like load an X file into a variable without touching the IDirect3DDevice object, and the variable can be used to create the mesh and textures?
Nope - because you need to create an index and vertex buffer; both of which need created by the device.

The only way you can safely use D3D9 in a multithreaded environment is to use it only from the main thread (Which also needs to be the same thread that creates the window).

In your case, you can load the file and parse it in a worker thread, and then have everything ready to memcpy() into a vertex and index buffer in the main thread. There's no built in D3D or D3DX functions to do that though, you'll need to do it yourself.
Quote:Original post by Hassanbasil
multithreading flag totally kills the FPS


If you just turn the multithreading flag on and compare it to what it was before, it'll be slower, of course. However, the point of the multithreading flag is to enable multithreading. And you wouldn't use multithreading if it didn't give a performance boost in the first place. So, in conclusion, if you're multithreaded rendering code is slower than you're singlethreaded one, don't bother.

Quote:Original post by Hassanbasil
mind explaining a bit more? how can they record their draw calls?


Sure.
There are 2 scenarios where you'd want to access DirectX from multiple threads.

The first and most common is loading resources from a different thread. Here, the solution Evil Steve suggested works best. But you don't even need to memcpy everything.

Tell the rendering thread to create and lock a vertexbuffer or a texture. From the worker thread, load/copy data into the locked memory. Tell the rendering thread you're done and the resource is ready to use. Main threads unlocks and uses it.

The second and more complex scenario is that of actually rendering from multiple threads, like renderstate changes and draw calls. Instead of issuing these calls directly to the d3d device, "record" them and play them back from the rendering thread at the appropriate time.

This recording and replaying can be implemented in several ways, here's a quite generic one:
Implement the IDirect3DDevice9 interface that stores all (relevant) calls + parameters in a queue. The rendering thread than reads this queue and issues all calls stored there to the actual d3d device.

If you have your own abstraction over there, this might also be a good place to put the record/replay code.

I hope that helps!

ugh, i think the easiest way is to make my own tiny file format, e.g.:

1-make an application that converts X meshes to my own format, first it loads the object, reads the vertex/index buffers and uv coords and saves them to a file in a very simple format ( this is just for converting not a run-time application )
2-from the main application, in the worker thread, i read the file and save info in a structure or such, and then send it to the main thread, which uses it to make a vertex buffer, locks it and fill the data, same with index buffer

now i am missing 1 point only:
how can i get vertices / indices / uv coords of an object, if i load it in the way written in the documentations [topic title : "Step 1 - Loading a mesh object"]?

i create my objects that way: ( without loadmesh & d3dxcreate* )
        hVertex* v;	VB->Lock ( 0, 0, (void**)&v, 0 );	// build box	// fill in the front face vertex data	v[0] = hVertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);	v[1] = hVertex(-1.0f,  1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);	v[2] = hVertex( 1.0f,  1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);        //............        //............        VB->Unlock ( );        // same with index buffer...

and my vertex structure is:

struct hVertex{	hVertex(){}	hVertex(		float x, float y, float z,		float nx, float ny, float nz,		float u, float v)	{		_x  = x;  _y  = y;  _z  = z;		_nx = nx; _ny = ny; _nz = nz;		_u  = u;  _v  = v;	}    float _x, _y, _z;    float _nx, _ny, _nz;    float _u, _v; // texture coordinates};#define FVF_VERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)

so all i want my format to do is to save the hVertex constructor parameters

PS: how can i use code boxes? shouldn't it be

[Edited by - Hassanbasil on March 7, 2010 7:37:14 AM]
Quote:Original post by Hassanbasil
ugh, i think the easiest way is to make my own tiny file format, e.g.:

1-make an application that converts X meshes to my own format, first it loads the object, reads the vertex/index buffers and uv coords and saves them to a file in a very simple format ( this is just for converting not a run-time application )
2-from the main application, in the worker thread, i read the file and save info in a structure or such, and then send it to the main thread, which uses it to make a vertex buffer, locks it and fill the data, same with index buffer
Yup, that sounds reasonable.

Quote:Original post by Hassanbasil
now i am missing 1 point only:
how can i get vertices / indices / uv coords of an object, if i load it in the way written in the documentations [topic title : "Step 1 - Loading a mesh object"]?

i create my objects that way: ( without loadmesh & d3dxcreate* )
[snip]

so all i want my format to do is to save the hVertex constructor parameters
What the D3DXMesh format does is saves the vertex FVF (Or declaration). That tells you what components of the vertex you can expect, what size each vertex is, and so on.

Quote:Original post by Hassanbasil
PS: how can i use code boxes? shouldn't it be
Yep, for small sections of code. For larger sections, [ source ] [ /source ] is probably what you want, which will put it in an inline frame.
Quote:Original post by Evil Steve
What the D3DXMesh format does is saves the vertex FVF (Or declaration). That tells you what components of the vertex you can expect, what size each vertex is, and so on.


i want :
//....        v[0] = hVertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);	v[1] = hVertex(-1.0f,  1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);	v[2] = hVertex( 1.0f,  1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);//....i want these data


how can i get them from a mesh? some code or a function would be lovely

thanks
Quote:Original post by Hassanbasil

i want :
*** Source Snippet Removed ***

how can i get them from a mesh? some code or a function would be lovely

thanks


You want to write the vertices to a file, you can lock and read the vertice buffer:

	std::ofstream stream;	stream.open(filename, std::ios::binary);	void* vert;	mesh->LockVertexBuffer(0, (void**)&vert);		stream.write((char*)vert, mesh->GetNumVertices() * mesh->GetNumBytesPerVertex());	mesh->UnlockVertexBuffer();	stream.close();


It's basically the same for the Indices and everything else.

This topic is closed to new replies.

Advertisement