IDirect3DSwapChain9 Device Reset problem with different size back buffers.

IDirect3DSwapChain9 Device Reset problem with different size back buffers.

I am developing a Direct3D X file GUI editor and am having a problem with how to display multiple views with the same device.  I started out with the Skinned Mesh Direct3D example and added four views using MFC classes derived from CMDIFrameWnd as the main frame, CMDIChildWnd as the child windows that have four splitter windows displayed in the child windows client area.  Each splitter window pane in each MDI child window displays a different view of the model (a perspective view, and orthogonal top, left, and front).  Since I started with the Skinned Mesh example, the splitter pane views actually use the same render view and is pretty much implemented the same as the Skinned Mesh example.

What I am doing right now, just to get it working, is loading my meshes four different times for each splitter pane view.  I have not changed the code yet nor have I moved the mesh, frame, and animation data into the document class where it would only be loaded once.  I would now like to do that, but there is a problem…

If I load the mesh from the derived CDocument class, I would need to first setup the ID3DXDevice9 interface and then load the mesh.  My Document View class for each splitter pane would have to create a IDirect3DSwapChain9 interface each time a view is created – the problem is that if the splitter panes are resized, the IDirect3DDevice9::Reset() function needs to be called to reset the device… which takes a pointer to the D3DPRESENT_PARAMETERS where the back buffer height and width are defined for the device… but if my splitter panes have different widths and heights, their back buffers will also.

How do you use a device swap chain if the back buffers are different sizes?


And to anyone that responds to this post, could explain exactly what I would have to do to implement the swap chains, it would help.  I also assume that I should create a different device9 interface for each MDI Child Window (one for all 4 splitter panes)… if there is more than one document open at a time, then there will have been just as many devices created.  I am pretty sure this is the way it should be – as far as I know, if the program has multiple documents open, there should NOT be just one device opened for the entire program - Is this the right way to do things – (I just want to make sure) – or is there a way to not link a mesh to a device when you load it.  And if so, how would you render the mesh.

My email address is:

Who is Participating?
dkeithleyConnect With a Mentor Commented:
Follow up: Just to clarify, what you want is one swap chain per view.  There are other solutions, but this is the one I'm recommending here.

You use the CreateAdditionalSwapChain function to create them.  It takes a D3DPRESENT_PARAMETERS structure describing the swap chain.  Ignore the structure members which describe z-buffer and stencil buffer -- they are not used by this function.  So this means that if you're z-buffering, you need a z buffer that can accomodate each view.  In most cases you can just create a single z-buffer using CreateDepthStencilSurface and share it among the views.  Just make sure it's larger than each view in x and y.

To render a view, call GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, ...) on the view's swap chain.  This gives you back a surface.  Pass that surface to SetRenderTarget(0, ...) on the device.  Make sure the z-buffer is set via SetDepthStencilSurface.  When you're done rendering, call Present on the IDirect3DSwapChain9 interface -- not on IDirect3DDevice9.

And I think that about covers it.  Good luck!
The way I used to do this was to create a single context the size of the entire window, and handle the 'splitter' myself.  Then you have virtual viewport rects into a unified buffer.  But that was a while ago, when DX was much more simple. ;)

Under DX9, you could do something similar, but you'd have to manage splitters yourself, which you probably don't want to do.

The other option is to create a single backbuffer for the entire window, and render each viewport as an independent pass, and blit them to the window.  Also one I don't like.

I agree that it seems like with DX9, you'd want to create a separate device interface for every splitter plane, so that they are independently managed contexts.  That will use a huge amount of resources, but the only way to avoid that is a single unified backbuffer approach....

danielvallasAuthor Commented:

Is there anyway to link the meshs loaded to multiple device's... or at least draw a mesh on a different device than the one that it was loaded with.

If not...

If I created a single backbuffer for the entire window, how would I blit the rendered pixels to a window that had a smaller size - like the individual panes - without only bliting a portion of the full size backbuffer window.  Is there a way to scale it to the size of the smaller splitter panes?  If you know how to do this, could you show a little example code of what I would have to do.

I really have to figure out how to use only one device for all 4 views of splitter panes - otherwise, I have to load the mesh file 4 different times for each device and splitter view... and every time I make a change to the mesh, I have to update 4 different meshes, etc.... like my program is currenlty doing.

No, do not create a device for each view.  This is unnecessary and just a really bad idea because it requires duplicating resources across each device.  There is no reason to ever create more than one device per process unless you intend to drive multiple adapters.  That's fine, but multiple devices per adapter is always the wrong solution.

> the problem is that if the splitter panes are resized, the IDirect3DDevice9::Reset() function needs to be called to reset the device…

You do not have to reset the device here.  If you're creating a swap chain for each view then you simply have to recreate the swap chains when the splitter is moved.  Once the splitter has been moved call Release on each swap chain and then CreateAdditionalSwapChain for each view.  There are more sophisticated approaches that can reduce the swap chain destruction & recreation, but this is a very straightforward and simple solution that will work fine for most purposes.

Also note: The device has an implicit swap chain when you create it and reset it, as described by D3DPRESENT_PARAMETERS.  But if you're creating a swap chain for each view, then this implicit swap chain is not necessary, right?  So, while you can't avoid creating it, you can minimize the resources that it consumes by specifying a width and height of 1 when creating/resetting the device.  Which is what I recommend you do. ;-)
danielvallasAuthor Commented:

Thanks for the solution.  I will not be able to actually fix my program and see whether your solution will work for another couple of weeks, because it is a major fix, and I have other things to do to the program right now.  I will save it and assume it will work and accept the solution for now.  

As far as having multiple device's open at the same time... What I want is to have one device per mesh file that you open - and then have 4 swap chain entries created for the 4 different views of each mesh file loaded.  I don't think I would actually want one device created for multiple files... one device for multiple views of a file, yes...  but not multiple files (it is a Multi-Document-Interface, MDI, program).

I would just like to add that you seem knowlegeable on the Direct3X subject - maybe you could help with my other posts...
   Problem translating Direct3D Skinned Mesh Bones with SOFTWARE skinning method
   Selecting Vertexes with a Bounding Selection Box in Perspective View

Thanks again.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.