OpenGL闪烁/窗口调整大小和DWM激活损坏 [英] OpenGL flickering/damaged with window resize and DWM active

查看:226
本文介绍了OpenGL闪烁/窗口调整大小和DWM激活损坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个wxWidgets应用程序,该应用程序具有许多子opengl窗口.我使用的是我自己的GL canvas类,而不是wx类.这些窗口共享它们的OpenGL上下文. 我不认为这实际上与wxwidgets有关.

I have a wxWidgets application that has a number of child opengl windows. I'm using my own GL canvas class, not the wx one. The windows share their OpenGL context. I don't think the fact it is wxwidgets is really relevant here.

opengl窗口是选项卡控件中包含的彼此同级窗口的子级.一种MDI样式的界面,但不是MDI窗口.每个界面都可以单独调整大小.除非启用了Aero且DWM处于活动状态,否则所有内容都将很可爱.

The opengl windows are children of a windows that are siblings of one another, contained within a tab control. Kind of an MDI style interface, but it is not an MDI window.. Each one can be individually resized. All works lovely unless Aero is enabled and the DWM is active.

调整任何窗口(甚至不是opengl窗口)的大小都会导致所有opengl窗口偶尔闪烁,而它们的陈旧后备视图包含屏幕上当时不是opengl的任何垃圾.这仅在启用Aero的情况下发生.

我可以肯定,这是DWM实际上在其绘图表面支持存储上没有opengl内容,并且窗口在适当的时候没有被重新粉刷.

I'm pretty certain that this is the DWM not actually having the opengl contents on its drawing surface backing store and the window not being repainted at the right moment.

我已经尝试了很多方法来解决这个问题,我确实有一个解决方案,但是它不是很好,涉及到使用glReadPixels将帧缓冲区读取到DIB中,然后在我的onPaint例程中将其缓冲到paint DC.仅当DWM处于活动状态时才启用此解决方法,但我宁愿完全不必这样做,因为它会稍微影响性能(但在功能强大的系统上不太糟糕-场景是相对简单的3d图形).另外,不建议将GDI和opengl混合使用,但是这种方法很有效.我现在可以忍受它,但是我宁愿不必这么做.无论如何,我仍然必须在WM_PRINT中执行此操作,以获取子窗口的屏幕截图,但看不到解决方法.

I've tried so many things to get round this, I do have a solution but it is not very nice and involves reading the framebuffer with glReadPixels into a DIB and then blitting it to the paint DC in my onPaint routine. This workaround is only enabled if DWM is active but I'd rather not have to do this at all as it hurts performance slightly (but not too bad on a capable system - the scenes are relatively simple 3d graphs). Also mixing GDI and opengl is not recommended but this approach works, surprisingly. I can live with it for now but I'd rather not have to. I still have to do this in WM_PRINT if I want to take a screenshot of the child window anyway, I don't see a way around that.

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

在有人问我之前,请务必执行以下操作:

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

我尝试过:

  • 在像素格式描述符中设置PFD_SUPPORT_COMPOSITION.
  • 未在绘制处理程序中使用wxPaintDC并调用 :: ValidateRect(hwnd,NULL).
  • 处理WM_NCPAINT并排除客户区域
  • 通过DWM API禁用NC绘制
  • 在绘画活动中不包括客户区域
  • 在缓冲区交换之前和之后调用glFlush和/或glFinish.
  • 在每次绘制事件时使窗口无效(作为测试!)-仍然 忽隐忽现!
  • 不使用共享的GL上下文.
  • 禁用双重缓冲.
  • 写给GL_FRONT_AND_BACK
  • Setting PFD_SUPPORT_COMPOSITION in the pixel format descriptor.
  • Not using a wxPaintDC in the paint handler and calling ::ValidateRect(hwnd, NULL) instead.
  • Handling WM_NCPAINT and excluding the client area
  • Disabling NC paint via the DWM API
  • Excluding the client area in the paint event
  • Calling glFlush and/or glFinish before and after the buffer swap.
  • Invalidating the window at every paint event (as a test!) - still flickers!
  • Not using a shared GL context.
  • Disabling double buffering.
  • Writing to GL_FRONT_AND_BACK

禁用DWM是不可选项.

Disabling DWM is not an option.

据我所知,即使您在OpenGL上使用Direct3D,这甚至是一个问题,尽管我尚未对其进行测试,因为它代表了很多工作.

And as far as I am aware this is even a problem if you are using Direct3D instead on OpenGL, though I have not tested this as it represents a lot of work.

推荐答案

这是一个远景,但是我 just 自己也解决了同样的问题.

This is a longshot, but I just solved exactly this same problem myself.

之所以出现长镜头部分,是因为我们正在绘制所有者标题,该标题围绕着我们的OpenGL窗口绘制了一个无标题的组框(即,画出一个漂亮的小边框),而这可能无法描述您的情况.

The longshot part comes in because we're doing owner draw of the outline of a captionless group box that surrounds our OpenGL window (i.e., to make a nice little border), and that may not describe your case.

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

What we found caused the problem was this:

我们一直在使用RoundRect()调用(带有HOLLOW_BRUSH)来绘制组框的轮廓.将其更改为MoveToEx()和LineTo()调用以确保仅绘制了线条,并且在组框内未进行任何操作,从而阻止了GDI尝试意外重绘控件的整个内容.无效逻辑可能会有所不同(或者我们在加载预期的空心笔刷时遇到了一个错误).我们仍在调查中.

We had been using a RoundRect() call (with a HOLLOW_BRUSH) to draw the outline of the group box. Changing it to a MoveToEx() and LineTo() calls to ensure JUST the lines are drawn and nothing gets done inside the group box kept the GDI from trying to unexpectedly repaint the whole content of the control. It's possible there's a difference in invalidation logic (or we had a bug somehow in loading the intended hollow brush). We're still investigating.

-Noel

这篇关于OpenGL闪烁/窗口调整大小和DWM激活损坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