5 Microsoft Windows Specifics
Samuel Paik has created a large repository of links to OpenGL information on Microsoft Web sites.
The consumer-level 3D graphics marketplace moves fast. Any information placed in this FAQ would be soon outdated.
You might post a query on this topic to the comp.graphics.api.opengl newsgroup, or one of the many newsgroups devoted to Wintel-based 3D games. You might also do a Web search.
Currently, OpenGL doesn't contain a switch to enable or disable hardware acceleration. Some vendors might provide this capability with an environment variable or software switch.
If you install your graphics card, but don't see hardware accelerated rendering check for the following:
- Did you install the device driver / OpenGL Installable Client Driver (ICD)? (How do I do that?)
- Is your desktop in a supported color depth? (Usually 16- and 32-bit color are accelerated. See your device vendor for details.)
- Did your application select an accelerated pixel format?
You might also have acceleration problems if you're trying to set up a multimonitor configuration. Hardware accelerated rendering might not be supported on all (or any) devices in this configuration.
To force software rendering from your application, choose a pixel format that is not hardware accelerated. To do this, you can not use ChoosePixelFormat(), which always selects a hardware accelerated pixel format when one is available. Instead, use DescribePixelFormat() to iterate through the list of available pixel formats. Any format with the PFD_GENERIC_FORMAT attribute bit set will not be hardware accelerated.
Ron Fosner has a source code snippet that shows how to select a software-only pixel format, and how to select a pixel format based on other weighting criteria.
An example of iterating over available pixel formats can be found here.
A less tasteful method to disable hardware acceleration is to move or rename your OpenGL ICD.
Also, check your device's documentation to see if your device driver supports disabling hardware acceleration by a dialog box.
OpenGL doesn't provide a direct query to determine hardware acceleration usage. However, this can usually be inferred by using indirect methods.
If you are using the Win32 interface (as opposed to GLUT), call DescribePixelFormat() and check the returned dwFlags bitfield. If PFD_GENERIC_ACCELERATED is clear and PFD_GENERIC_FORMAT is set, then the pixel format is only supported by the generic implementation. Hardware acceleration is not possible for this format. For hardware acceleration, you need to choose a different format.
If glGetString(GL_VENDOR) returns something other than "Microsoft Corporation", it means you're using the board's ICD. If it returns "Microsoft Corporation", this implies you chose a pixel format that your device can't accelerate. However, glGetString(GL_VENDOR) also returns this if your device has an MCD instead of an ICD, which means you might still be hardware accelerated in this case.
Another way to check for hardware acceleration is to temporarily remove or rename the ICD, so it can't be loaded. If performance drops, it means you were hardware accelerated before. Don't forget to restore the ICD to its original location or name. (To find your ICD file name, run the regedit utility and search for a key named "OpenGLdrivers".)
You can also gather performance data by rendering into the back buffer and comparing the results against known performance statistics for your device. This method is particularly useful for devices that revert to software rendering for some state combinations or OpenGL features. See the section on performance for more information.
If your device supports OpenGL, the manufacturer should provide an ICD (commonly referred to as the device driver) for it. After you install the ICD, your OpenGL application can use the device's hardware capabilities.
If your device didn't come with an ICD on disk, you'll need to check the manufacturer's Web page to see where you can download the latest drivers. The chip manufacturer will probably have a more current ICD than the board manufacturer. Find the device driver download page, get the latest package for your device, and install it per the instructions provided.
GLsetup is a free utility. Although the authors website no longer exists, you can still download a copy of the program from MajorGeeks.com. GLSetup is supposed to detect a user's 3D graphics hardware and install the correct device drivers." Windows 2000 device drivers might not be supported. You can still get it from http://www.majorgeeks.com/GLSetup_d383.html.
It could simply be a bug in your code. However, if the same code works fine on another OpenGL implementation, this implies the problem is in your graphics device or its ICD. See the previous question for information on obtaining the latest ICD for your device.
Moxing OpenGL rendering calls with rendering calls from other APIs (such as DirectDraw) in the same window won't work on some drivers, and is therefore unportable. I don't recommended it.
You can create a window and use DirectDraw to change the display resolution and/or pixel depth. Then, get the window's DC and create an OpenGL context from it. This is known to work on some devices.
While we're on the subject, Microsoft doesn't require, and consequently does not test for, the ability to render OpenGL into a DirectDraw surface. Just because you can get a surface's DC does not mean that OpenGL rendering is supported. Always check for error returns when creating contexts or maiing them current.
Are you in 8bpp? There are few 3D accelerators for PCs that support acceleration in 8bpp.
The pixel format selects hardware acceleration. Pay attention to the flags GENERIC_FORMAT and GENERIC_ACCELERATED. You want both of them on if you're using a 3D-DDI or an MCD and neither on if you are using an ICD. You may have to iterate using DescribePixelFormat() instead of only using ChoosePixelFormat().
In Windows 98, Microsoft decided to disable OpenGL hardware acceleration when multiple monitors are enabled. In Windows NT 4.0, some drivers support multiple monitors when using identical (or nearly identical) cards. I don't believe multiple monitors and hardware accelerated OpenGL work with different types of cards. I don't know the story with Windows 2000, but it's likely to be similar to Windows NT 4.0.
Your view class should have an OnEraseBkgnd() event handler. You can eliminate flashing by overriding this function and returning TRUE. This tells Windows that you've cleared the window. Of course, you didn't really clear the window. However, overriding the function keeps Microsoft from trying to do it for you, and should prevent flashing.
This is a problem with MS OpenGL. The bug is in the generic code, or possibly in MS Windows itself, because it occurs even with pure software rendering.
Microsoft's product support page contains information on this issue: Clipping Problems with Generic Implementation of OpenGL for Windows 2000
To work around the bug, try one of these two methods:
- Create the OpenGL drawing window, but don't make it visible immediately. Get the screen size and set the window's size to be the same as the screen. Now set the pixel format and create the HGLRC. Set the window's size back to whatever it should be and make the window visible. This hack is invisible to the user, but doesn't always work.
- When the window is resized larger, destroy and re-create the window. This is really ugly and visible to the user, but it seems to always work.
According to OpenGL Reference Manual editor Dave Shreiner:
"Unless there's an absolutely compelling reason ... I really would suggest using opengl32.dll, and letting the old opengl.dll thing die.
"opengl.dll comes from the now totally unsupported OpenGL for Windows release of OpenGL for Microsoft Windows by SGI. We stopped supporting that release over two years -- like no one ever touches the code. ...
"Now, why use opengl32.dll? For the most part, SGI provides Microsoft with the ICD kit, sample drivers, and software OpenGL implementation that you find there. Its really the same code base (with fixes and new features) as the opengl.dll, its only that we got Microsoft to ship and support it (in a manner of speaking)."
You need to be familiar with both OpenGL and the Microsoft Foundation Class (MFC). An online MFC reference is available, the MFC FAQ. You don't need to be an MFC guru to add OpenGL to an MFC application. Familiarity with C++ can make mastering MFC easier, and the more you know about MFC, the more you can concentrate on your OpenGL code. If you have only a rudimentary knowledge of MFC, look at the downloadable source code example below, and look at the steps necessary to recreate it.
Joel Parris' OpenGL/MFC web site contains lots of useful information.
Samuel Paik's repository of links to OpenGL information on Microsoft Web sites also has information on using OpenGL and MFC.
Here's a list of books that might be helpful.
OpenGL Programming for Windows 95 and Windows NT, by Ron Fosner. This is also known as the white book. It contains good information on using OpenGL in Microsoft Windows. Much of the information in it can be found on the MSDN Web site, but the book presents the information in a more logical and easily digestable format, and comes with good demos.
Opengl Superbible: The Complete Guide to Opengl Programming for Windows NT and Windows 95, by Richard S. Wright and Michael Sweet. This book contains a chapter on OpenGL and MFC.
MFC Programming with Visual C++ 6 Unleashed, by David White, et al. The book contains a short chapter on OpenGL and focuses more on DirectX.
To add OpenGL to an MFC application, you need to do at least the following:
- Add glu32.lib opengl32.lib to the list of object/library modules to link with.
- When your View class's OnInitialUpdate() function is called, set the pixel format and create a rendering context as you would for a Win32 application.
- Render your OpenGL scene when the View needs to be updated, or add a Run message handler to your Application class that updates when idle.
You can render OpenGL into any CWnd object, including frame windows, dialog boxes, and controls.
Download this example, which demonstrates OpenGL in a CStatic form control. This code uses a CGlView class that takes any CWnd as a parameter to its constructor. Rather than create a View derived from a CFormView, you could just as easily create an SDI application, and pass "this" (an instantiation of a CView) as a parameter to the constructor. Follow these steps to recreate this sample code using Microsoft Visual C++ v6.0:
- If you haven't done so already, download the example. You'll need to borrow code from it in the steps that follow.
- Create an MFC application using the AppWizard. Use defaults, except derive your View class from a CFormView. The project will open in the resource editor. Add a FORM control to the open CFormView. Call it IDC_OPENGLWIN.
- Select Project->Settings...->Link, and add glu32.lib opengl32.lib to the list of objects/library modules.
- Select Project->Add To Peoject->Files... and add the CGlView.cpp OpenGL view class source file from the above example code.
- From the class view, right click your application's View class and select Add Member Variable... Set the variable type to CGlView *, the name to m_pclGLView, and the access to Private.
- In your application's View class header file, add #include "CGlView.h" just before the class definition.
- Find the global declaration of "theApp". Immediately after this declaration, add two new global variables:
CGlView *g_pclGLView = NULL; MSG msg;
- In the wizard bar, set the application's View class, set the filter to All Class Members, and select the OnInitialUpdate member function.
- For the CGlView class to work, it needs a CWnd to initialize OpenGL for that window. For this example, our CWnd is the CStatic FORM control we added in step 1. After the existing code in this function, add the following:
CStatic pclStatic = (CStatic *)GetDlgItem(IDC_OPENGLWIN); m_pclGLView = new CGlView(pclStatic);
- Open the class wizard with View->ClassWizard. From the message map tab, select your project's Application class. Add a function handler for the Run message. Replace the generated code with the Run message handler from the downloaded example.
Nothing in MFC guarantees a slow-running OpenGL application. However, some poorly written MFC applications might run slowly. This is a possibility in any development environment and is not specific to OpenGL. Here are some things to look out for:
- Build the application as Release instead of Debug. Disable the TRACE debugging feature.
- Avoid MFC classes such as CArray, CMap, and CList that perform inefficient data copies.
- You may be able to improve performance by avoiding the WM_PAINT message. See the question above for example source that does this.
- MFC classes are general purpose. For maximum performance, write a tuned implementation of an MFC class.
- Use standard efficient programming techniques such as avoiding redundant calls, etc.
Alan Oursland, Using OpenGL in Visual C++ Version 4.x, DevCentral Learning Center, http://devcentral.iftech.com/learning/tutorials/mfc-win32/opengl/. This is good but dated. It will get you started with a SDI MFC OpenGL application.
Mahesh Venkitachalam, OpenGL Code, http://home.att.net/~bighesh/ogl.html. Mahesh presents OpenGL in a no application wizard, minimal MFC program along with some OpenGL techniques.
Roman Podobedov, Skeleton of OpenGL program for Windows (MFC). http://madli.ut.ee/~romka/opengl/demos/win32_eng.htm. This is a minimal MFC program with no controls or application wizard.
Paul Martz, Generating Random Fractal Terrain. http://www.gameprogrammer.com/fractal.html. This is a good example of the MFC SDI approach. However, the primary focus of the example is terrain, to which OpenGL and MFC take a back seat.
 Pierre Alliez, Starting OpenGL in a Dialog. http://codeguru.earthweb.com/opengl/texture_mapping.shtml.
