使用SlimDX进行双缓冲

时间:2013-10-17 21:21:24

标签: .net directx slimdx doublebuffered

我正在尝试使用SlimDX创建DirectX9应用程序。

如果我使用.PresentationInterval = PresentInterval.Default,它会以〜我的显示器的刷新率呈现并且看起来很好。

如果我使用.PresentationInterval = PresentInterval.Immediate,我会得到~6,000 FPS,但是会出现严重的闪烁 - 可能是因为当立即呈现时设备正在更新,因此可能会或可能没有正确绘制。

有人可以告诉我如何使用后台缓冲区,以便在完成绘图后立即不会闪烁并且交换缓冲区吗?

显然,我实际上并不想要6K FPS,但我确实希望控制帧速率上限,并且对缓冲有更好的理解。

设备初始化

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)

最小渲染样本......

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()

窗口创建/主循环

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

(我省略了显示FPS /其他位的代码,因为它只是噪音,但如果需要可以提供它)

3 个答案:

答案 0 :(得分:1)

我可能错了,但我相信这与DirectX无关。您必须在创建窗口时启用双缓冲。

  • 如果您使用System.Windows.Forms,请按照here所述致电Control.SetStyle()

    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();
    }
    
  • 或者更好,只需使用SlimDX.Windows.RenderForm即可。它派生自Form并默认启用双缓冲。

闪烁的另一个原因可能是错误的主循环结构。您没有向我们展示您的主循环以及如何调用渲染功能。您可以在tutorials中找到典型的渲染循环。

希望它有所帮助!

答案 1 :(得分:1)

DirectX总是使用双缓冲,你不能这样做(你可以去做tripple缓冲,但到目前为止我还没有看到一个用例)。

如果使用默认值,后备缓冲区将被复制到监视器两帧之间的屏幕上。使用Immediate,直接发生这种情况。这将总是闪烁一点,特别是如果新图像与旧图像非常不同,因为屏幕的上半部分将显示一个图像而下一个图像将显示底部。对于大多数情况,渲染速度比监视器的刷新速率更快是没有用的。

答案 2 :(得分:0)

所以....事实证明这是一个愚蠢的案例。

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

正如您将注意到的,衰落基于帧数而不是经过的时间。所以当帧率上升时,褪色速度也会提高......