• Advertisement
Sign in to follow this  

[MDX] Device Resize

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

Hi, my problem is currently that running Managed DirectX 9.0 (MDX 1.1 I believe) in windowed mode causes an InvalidCallException whenever the form (and therefore device) is resized. I'm not using any VertexBuffers which usually seem to cause the problem, only Sprites and Textures. At the moment, I recreate the presentation parameters and reset the device in the DeviceResizing event. I've tried most of the simple things already but feel free to suggest anything still. Here's my code: [Device Initialisation]
Protected Overridable Sub InitializeGraphics()
        If _disposed Then Throw New ObjectDisposedException(Me.GetType().Name)

        Trace.WriteLine("Initializing Graphics Device")

        ' Get display mode and capibilities
        Dim displayMode As DisplayMode
        Dim displayCaps As Direct3D.Caps

        displayMode = Direct3D.Manager.Adapters.Default.CurrentDisplayMode
        displayCaps = Direct3D.Manager.GetDeviceCaps(Direct3D.Manager.Adapters.Default.Adapter, Direct3D.DeviceType.Hardware)

        ' Check for hardware processing
        Dim flags As CreateFlags

        If displayCaps.DeviceCaps.SupportsHardwareRasterization Then
            flags = CreateFlags.HardwareVertexProcessing
        Else
            flags = CreateFlags.SoftwareVertexProcessing
        End If

        ' Check for pure device
        If displayCaps.DeviceCaps.SupportsPureDevice AndAlso _
        ((flags AndAlso CreateFlags.HardwareVertexProcessing) <> 0) Then
            flags = flags Or CreateFlags.PureDevice
        End If

        ' Create device from presentation parameters
        BuildPresentParameters()

        _graphics = New Direct3D.Device( _
            Direct3D.Manager.Adapters.Default.Adapter, _
            displayCaps.DeviceType, _
            Me, flags, _presentParams)

        ' Set form size
        Me.Size = _resolution
    End Sub

And here's the DeviceResizing code plus additional helper functions need for init & resizing:
Public Sub ResetGraphics()
        If _graphics Is Nothing Or _deviceLost Then Exit Sub

        ' Stop engine timer
        _timer.Stop()

        ' Recreate presentation parameters
        BuildPresentParameters()

        ' Reset graphics device
        Try
            _graphics.Reset(_presentParams)
        Catch ex As DeviceLostException
            ' Device lost
            _deviceLost = True

            ' Write to trace
            Trace.WriteLine("Device lost in game loop")
        End Try
    End Sub

    Protected Sub BuildPresentParameters()
        If _disposed Then Throw New ObjectDisposedException(Me.GetType().Name)

        Trace.WriteLine("Build Presentation Parameters")

        ' Create presentation parameters for graphics device
        _presentParams = New PresentParameters()

        _presentParams.BackBufferCount = 1
        _presentParams.BackBufferFormat = Format.A8R8G8B8
        _presentParams.BackBufferWidth = _resolution.Width
        _presentParams.BackBufferHeight = _resolution.Height
        _presentParams.BackBufferCount = 1
        _presentParams.ForceNoMultiThreadedFlag = False
        _presentParams.SwapEffect = SwapEffect.Discard
        _presentParams.PresentationInterval = PresentInterval.Immediate
        _presentParams.PresentFlag = PresentFlag.None
        _presentParams.Windowed = _isWindowed
    End Sub

    Private Sub _graphics_DeviceResizing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles _graphics.DeviceResizing
        '' Stop device resizing
        'e.Cancel = True

        ResetGraphics()
    End Sub

I hope this is a simple problem...you should have all the code/information here but please tell me if you need more. Thanks in advance for any help.

Share this post


Link to post
Share on other sites
Advertisement
This sound familiarly.

The default behavior of managed Direct3D is to reset the device after the window is resized. This is done to make sure that the back buffer has the same size as your window. Unfortunately such a reset will invalidate some of your DirectX objects. Mainly everything that was created in the default pool or use a state block. Your Sprite object is part of this invalidation, too.
There are at least three possible solutions for this problem.

1. Disable the managed Direct3D event handling. Look for the Device.IsUsingEventHandlers property
2. You can handle the Device.DeviceResizing event and cancel it. If the device is not reset your sprite object will not lost.
3. Handle the Device.DeviceLost and Device.DeviceReset event. Dispose your sprite object during the lost and recreate at the reset event.

I don’t recommend the second solution because there are other reasons that will cause a device reset.
If you look for a fast solution use the third one. As the event handlers have some other drawbacks solution one would be the best but force you to handle device lost situations and back buffer scaling fully by your own.

Share this post


Link to post
Share on other sites
thanks for your reply. i will try solution #3 for now, but maybe you could explain breifly how i could accomplish #1 either yourself or with a link? anyway your answer makes sense, so i will post about my success with it.

Share this post


Link to post
Share on other sites
I'm having trouble understanding what functions I should call when...
Would you mind clarifying what I have to do for DeviceLost and DeviceReset for these types of objects: Sprites, Textures (Pool.Default & Pool.Managed), Direct3D.Font please?

