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.
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.
Resizing any window (not even the opengl ones) causes all of the opengl windows to flicker occasionally with a stale backing-store view that contains whatever rubbish has been on the screen at that point that is not opengl. This ONLY happens with Aero enabled.
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.
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.
Does anyone know of a better solution to this?
Before anyone asks I definitely do the following:
- Window class has CS_OWNDC
- WM_ERASEBACKGROUND does nothing and returns TRUE.
- Double Buffering is enabled.
- Windows have the WS_CLIPSIBLINGS and WS_CLIPCHILDREN window styles.
- In my resize event handler I immediately repaint the window.
I've tried:
- 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
Disabling DWM is not an option.
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.