Question

I'm trying to use SlimDX to create a DirectX9 application.

If I use .PresentationInterval = PresentInterval.Default, it renders at ~The refresh rate of my monitor and looks fine.

If I use .PresentationInterval = PresentInterval.Immediate, I get ~6,000 FPS but there is severe flickering - presumably because the device is being updated when the immediate presentation happens and thus it may or may not be correctly drawn.

Can someone tell me how I can use a back-buffer so that immediate doesn't flicker and the buffers are swapped when I've finished drawing?

Obviously, I don't actually want 6K FPS but I do want control the frame rate cap and also have a better understanding of buffering.

Device initialisation

PresentParameters = New PresentParameters()

With PresentParameters
    .BackBufferFormat = Format.X8R8G8B8
    .BackBufferCount = 2
    .Multisample = MultisampleType.None
    .SwapEffect = SwapEffect.Discard
    .EnableAutoDepthStencil = True
    .AutoDepthStencilFormat = Format.D24S8
    .PresentFlags = PresentFlags.DiscardDepthStencil
    .PresentationInterval = PresentInterval.Default '' or PresentInterval.Immediate
    Select Case Settings.Display.Mode
        Case WindowMode.FullScreen
            .BackBufferWidth = Settings.Display.Width
            .BackBufferHeight = Settings.Display.Height
            .Windowed = False
        Case WindowMode.Windowed Or WindowMode.WindowedNoBorder
            .BackBufferWidth = Settings.Display.Width
            .BackBufferHeight = Settings.Display.Height
            .Windowed = True
    End Select
    .DeviceWindowHandle = Handle
End With

Direct3D = New Direct3D()
Device = New Device(Direct3D,
                    Settings.Display.Adapter,
                    DeviceType.Hardware,
                    Handle,
                    CreateFlags.HardwareVertexProcessing,
                    PresentParameters)

Minimal Render sample...

Context9.Device.BeginScene()
Context9.Device.Clear(Direct3D9.ClearFlags.Target Or Direct3D9.ClearFlags.ZBuffer,
                Color.Black,
                1.0F,
                0)

Game.Render(Context9)

Using Sprite As New Sprite(Context9.Device)
    Sprite.Begin(SpriteFlags.AlphaBlend)
    Dim Mtx = Matrix.Translation(125, 200, 0)
    Dim Scaling = Matrix.Scaling(0.5, 0.5, 1)
    Matrix.Multiply(Mtx, Scaling, Mtx)
    Sprite.Transform = Mtx

    Dim Fade As Single = CSng(Math.Min(1, Math.Sin(FrameI / 30) * 0.5 + 0.5))
    Sprite.Draw(TestTex,
                Nothing,
                Nothing,
                Nothing,
                New Color4(Fade, Fade, Fade))


    Sprite.End()
End Using

Context9.Device.EndScene()

Context9.Device.Present()

Window Creation / Main Loop

Private Sub Run()
    Application.EnableVisualStyles()
    Application.SetCompatibleTextRenderingDefault(False)

    Window = New RenderForm("Test")

    InitializeDevice()

    ''Add lots of key handlers, etc here

    LoadResources()

    Clock.Start()
    MessagePump.Run(Window, AddressOf MessageLoop)
    Cleanup()

    Window.Dispose()
End Sub

Sub MessageLoop()
    Update()
    If Not IsResizing Then
        Render()
    End If
End Sub

(I've omitted the code to show FPS / some other bits as it's just noise but can provide it if required)

Was it helpful?

Solution 3

So.... It turns out this was a case of stupidity.

Dim Fade As Single = CSng(Math.Min(1, Math.Sin(FrameI / 30) * 0.5 + 0.5))

As you'll notice, the fading was based on the frame number not the elapsed time. So when the frame rate shot up, so did the fade speed...

OTHER TIPS

I can be wrong, but I believe this have nothing with DirectX. You must enable double buffering on window creation.

  • If you using System.Windows.Forms, then call Control.SetStyle() as described here:

    public void EnableDoubleBuffering()
    {
          // Set the value of the double-buffering style bits to true. 
          this.SetStyle(ControlStyles.DoubleBuffer | 
          ControlStyles.UserPaint | 
          ControlStyles.AllPaintingInWmPaint,
          true);
          this.UpdateStyles();
    }
    
  • Or better, just use SlimDX.Windows.RenderForm. It is derived from Form and has double buffering enabled by default.

Another cause of flickering can be wrong main loop structure. You didn't show us your main loop and how you invoke your rendering function. You can find typical rendering loop in tutorials.

Hope it helps!

DirectX is always using double buffering, you cannot dissable this (you could go for tripple buffering, but so far I have not seen an use case for this).

What happens is that with Default, the backbuffer is copied to the screen between two frames of the monitor. With Immediate, this happens directly. This will always flicker a bit, especially if the new image is very different from the old, because the top half of the screen will show one image and the bottom the next. For most cases, it is not useful to render faster than with the refresh rate of the monitor.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top