Share this post


Link to post
Share on other sites
In the device lost handler you simply need to call Dispose for any Direct3D object that lives in the video memory or in the driver. This are all Pool.Default resources and objects that use state blocks like the font and sprite objects.

The device reset handler should recreate anything you have disposed during the lost. It is recommended to write one method that create such resources and call it one time after you have created the device and every time you get a device reset.

The same is valid for the disposing of the objects. This method should called during a device lost and before you finally dispose your device.

In the case you set some render states after you have created the device you should this do in an additional method that is called during the reset. The reason for this is that a reset will reset your render states, too.

Share this post


Link to post
Share on other sites
Great, that explains it perfectly, thanks. Except what are the OnDeviceLost and OnDeviceReset methods of a Sprite/Font object for?

EDIT: The problem I find is that it takes very long to recreate some resources...
I believe it's to do with the GUI system, so it could involve VertexBuffers. Thanks for your help again...

[Edited by - alex_myrpg on May 29, 2006 3:32:01 PM]

Share this post


Link to post
Share on other sites
How many d3d objects do you have?

How much of them need to be recreated?

Share this post


Link to post
Share on other sites
I think an important thing to note is that in MDX the recreation of the device is handled automatically. If you've attached the device to a form itself then there is no need to override the resize event.

Any vertex buffers and such should be created with the managed flag in their constructors. Render targets are the only exception from what I know.

I struggled with the same problem for some time. I used complex algorithms to try and handle this resize event. Then I read Tom Millers MDX book and he explains that it's best to just allow MDX to handle it's own resize managment.

The only thing you will have to reset are things like view, world, projection matrix and other custom data that you've stored in the device object. MDX will automatically eject that data on resize. Also renderstates need to be reset.

So hook to the deviceResize event and handle reseting the custom data but don't cancel it or override it.

-Devin

Share this post


Link to post
Share on other sites
Thanks for your replies - it's the GUI system (includes many vertex buffers) that need to be recreated I believe, and fonts too possibly. The problem is if i let DX handle resizing itself it just stretches the display to fit the screen, and I don't want that. Any ideas please?

Share this post


Link to post
Share on other sites
MDX only stretches the screen to fit the display if you've cancelled the resize handling by MDX via the following:



void device_DeviceResizing(object sender, CancelEventArgs e)
{
e.Cancel = true;
}



setting e.Cancel to true stops MDX from handling it's own resizing. Instead simply reset your render states and data structs in the event without cancelling:


void device_DeviceResizing(object sender, CancelEventArgs e)
{
this.ResetRenderStates();
}



if a vertex buffer is created with the managed flag then it will automatically be recreated. You don't have to handle those if you don't want, but you have to specify managed in the pool argument during construction of the buffer. ie:

Pool.Managed;

HTH,

Devin
-Devin



Share this post


Link to post
Share on other sites
Hi, the problem is I'm using MDX 2 which doesn't have a DeviceResizing event (or allow it to be cancelled)... however my engine used to be in MDX 1.1 (which is what you're referring to) and when I didn't cancel the device resize I got the error. :S thanks for sticking with the problem anyway. this is all very confusing - maybe i could send the code to someone to look at if anyone's feeling very helpful ? it would be much appreciated...

EDIT: I just realised that after removing the GUI system now, it doesn't help. In fact, if I render nothing it still occurs; the only time it *doesn't occur* is when I don't load any resources at all.

[Edited by - alex_myrpg on May 31, 2006 6:54:01 AM]

Share this post


Link to post
Share on other sites
Ok, well I've just figured out it's to do with Video (DirectShow .NET) and a thing called the VMR Allocator. I believe it's because surfaces in Pool.Default aren't getting reset or something, but I don't know enough to explain more sorry. Thanks for all the help anyway!

Share this post


Link to post
Share on other sites
Yes perhaps if you posted some code. I'm not familiar with MDX2 as I won't be using it. Actually I think it's a dead end to even use it as Microsoft won't offically support it. They are migrating to XNA and MDX2, from what I've read, is just FYI or something. I'll stick with MDX1 till XNA is fully saturated.

And please, correct me if I'm wrong :)

-Devin

Share this post


Link to post
Share on other sites
Well as far as I'm concerned, it's really not very different and easy to convert back. And maybe I could just send the Allocator and Video classes that I use to render video (using the DirectShow .NET library). You may not be familiar with the DirectShow parts but the surfaces are what's causing the problem and that's plain old Direct3D. If you're willing to help more, please PM me your email so I can send you the Allocator class - thanks very much.

Share this post


Link to post
Share on other sites
I may have been wrong about MDX2. I read in another post that perhaps XNA will ship with MDX2. I beleive what I should have said is that MDX2 is not currently an active system, but will be. So the question is how much will it change when an official release is made?

I'll pm you in a sec.

-Devin

Share this post


Link to post
Share on other sites
Hey, are you still around devronious? I've really narrowed down the source of the problem now but it's not quite yet fixed. Please PM me/reply if you are. Thanks

Share this post


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

  • Advertisement