我有一个 wxWidgets 应用程序,它有许多子 opengl 窗口。我正在使用我自己的 GL 画布类,而不是 wx 类。窗口共享它们的 OpenGL 上下文。我不认为它是 wxwidgets 的事实在这里真的很重要。
opengl 窗口是一个窗口的子窗口,它们是彼此的兄弟窗口,包含在选项卡控件中。一种 MDI 风格的界面,但它不是 MDI 窗口。每个都可以单独调整大小。除非启用 Aero 并且 DWM 处于活动状态,否则一切正常。
调整任何窗口(甚至是 opengl 窗口)的大小会导致所有 opengl 窗口偶尔闪烁,并带有一个陈旧的后备存储视图,其中包含当时屏幕上的任何垃圾,而不是 opengl。这只发生在启用 Aero 的情况下。
我很确定这是 DWM 实际上在其绘图表面后备存储中没有 opengl 内容,并且窗口没有在正确的时刻重新绘制。
我已经尝试了很多方法来解决这个问题,我确实有一个解决方案,但它不是很好,并且涉及将带有 glReadPixels 的帧缓冲区读取到 DIB 中,然后在我的 onPaint 例程中将其传送到绘图 DC。仅当 DWM 处于活动状态时才启用此解决方法,但我宁愿根本不必这样做,因为它会稍微损害性能(但在功能强大的系统上并不算太糟糕 - 场景是相对简单的 3d 图)。也不建议将 GDI 和 opengl 混合使用,但令人惊讶的是,这种方法很有效。我现在可以忍受它,但我宁愿不必。无论如何,如果我想截取子窗口的屏幕截图,我仍然必须在 WM_PRINT 中执行此操作,我看不到解决方法。
有谁知道更好的解决方案?
在有人问之前,我肯定会做以下事情:
- 窗口类有 CS_OWNDC
- WM_ERASEBACKGROUND 什么都不做并返回 TRUE。
- 双缓冲已启用。
- Windows 具有 WS_CLIPSIBLINGS 和 WS_CLIPCHILDREN 窗口样式。
- 在我的 resize 事件处理程序中,我立即重新绘制窗口。
我试过了:
- 在像素格式描述符中设置 PFD_SUPPORT_COMPOSITION。
- 不在绘制处理程序中使用 wxPaintDC 而是调用 ::ValidateRect(hwnd, NULL) 。
- 处理 WM_NCPAINT 并排除客户区
- 通过 DWM API 禁用 NC 绘制
- 在绘制事件中排除客户区
- 在缓冲区交换前后调用 glFlush 和/或 glFinish。
- 在每个绘画事件中使窗口无效(作为测试!) - 仍然闪烁!
- 不使用共享 GL 上下文。
- 禁用双缓冲。
- 写入 GL_FRONT_AND_BACK
禁用 DWM 不是一种选择。
据我所知,如果您在 OpenGL 上使用 Direct3D 而不是这甚至是一个问题,尽管我没有对此进行测试,因为它代表了很多工作。