OpenGL闪烁/损坏,窗口调整大小并且DWM处于活动状态

时间:2012-05-16 09:07:01

标签: c++ windows opengl direct3d dwm

我有一个wxWidgets应用程序,它有许多子opengl窗口。我正在使用自己的GL画布类,而不是wx类。 Windows共享他们的OpenGL上下文。 我不认为它是wxwidgets的事实在这里真的很重要。

opengl窗口是窗口的子窗口,它们是彼此的兄弟,包含在选项卡控件中。 MDI样式界面的种类,但它不是MDI窗口..每个窗口都可以单独调整大小。除非启用Aero并且DWM处于活动状态,否则所有工作都很可爱。

调整任何窗口(甚至不是opengl窗口)的大小会导致所有opengl窗口偶尔闪烁,其中包含一个过时的后备存储视图,其中包含屏幕上那个非opengl的垃圾。这仅在启用Aero时发生。

我很确定这是DWM实际上没有在其绘图表面支持商店中的opengl内容,并且窗口没有在正确的时刻重新绘制。

我已经尝试了很多东西来解决这个问题,我确实有一个解决方案,但它不是很好,并且需要将带有glReadPixels的帧缓冲区读入DIB,然后在我的onPaint例程中将其blitting到paint DC。这种解决方法仅在DWM处于活动状态时才启用,但我根本不必这样做,因为它会稍微损害性能(但在功能强大的系统上也不会太糟糕 - 场景是相对简单的3d图形)。也不推荐混合使用GDI和opengl,但这种方法令人惊讶。我现在可以忍受它,但我宁愿不必。如果我想截取子窗口的截图,我仍然需要在WM_PRINT中执行此操作,我没有看到解决方法。

是否有人知道更好的解决方案?

在有人要求之前我肯定会做以下事情:

  • Window类具有CS_OWNDC
  • WM_ERASEBACKGROUND不执行任何操作并返回TRUE。
  • 启用双缓冲。
  • Windows具有WS_CLIPSIBLINGS和WS_CLIPCHILDREN窗口样式。
  • 在我的resize事件处理程序中,我立即重新绘制窗口。

我试过了:

  • 在像素格式描述符中设置PFD_SUPPORT_COMPOSITION。
  • 在绘图处理程序中不使用wxPaintDC并调用 :: ValidateRect(hwnd,NULL)代替。
  • 处理WM_NCPAINT并排除客户区
  • 通过DWM API禁用NC涂料
  • 在paint事件中排除客户区
  • 在缓冲区交换之前和之后调用glFlush和/或glFinish。
  • 在每个油漆事件中失效(作为测试!) - 仍然 闪烁!
  • 未使用共享的GL上下文。
  • 禁用双缓冲。
  • 写入GL_FRONT_AND_BACK

禁用DWM不是一种选择。

据我所知,如果你使用Direct3D而不是OpenGL ,这甚至会出现问题,虽然我没有对此进行测试,因为它代表了很多工作。

3 个答案:

答案 0 :(得分:3)

这是一个远景,但我只是自己解决了同样的问题。

远视部分是因为我们正在为我们的OpenGL窗口周围的无标题组框的轮廓绘制(即,制作一个漂亮的小边框),这可能无法描述您的情况。

我们发现导致问题的原因是:

我们一直在使用RoundRect()调用(使用HOLLOW_BRUSH)来绘制组框的轮廓。将其更改为MoveToEx()和LineTo()调用以确保只绘制线条,并且在组框内没有任何操作,这使得GDI不会尝试意外地重新绘制控件的整个内容。失效逻辑可能存在差异(或者我们在装载预期的空心刷时有某种错误)。我们还在调查。

-Noel

答案 1 :(得分:1)

我的应用程序只有一个OpenGL窗口(主窗口),但是在调整窗口大小时遇到​​了一些讨厌的DWM撕裂问题,我想知道其中一种解决方案是否对您有用。

首先,我发现在调整窗口大小的过程中,至少有两个不同的坏人想要在有机会自己更新窗口并产生闪烁之前通过修改客户区域来“帮助”您。

第一个坏人的历史可以追溯到BitBlt内的XP / Vista / 7 SetWindowPos(),Windows在调整窗口大小时会在内部进行操作,并且可以通过涉及拦截WM_NCCALCSIZE的技巧来消除或涉及拦截WM_WINDOWPOSCHANGING的其他技巧。

在Windows 8/10中,我们仍然存在该问题,但是我们有一个新的坏人,Aero DWM.exe窗口管理器,当他认为您“落后”时,他将使用他自己的另一种BitBlt更新屏幕。

我怀疑您所看到的垃圾像素实际上可能是DWM在等待您绘制时填写的“可以接受”的东西,这是有意的且非常差劲的尝试。我发现DWM在使新的客户区发疯时会扩展旧客户区数据的边缘像素。

不幸的是,我不知道有什么100%的解决方案可以阻止DWM做到这一点,但是我确实有一个定时破解功能,可以大大降低DWM的发生频率。

有关WM_NCCALCSIZE / WM_WINDOWPOSCHANGING黑客以及DWM定时黑客的源代码,请参见:

How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?

答案 2 :(得分:0)

嗯,也许你遇到过同样的问题:如果你使用的是“新”MFC 它将使用Tabs和Window Spliter创建和应用。

分离器有一些逻辑(我猜测透明窗口周围的某处并绘制XOR 导致此行为的拆分行。卸下分离器以确认它已解决 你的问题。如果您需要拆分功能 - 请放入不同的拆分器。

此外,标签允许对接并再次拆分具有相同问题的窗口 - 删除/替换。

祝你好运, 伊戈尔