【问题标题】:SharpDX on Windows form - Race condition when minimizing screenWindows 窗体上的 SharpDX - 最小化屏幕时的竞争条件
【发布时间】:2017-08-16 13:07:59
【问题描述】:

我有一个问题一周以来无法解决,我希望有人能遇到过这种情况。

我正在将 SharpDX 与 windows 窗体项目一起使用,基本上有一个带有图片框和一些面板的窗体。

当我缩放或翻译图像时,典型的 Swapchain.Present(1,PresentFlags.None) 效果很好。但是,我遇到了这种奇怪的情况,当我最小化屏幕并重新打开它时,所有交换链内容都被隐藏起来,就像它已被删除一样。但是,我知道它没有,这可能是 GDI 刷新和 SharpDX 之间的竞争条件。

所以,我尝试在每个控件中覆盖 WndProc(Message m) 并处理它的绘制和擦除背景事件。这是行不通的。当我调试时,windows消息总是不时不同,所以很难找出可能是什么问题。

如果有人在 Windows 窗体上混合 SharpDX(或 directX)时遇到过这种行为,我真的很想得到答案。

这是我如何处理 SharpDX DeviceContext 的调整大小事件

Public Overrides Sub Resize(Width As Integer, Height As Integer)
      If m_SwapChain IsNot Nothing Then
         If m_BackBuffer IsNot Nothing Then
            m_BackBuffer.Dispose()
         End If
         If m_2DDeviceContext IsNot Nothing Then
            m_2DDeviceContext.Dispose()
         End If
         If m_2DTarget IsNot Nothing Then
            m_2DTarget.Dispose()
         End If

         m_SwapChain.ResizeBuffers(2, Width, Height, Format.B8G8R8A8_UNorm, SwapChainFlags.GdiCompatible)

         m_BackBuffer = m_SwapChain.GetBackBuffer(Of Surface)(0)

         m_2DDeviceContext = New SharpDX.Direct2D1.DeviceContext(m_2DDevice, SharpDX.Direct2D1.DeviceContextOptions.EnableMultithreadedOptimizations)

         m_2DTarget = New SharpDX.Direct2D1.Bitmap(m_2DDeviceContext, m_BackBuffer, m_Properties)
         m_2DDeviceContext.AntialiasMode = AntialiasMode.PerPrimitive

         m_2DDeviceContext.Target = m_2DTarget

         CType(m_Context, GPUDrawingContext).DeviceContext = m_2DDeviceContext
      End If

   End Sub

编辑: 在尝试了很多东西之后,当我调用 base.Wndproc(m) where m = WM_PAINT 时,我意识到它正在发生。

我不能忽略绘制消息,因为如果我这样做了,我的控件仍然无效,它会在事件队列中添加一个新的 WM_PAINT 并将我发送到一个无限循环。我真的不能做 base.Wndproc(m) 因为这是我的交换链隐藏的地方。

他们是否有任何方法来处理(忽略)此事件消息而无需将其重新置于循环中,因为 SharpDX 不需要此功能,因为它是控件上的油漆层。

【问题讨论】:

  • 你能展示一些代码吗(特别是你如何处理调整大小事件)?否则很难猜出发生了什么。
  • 我编辑了我的帖子以添加我如何处理来自 SharpDX 的 deviceContext 大小调整,但我不确定这是否是您想要看到的。 (我不认为这来自它)
  • 我确实记得最小化将大小设置为 0 的情况(并且尝试创建任何大小组件为零的交换链当然会带来各种问题)。我最终会首先检查这种情况(而不是在那种情况下重建交换链)。
  • 此外,您最终应该确保在表单最小化时什么都不做(例如,不执行任何绘图/演示调用)。这在主循环开始时很容易做到(通过检查表单标志)。
  • 除了所有的windows事件消息外,最小化没有做任何事情。此外,我的课程用于两个项目(两个窗口形式)我只在一个项目中遇到这个问题,而在另一个项目中没有。所以我最好的选择可能是因为这个项目有孩子,因为另一个没有?图片框的孩子可以刷新图片框以删除我的内容吗?

标签: c# winforms directx sharpdx


【解决方案1】:

当您只想调整交换链的大小时,您不必重新创建 DeviceContext。也许这是您的问题的第一个原因,因为交换链是使用与后缓冲区不同的 DeviceContext 创建的。 对我来说,这是在 C# 中工作的:

首先将事件处理程序添加到控件的调整大小事件中。无需覆盖 WM_PAINT:

form.ResizeBegin += (o, e) => {
    formHeight = ((Form)o).Height;
    formWidth = ((Form)o).Width;
};
form.ResizeBegin += (o, e) => {
    isResizing = true;
};
form.ResizeEnd += (o, e) => {
    isResizing = false;
    HandleResize(o, e);
};
form.SizeChanged += HandleResize;

这样我可以保存控件的旧尺寸以进行比较。而且我只是在调整大小完成后调整交换链的大小,而不是针对每个事件(比如调整窗口大小时)。此外,如果控件未最小化,我只会调整大小:

private void HandleResize(object sender, System.EventArgs e) {
    Form f = (Form)sender;
    if ((f.ClientSize.Width != formWidth || f.ClientSize.Height != formHeight)
        && !isResizing
        && !(f.WindowState == FormWindowState.Minimized)) {
        formWidth = f.ClientSize.Width;
        formHeight = f.ClientSize.Height;

        DoResize(formWidth, formHeight);
    }
}

最后 DoResize 如下(renderTarget 是我的自定义类):

private void DoResize(int width, int height) {
    renderTarget.Dispose();
    swapChain.ResizeBuffers(1, width, height, Format.R8G8B8A8_UNorm, SwapChainFlags.AllowModeSwitch);
    using (var resource = Resource.FromSwapChain<Texture2D>(swapChain, 0)) {
        //recreate the rendertarget with the new backbuffer
        renderTarget.Resize(width, height, resource);
    }
}

【讨论】:

    猜你喜欢
    • 2015-10-18
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    相关资源
    最近更新 更多