When I wrote the story of microsleep, it was only part of a larger story, namely that of rendering to multiple monitors. The microsleep issue was only one problem that I ran into. Aside from that problem with the multithreading itself, I also ran into two other problems. It truly gives you that “off the beaten path”-feeling, when you run into bugs one after the other. Although the OS and the APIs are designed to handle multithreading and multi-monitor applications, it seems like the standard single-monitor setup is far more mature.
Vista is better than Windows 7
The first problem I ran into was when I wanted to have multiple windows fullscreen at the same time. I was using two separate videocards for this. First I made it work in Direct3D9, and that seemed to go okay in Windows 7. Then I worked on the DXGI version of the code, for D3D10 and above… And no matter what I tried, I could not get both windows to go fullscreen at the same time. As soon as I set the second window to fullscreen, the first window popped back to windowed mode for no apparent reason.
I looked over my code dozens of times, re-read the DXGI documentation again and again, tried various variations… but nothing I did made it work. I looked at the MultiMon example from the DirectX SDK, but even that didn’t work. Eventually I found this thread discussing the same issue.
So, apparently it is a known issue to Microsoft. In fact, I even found the bugreport on their Connect website at the time, and I added a comment myself. I can no longer find it though, I think they closed off that part of Connect, now that they are focusing on Windows 8 and Visual Studio 11 (which make the DirectX SDK obsolete).
However, as Charybdis is very specific about DXGI 1.1, I was wondering: does that mean it works on Vista with only DXGI 1.0? So I tested my code, and indeed: in Vista it works fine! My code was good all along. In fact, even with the Platform Update installed, it seems to work (which adds DXGI 1.1 and DirectX 11 support for Vista). So by the looks of it, it is a Windows 7-specific bug. However, Microsoft never bothered to fix it, and I doubt they ever will. I can only hope that the bug is not present in Windows 8.
For the time being, I will just need a workaround for Windows 7, much like how the microsleep is really just a workaround for the Aero problem. I have two options here:
- Use Direct3D 9 only
- Use a ‘fake’ fullscreen mode, by using a borderless window that is topmost, and maximized to fill the entire screen.
It’s obvious why 1. is not very ideal. I would not be able to use any new functionality. For 2. I may need to give a little more background information. What is the difference between windowed mode and fullscreen mode?
For starters, when you switch to fullscreen mode you can also control the resolution and refreshrate. So you can switch to a different screenmode than the regular desktop configuration. When your program exits (even if it crashes), the desktop settings are restored. You can implement switching yourself, using ChangeDisplaySettingsEx(), but if your program crashes, the original settings won’t be restored, which can be rather annoying (an issue that is present in many OpenGL applications as well).
There are also various other advantages to real fullscreen. For example, you can specify the actual pixelformat you want to use. Also, when in fullscreen mode, the frontbuffer and backbuffer can simply be flipped, where in windowed mode it will require a blt instead. Another advantage is that you can run in ‘exclusive mode’ in fullscreen, which means that the desktop manager is shut off altogether for your screen, which removes some CPU overhead and also frees up videomemory.
So there are various reasons why you would want to use fullscreen mode rather than just faking it via windowed mode. But sadly, that is not an option in Windows 7.
Direct3D vs OpenGL
The other problem I ran into was when I ported the multithreaded windowing code to my OpenGL renderer. I set up a simple test case where I could instance as many threads/windows/renderers as I liked, each playing back the claw animation that is used in the BHM sample. In Direct3D everything ran fine with 10 windows side-by-side. Each window had its own framerate counter, so I could see that the load was balanced quite nicely by the thread scheduler:
In OpenGL however, things weren’t going that well. Not only did the framerate counters jump up and down erratically for each window, but the animations themselves were actually looking rather jerky:
This was on my machine with my GeForce GTX460. I first tested it under Windows 7. I then decided to also try Vista and XP, but they all showed the same problem. So I decided to also test it on some other machines. One had a Radeon HD5770, the other a Radeon X1900XTX. Both machines ran the application smoothly. The average framerates were lower than on my GTX460, but they were smoother nonetheless. So, since D3D worked fine, and the Radeons worked fine as well, I figured I could rule out the Windows scheduler as the main cause for the load balancing problems. It seemed to be specific to the nVidia OpenGL driver.
So I decided to report it to nVidia as a driver bug. I sent them a link to the program as well, which should make it easier for them to reproduce and analyze the problem. And indeed, nVidia responded that they have been able to reproduce the problem. They said they had found the cause in their drivers, and that they hope to have a fix in a future driver.
Now that’s nice. At least one of my problems is actually going to get fixed! If only Microsoft was that committed. The other day I installed the new 301.42 drivers, and when I ran my test program again, it seemed to balance quite a bit better. I’m not sure if this driver already includes the fix for this problem, or if it’s just a coincidence that it runs better now (the changelog does not seem to make mention of the issue). It’s still not perfect, but it’s acceptable: