0

我正在尝试使用 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 / 其他一些位的代码,因为它只是噪音,但如果需要可以提供)

4

3 回答 3

1

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

  • 如果您使用System.Windows.Forms,则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并默认启用双缓冲。

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

希望能帮助到你!

于 2013-10-17T22:55:35.473 回答
1

DirectX 总是使用双缓冲,你不能禁用它(你可以使用三重缓冲,但到目前为止我还没有看到这个用例)。

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

于 2013-10-23T19:20:17.467 回答
0

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

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

您会注意到,褪色是基于帧号而不是经过的时间。因此,当帧速率上升时,淡入淡出速度也...

于 2014-05-20T07:16:43.157 回答