Thursday, March 25, 2010

Windows 7 and OpenGL

I've recently been writing some OpenGL code under Windows 7 x64. This has been rather disappointing for me. I hadn't written any OpenGL code in a while, and my first few attempts didn't seem to work at all. Nothing I drew showed up at all -- even something as simple as clearing the background just wouldn't work!

After several attempts (and a bit of head-scratching) I accidentally resized the window - and suddenly, what I had drawn all showed up. A bit more testing showed that quite a bit of the time, resizing the window or minimizing and re-displaying the window would get it to draw correctly. Knowing that these invalidate the window and force it to be redrawn, I added a quick hack to set a timer when the window was initialized, and responded to the timer by invalidating the window. This helped quite a bit -- sometimes things still didn't show up correctly, but at least they usually did, though I sometimes had to wait a second or two before (for example) the content scaled correctly after I resized the window. One other detail bothered me a bit: my code seemed slow and sluggish -- in fact, my old laptop (still running Windows XP, because it only has 512M of RAM) seemed faster than my desktop, despite much slower hardware in general.

This got to me thinking back over things I'd heard when Windows Vista was new, about how it composed an images of the windows being displayed and displayed them all via Direct3D. That made me wonder, so after a little looking, I found the control panel where I could turn that off ("Performance Information and Tools"). With "Enable desktop composition" turned off, suddenly all my OpenGL code worked beautifully! Everything displayed perfectly every time, and it was fast!

Based on this, I did a bit of looking and added a couple of lines of code to automatically disable desktop compositing while my OpenGL program was running. During initialization, it calls:


DWM_hack = S_OK != DwmEnableComposition(DWM_EC_DISABLECOMPOSITION);


and during shutdown, it does:


DwmEnableComposition(DWM_EC_ENABLECOMPOSITION);
::RedrawWindow(NULL,
NULL,
NULL,
RDW_INVALIDATE | RDW_UPDATENOW);


The "DWM_hack" is a Boolean that controls whether to set the timer that invalidates the window -- so if we can't disable compositing for some reason, we'll still set the timer, and at least get mediocre results instead of things mostly failing completely. I'm not sure whether the call to RedraWindow is really necessary -- at first I didn't include it, but once I ran into the desktop being left incompletely drawn after it exited, which this is intended to prevent. It probably shouldn't really be necessary, but then nothing in this entire post should be necessary.

So, if you're trying to write OpenGL for a recent version of Windows, and things are slow and/or not working dependably, this might be one way to make the code work.

No comments:

Post a Comment