OpenGL/GDI sync

I realize this is a sin against humanity, but I need to overlay GDI on top of an OpenGL rendering. This is all done in .NET 2.0 using C#. The OpenGL calls are provided by DLLImports from opengl32.dll so context creation/makecurrent haven’t changed.

At the moment, I’m creating a context using the handle of a form, and both OGL and GDI show up. Both are double buffered (are they sharing the pixel format desc?) and the OGL runs smooth but the GDI flickers.

So I’m close I suppose. I’m not asking anyone to come out and solve this (though feel free), rather I want to know if anyone has tried anything like this or if anyone can offer any suggestions or insight about how OGL/GDI share the same graphics area?

GDI itself is not double buffered! It doesn’t know anything about OpenGL’s backbuffer either.
It’s also just not supported by some implementations on double buffered pixelformats (Microsoft’s being one!) and you must check the PFD_SUPPORT_GDI flag.
Under Vista mixing of GDI with 3D APIs is more troublesome. Search for “OpenGL” here:
http://msdn.microsoft.com/windowsvista/support/lhdevfaq/avalon.aspx

If you can avoid GDI, you’re better off with pure OpenGL rendering.

You could try offscreen rendering and then use GDI functions to put rendered image to window. Will cost performance, but should be simple to implement.

You could also create single buffered OpenGL view in your window and update only what’s need to be updated (could use stencil buffer to mask areas covered by other windows) and when it needs to be updated (only in response to WM_PAINT message). This would also require rendering to texture first if you want something more complex and flicker-free.

Thanks for the comments all.

Relic:
I thought they might share the same buffer since the GDI flickering goes away when I remove the OpenGL SwapBuffers call. Why would this call remove any GDI above it? Unfortunately I can’t avoid using GDI unless I want to re-implement a lot of it in OpenGL. Also I’m not concerned about Vista at this point.

kszdzech:
I could, but how would I get the image from OpenGL? Are you thinking ReadPixels() and then create a Windows Image from that? Sounds slow, but you’re right, it’d probably work ok. I might give this a shot

An OpenGL swap buffers call repaints the whole client area with the OpenGL back buffer contents, all your GDI rendering is erased at that point.
GDI only renders into the front buffer and that must be done after that swap buffers.
You will see it flickering because of that visible erase and repaint action.
I can’t describe it simpler.
Select a single buffered pixelformat and OpenGL will flicker the same way.

Worse, you must correctly synchronize OpenGL vs. GDI using glFinish() (and maybe GDIFlush()) or the rendering might run into race conditions.

All workarounds compositing OpenGL rendering with GDI in an offscreen buffer and then updating with a SwapBuffers or GDI BitBlt will cost you a lot of performance.

Right, I understand why flickering happens in general, I just didn’t realize SwapBuffers took everything in the window with it.

As far as flushing, I’ve tried calling glFinish, SwapBuffers, then GdiFlush, with no obvious effects. This is the right order, correct?

It depends on your OpenGL implementation if you would have seen any problems to begin with.
Some implementations render synchronously and don’t need this, but you’d never know.
This is not about the flicker you can’t fix that while rendering with GDI on top of the OpenGL.

There is another flicker effect which happens if you don’t implement a window message handler for the ERASEBKGND message. Because OpenGL renders your whole window you must prevent the default erase background message handler from clearing the client area with the windows workspace color.
Always write a WM_ERASEBKGND hander which just contains “return 1;” for OpenGL windows.

The secure mechanism is to put glFinish() immediately before your GDI rendering (after the swap). Mind, you need to have the OpenGL context still current for that.
OpenGL rendering after the GDI should not run into trouble because you render into the back buffer first. If the OpenGL is that quick that the GDI rendering has not finished before the next swap buffers, you’d never see the GDI rendering completely.
You might add another glFinish before the OpenGL rendering to give GDI some time, but that’s likely overkill.

Anyway, I would take all steps to eliminate GDI rendering into an OpenGL window.
What exactly do you need to re-implement in OpenGL to replace GDI rendering?

I’ll give the additional glFinish a shot when I can. This morning I was also toying with the idea of playing with GdiSetBatchLimit…not sure if that’ll do anything.

I’m using the new Designer classes in C# to implement an OpenGL based form designer. It’s essentially drag/drop triangles/etc onto an OpenGL window.

The built-in designers offer a lot of GDI help such as resize handles. Reimplementing these would mean implementing their behavior (as well as their rendering), which isn’t something I’d like to do.

If I can’t get rid of the flicker, I may have to bite the bullet and implement the above. The GDI flicker is just too annoying.

Make sure you request a pixel format with the PFD_SUPPORT_GDI flag.

But I suggest you abandon this approach - its not well supported on XP and wont work at all under Vista.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.