Pierre Alliez, Starting Rendering Modes. http://www.codeguru.com/opengl/start.shtml. This is a splitter window example.
Pierre Alliez, How to snap an OpenGL client and send it to the clipboard, http://codeguru.earthweb.com/opengl/snap.shtml.
Pierre Alliez, A small VRML viewer using OpenGL and MFC. http://www.codeproject.com/opengl/wrl_viewer.asp.
Uwe Kotyczka, OpenGLSample.zip, http://www.virtue.nu/kotyczka/opengl_en.html. This rather large and impressive MFC contribution demonstrates, multiple OpenGL views, rubber banding, color ramp, mouse trackball type control, OpenGL printing, etc., in a MFC MDI and SDI framework. This was built with VC++ 6.0 (SP4) .
On the Win32 platform a number of platform specific function calls are duplicated in the OpenGL ICD mechanism and the GDI. This may cause confusion as they appear to be functionally identical, the only difference being whether wgl precedes the rest of the function name. To ensure correct operation of OpenGL use ChoosePixelformat, DescribePixelformat, GetPixelformat, SetPixelformat, and SwapBuffers, instead of the wgl equivalents, wglChoosePixelformat, wglDescribePixelformat, wglGetPixelformat, wglSetPixelformat, and wglSwapBuffers. In all other cases use the wgl function where available. Using the five wgl functions is only of interest to developers run-time linking to an OpenGL driver. Not using the functions as described may result in a black OpenGL window, or a correctly functioning application in Windows 9x that produces a black OpenGL window on Windows NT/2000.
5.200 Why does my code produce a black screen under Windows NT or 2000 but run fine under 9x?
Incorrect mixing of GDI and wgl functions may result in OpenGL functioning correctly under Windows 95 and not functioning correctly under Windows NT/2000. Incorrect functioning will result in a black OpenGL window under Windows NT/2000.
5.210 How do I properly use WGL functions?
As described in section 5.190, ChoosePixelformat, DescribePixelformat, GetPixelformat, SetPixelformat, and SwapBuffers, are used when going through the OpenGL ICD mechanism. wglChoosePixelformat, wglDescribePixelformat, wglGetPixelformat, wglSetPixelformat, and wglSwapBuffers, are used when run-time linking to the OpenGL driver. The wgl functions specific to outline and bitmap fonts require special attention only by developers linking directly to the OpenGL driver. All other developers should use wglUseFontBitmaps and wglUseFontOutlines as per Microsoft platform documentation. wglUseFontBitmaps and wglUseFontOutlines come in two flavours, depending on whether a unicode or non-unicode platform is being targeted. When run-time linking use wglUseFontBitmapsW and wglUseFontOutlinesW for unicode platforms. wglUseFontBitmapsA and wglUseFontOutlinesA for non-unicode platforms. All other wgl functions may be used freely as per Microsoft platform documentation.
Charles E. Hardwidge has tutorial articles and examples for download that address these issues. The idea is to use WGL, GDI, and OpenGL functions such that the Microsoft OpenGL ICD mechanism isn't assumed.