Resizing D3D Window?

Hello

I have a simple D3D app running in windowed mode. It simply renders a textured cube.

However when I resize the window I have to reset the viewport, I think based on my experience in OGL. The default behaviour is not working properly, as it blurs the rendered cube and makes its edges very gaggy. Resetting the viewport upon resize does not solve the problem though.

I have something like this:

WM_SEIZE:

// viewport width = cx
// viewport height = cy
// ....

d3ddev->SetViewport(...);

Is not it the same way OGL viewp[ort setting work What else should I do

Some advised to Reset the device, but after doing so there is no rendering not even the back buffer is cleared by bk color. As if the dev/render target  was lost.

Your help would be greatly appreciated. Thanks.



Answer this question

Resizing D3D Window?

  • MitkoB

    But is not expensive to re-create the resources And the Clear should work even if there is no resources, which are destroyed automatically by the Reset
  • Nikolaus Brennig

    Well, I've been able to answer my own question. I now have smooth resizing of windows and multiple windows can share a single device.

    When the window is resized, you can create a new render target (SwapChain) that matches the size of the resized window. Then you can call device.SetRenderTarget(0, swapchain.GetBackBuffer(0)) to tell the device to use that render target. You should call Dispose on the old SwapChain to free up video memory (but see below for why that can still fail).

    That wasn't the whole story, though. I also had to crete a new depth buffer via device.CreateDepthStencilSurface with the appropriate size and set that via the device.DepthStencilSurface property.

    My application actually manages multiple windows, so I created a DeviceManager class which uses a single device and tracks the SwapChains for each window. The depth buffer is set to a size that is large enough to accommodate all windows (i.e. the maxmimum width x the maximum height of all the windows). I got the hints for this by studying the source code for this article: http://www.fairyengine.com/articles/dxmultiviews.htm

    I did run into some trouble with the managed code because I was getting OutOfVideoMemory exceptions after resizing a lot. Creating all those new swapchains and depth buffers puts a lot of pressure on the device and even though I was carefully disposing all the 'dead' swapchains the garbage collector wasn't cleaning them up fast enough. I "fixed" this in a couple of ways:

    1) I added a catch block for OutOfVideoMemoryException and put calls to GC.Collect and GC.WaitForPendingFinalizers.

    2) I added some calls to GC.AddMemoryPressure each time I created a new surface. I had to guess at the amount of memory these things consume. (It would be nice if this was done automatically by the managed direct3d framework.)



  • markybark

    Over the holidays I dabbled a bit with Direct3d and this was one of the problems I ran into too.

    The default behavior for windowed mode (when you do device.Present into a Form) is for the device to stretch or compress its rendering surface to fill the window. That's why it looks jaggy and ugly if you stretch the window too much. It also allows the image to distort if, for example, you only resize horizontally (even if you have set the aspect ratio in your projection matrix)

    Normally you create the device after you create the form so it takes the current client size as the size of its rendering surface. That's fine until the window is resized.

    I tried in vain to come up with a way to allow resizing of the window without completely resetting the device. I thought I came close by changing the viewport. In the end I gave up and just call device.Reset in my ClientSizeChanged event handler. As Etienne2005 said you also need to recompute the projection matrix, but that's trivial to do at the end of the OnResetDevice handler (you can even use the form's width and height to compute the new aspect ratio and a little bit of additional math to adjust the field of view appropriately).

    I don't like this solution because there is a slight, but noticable delay resetting the device which makes smooth resizing of the window a bad experience.

    I'd love to know if there's a better way for windowed mode.



  • serimc

    Basically, yes, you simply need to reset the device.  However, doing that, you would also need to destroy (and re-create) any objects living in video memory.

    Depending on how your project is setup, device reset on resize can happen automatically (by default it will happen automatically if you're using a WinForm).  We normally recommend that you use the DXMUT Sample Framework for your projects, and this will automatically reset the device on resize as well.  Just be sure you are creating/destroying your objects in the correct callback method and it should "just work".

    Look at the basic "EmptyProject" sample that ships with the SDK for a bare bones example of using the framework.



  • mattyo

     

    If you go from a Windowed mode to another you don't need to

    destroy device and recreate it...(i don't think)

    What you need when you resize is to recalculate and set the new Projection

    matrix, it's the projection matrix that calculate the height and width of the new

    resized window

    In the OnSize handler you just recalculate the Projection matrice to use the new

    Rectangle value of your window...and use D3DXTransform(D3D_PROJ, matProj);

    If your projection matrix is not recalculate your cube will be crush or expanded...

    No need for viewport, the viewport even in GL is to set up a section

    of the window to draw...you use all the window

     

     

     


  • Resizing D3D Window?