当前位置: 首页 > 知识库问答 >
问题:

窗口调整大小和DWM激活时OpenGL闪烁/损坏

史淇
2023-03-14

我有一个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而不是Direct3D,这甚至是一个问题,尽管我还没有测试过这一点,因为它代表了很多工作。

共有3个答案

夏弘义
2023-03-14

嗯,也许您遇到了同样的问题:如果您使用“new”MFC,它将使用Tabs和Window Spliter创建和应用程序。

拆分器有一些逻辑(我猜是在透明窗口周围的某个地方并为拆分绘制异或线)导致了这种行为。删除拆分器以确认它解决了您的问题。如果您需要拆分功能-放入不同的拆分器。

此外,选项卡允许停靠和再次拆分具有相同问题的窗口——删除/替换。

祝你好运,伊戈尔

施辉
2023-03-14

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

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

第一个坏蛋可以追溯到SetWindowPos()中的XP/Vista/7BitBlt,Windows在窗口调整期间在内部执行,并且可以通过拦截WM_NCCALCSIZE或拦截WM_WINDOWPOSCHANGING的其他技巧来消除。

在Windows 8 / 10中,我们仍然有这个问题,但是我们有一个新的坏人,Aero DWM.exe窗口管理器,当他认为你“落后”更新屏幕时,他会做自己不同类型的BitBlt

我怀疑你看到的垃圾像素实际上可能是DWM有意且非常糟糕的尝试,在等待你绘制时填充一些“可接受的”东西。我发现DWM在点亮新客户端区域时扩展了旧客户端区域数据的边缘像素,这太疯狂了。

不幸的是,我不知道任何100%的解决方案来阻止DWM这样做,但我确实有一个定时黑客,大大降低了它的频率。

有关WM_NCCALCSIZE/WM_ WINDOWPOSCHANGINGhack以及DWM计时hack的源代码,请参阅:

如何平滑调整窗口大小时难看的抖动/闪烁/跳跃,尤其是拖动左/上边框(Win 7-10;bg,bitblt和DWM)?

东门楚
2023-03-14

这是一个长期的尝试,但我刚刚自己解决了完全相同的问题。

长镜头部分之所以出现,是因为我们正在绘制包围我们的OpenGL窗口的无标题分组框的轮廓(即,制作一个漂亮的小边框),这可能无法描述您的情况。

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

我们一直在使用 RoundRect() 调用(带有HOLLOW_BRUSH)来绘制分组框的轮廓。将其更改为 MoveToEx() 和 LineTo() 调用,以确保只绘制线条,并且在分组框中不执行任何操作,使 GDI 不会尝试意外地重绘控件的整个内容。在失效逻辑上可能存在差异(或者我们在加载预期的空心刷子时遇到了一个错误)。我们仍在调查中。

-诺埃尔

 类似资料:
  • 我正在尝试构建一个包含6个窗格(作为父级添加到GridPane布局中)的简单Java项目。我必须在开始时设置窗口大小,并通过参考根布局的宽度和高度,设法将它们均匀地拆分。 但我想要他们调整大小,因为我改变了窗口的大小(使用鼠标,现在他们得到固定的大小)。 下面是我的代码:

  • 我目前正在编写一个具有LineChart的程序,在这个问题的帮助下,我有条件地对其背景进行了着色。当我调整我的JavaFX程序所在的窗口大小时,颜色会扭曲整个地方。 如你所见,颜色从来没有被“清理”过。下面是我绘制多边形和linechart的代码: (代码被清除了一点,我排除了一些我认为不相关的内容)

  • 窗口大小,我们可以非常方便的使用width、height调整,但是如何知道 width和height是一个问题? 在 Window 操作系统中,假如我们想要缩放,我们通常会把鼠标移动到窗口的右边栏,和底部边栏,以及右下边栏。 而且在不同的边栏,鼠标呈现的样式也是不一样的。当我们在右边栏的时候我们可以通过cursor: e-resize;模拟鼠标样式。 在底部边栏我们可以通过cursor: s-re

  • #include <stdio.h> void fun1(void) { int i = 0; i++; i = i * 2; printf("%d\n", i); } void fun2(void) { int j = 0; fun1(); j++; j = j

  • 有人能帮我理解一下在flink中的窗口(会话)是什么时候和如何发生的吗?或者样品是如何加工的? 例如:假设定义的时间窗口是30秒,如果一个事件在t时间到达,另一个事件在t+30,那么这两个事件都将被处理,但是在t+31到达的事件将被忽略。 如果我说的不对,请纠正。 上面的问题是:如果一个事件在t时间到达,而另一个事件在t+3时间到达,是否还会等待整个30秒来汇总并最终确定结果? DTO: ====

  • 问题内容: 我有以下JQuery代码: 唯一的问题是,这仅在首次加载浏览器时有效,我是否还希望在调整窗口大小时进行检查? 有任何想法吗? 问题答案: 这是一个使用jQuery,javascript和css处理调整大小事件的示例。 (如果您只是通过调整大小来设置样式(媒体查询),最好的方法是CSS) [ CSS javascript jQuery 如何停止调整大小的代码执行如此频繁! 这是绑定到调整