Search code examples
.netdirectxslimdxdoublebuffered

Using double-buffering with SlimDX


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)


Solution

  • 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...