The OpenGL SuperBible
The Second Coming of the Graphics Pipeline

 

 

 

I wrote this article in 1997 just before the announcements from Microsoft and SGI about their new cooperation on the OpenGL ICD, and Fahrenheit. It was accepted for publication in NT Developer for the September issue, and I even got paid for it. However, the parent company shut down the magazine and this first of two parts never saw the light of day. The second part of the article is "OpenGL Metafiles and Printing". I hope you find them useful!

 

OpenGL, Workstation Graphics does Windows

Trying to make an informed decision about which 3D API to use? Here’s a brief history lesson and where the current state of the art stands.

Last Christmas, while visiting back home in Kentucky, a young cousin planning to enter college the next year came to me for advice as to his upcoming career in "computers". It was the standard question, "How many computer languages do you know?", followed by the ever faithful, "Which programming language is the best one?" That is to say, "which one will get me a good job where I’ll make lots of money!" Sparing him an in depth comparison of the relative merits of C/C++, Java, Visual Basic and the ilk, I tried to tell him something that would really make a difference in his future career; "What programming language you master or how many you know is not nearly as important as the API’s and tools you know".

Sparing you the tedious definition of what an API is, suffice it to say that your mastery of developer tools and libraries are what get you paid, not necessarily knowing the difference between binary and unary operators. No, I’m not minimizing the importance of knowing your primary language of choice well (you’d better know the difference!), but it does you little good to be the worlds foremost expert in C++ if you don’t know how to debug a DLL under Windows (assuming your developing a Windows DLL<g>). As a productivity issue, almost no programmer takes on a new project and writes all of the code from scratch. Even if you just use the C runtime, you are still making use of prepackaged functionality that was put together by someone else.

API’s are what make our lives easier, they make it possible for only a page of code to retrieve a file over the Internet, to easily create standard Windows dialogs and OLE enabled applications, get data from any number of SQL databases, etc. Standard API’s are good. They are good for you, they are good for the industry at large. Standards such as SQL have enabled thousands of applications on many different platforms to share code, data, and functionality. They’ve also saved programmers tens of thousands of hours of development time, enabled code reuse, reduced bugs and support costs, … I think you’ve got the picture.

There are "standard" API’s and tool languages for a variety of development tasks, SQL for database manipulation, Win32 for Windows development, Java and HTML for Internet and Web development, etc. A similar API exists for programs that have the need for functionality that includes 3D graphics. This API is OpenGL. Despite what you may have read on the back of a cereal box, supermarket tabloids, or Microsoft’s marketing literature (all equally credible sources of information), OpenGL is a low-level, real-time 3D graphics API. By low-level we mean that OpenGL gives us a very fine degree of control as to how rendering takes place, and by real-time graphics we mean interactive 3D graphics as opposed to graphics that render over a long weekend or during your lunch break. High-end (re: expensive) applications (such as CAD, scientific visualization and simulation) have an extreme need for real-time performance, and OpenGL is often the API of choice for developing these kinds of applications.

OpenGL in essence personifies real-time 3D graphics. It is an uninformed mistake to think that high-end applications are supposed or allowed to be slow applications. If that were true, companies such as Silicon Graphics would have long been out of business. Ask a CAD draftsman if rendering speed has any effect on his productivity. OpenGL is often mistakenly referred to as a high-level 3D API because of its use in high-end 3D applications. Another strength of OpenGL, visual fidelity, is also often confused with performance issues. You’ll see OpenGL referred to as a "precise" rendering API, that should only be used when you have "exacting" rendering needs where performance isn’t a consideration. That’s one way to put it. It would be just as unfair to ask if you want your 3D scenes to look somewhat realistic, or like cartoons. If you really do need ultra realistic 3D scenes, you’d use a ray tracer, not a real-time API such as OpenGL.

Another strength (and sometimes disadvantage) of OpenGL as a 3D rendering API is that it is a very general purpose rendering API. The advantage is that you can accomplish nearly any rendering task you can imagine with OpenGL. Being a low-level API, it also does not impose a great deal of "policy" upon the programmer. This means you are able to switch rendering modes and states on the fly, do all sorts of multipass techniques for a variety of special effects, and most important the API does not make any assumptions about how rendering should occur. This gives the programmer the ultimate creative freedom. This does not come free however. The great flexibility of OpenGL can make it very difficult to optimize implementations. The concept of code paths is used frequently to describe the various modes and states in OpenGL that may be on or off during rendering. For instance someone’s hardware may do very fast line drawing, but not when anitialiasing is turned on.

Being a low-level API, OpenGL does not include a great deal of tools or high level constructs (such as loading and displaying a graphics file). It is sometimes compared to assembly language in the amount of work that is required of the programmer. I prefer to think of the comparison being more like using the Win32 API when you could be using MFC; there are advantages to both approaches. This brings us to another important characteristic of OpenGL. OpenGL is an immediate mode graphics API. This means that the programmer issues a series of commands that have an immediate effect on the rendering process. By contrast, a retained mode API is more descriptive, where the programmer completely describes the end result to the API, and only then is the information processed to create an image. Retained mode API’s typically enforce a lot of policy. Fortunately, retained mode API’s are usually built on top of immediate mode API’s, and a well designed retained mode library will still allow ready access to the lower level rendering API underneath it.

To make an analogy to your everyday programming, Retained Mode programming is much like designing a dialog box with a dialog editor, quick and easy; just concentrate on where you want your controls and graphics. More cutting edge interfaces however come from painstakingly assembling your custom controls and customized painting logic. It’s more work, but sometimes the effort is worth what your trying to achieve.

Where did it come from?

OpenGL began life as IRIS GL at Silicon Graphics. IRIS was the name of SGI’s premier graphics workstations, and IRIS GL was the "Graphics Language" used to create real-time graphics on these machines. IRIS GL was proprietary to SGI’s hardware, and not an "open" standard.

At some point, SGI realized that although they made the worlds fastest 3D computers, not everyone could afford them, much less the specialized skill required to program them. The 3D market simply was not as large as it could be. If they could provide a migration path from their low end to higher end machines, or even to and from competitor’s machines, they would actually increase the desirability of their machines as well as seed the 3D industry at large. This is why OpenGL was born. SGI would provide a solid and portable 3D graphics API that would protect developers investments in software, allow content to be deployed on lower end machines, and allow applications to scale upwards in performance by upgrading hardware.

This was a good idea that would grow the total 3D market (and correspondingly SGI's share) and other vendors, hardware and software, cooperated and joined Silicon Graphics to form the OpenGL Architecture Review Board (OpenGL ARB as it’s now commonly called) in 1991. The founding companies of the ARB were; SGI, Microsoft, IBM, DEC, and Intel. Today nine companies have voting seats on the ARB, and several more attend the quarterly meetings regularly to provide input and guidance to the evolution of OpenGL.

OpenGL Does Windows

In 1992 Microsoft announced Windows NT, and the Win32 API. Microsoft wanted Windows NT to be the next generation workstation operating system that would replace UNIX for Engineering and Scientific applications, and for servers and networking applications too. A key to getting some UNIX vendors to port their applications to NT would be support for the new standard in 3D graphics, OpenGL.

Microsoft pledged support for OpenGL at the July, 1992 Win32 developers conference, concurrently with the release of the OpenGL Specification, 1.0. However, it wasn’t until the release of NT 3.5 two years later that OpenGL was actually implemented on Windows. At last, workstation graphics on the Wintel platform…. well, sort of.

There was a slight problem with Microsoft’s implementation of OpenGL. It was slow - it was dog slow. One of the fastest Windows machines you could buy at the time was a 486/66, and no one at Microsoft thought anyone would really be able to deliver high-end number smashing, 3D dyna-whopp’n applications on this platform, at least not without graphics hardware designed for OpenGL. At this time, vendors weren’t exactly lining up down the boulevard to build OpenGL hardware for NT either. This meant that applications written using OpenGL would be using the software implementation (called the Generic implementation) of OpenGL that came with Windows, and that was just plain too slow for anything other than a few marginally interesting screen savers.

The performance disparity between 3D programs written with OpenGL on Windows NT and other software 3D renderers was enormous. Why? Two reasons. The first is that as said previously, Microsoft didn’t expect anyone to seriously deliver any 3D applications that only used the software version of OpenGL. They took, what we call the "Sample Implementation" from SGI and ported it from UNIX to Win32 making next to no performance optimizations. The Sample Implementation is written in C and is designed to make it clear as to the intent of how the API functions. There are no performance optimizations because each platform’s performance characteristics differ. You simply cannot write highly tuned software in C that is completely optimized for every platform on which it is ported. Consider too that much of the OpenGL pipeline was architected to be implemented directly in hardware, not as software being interpreted by a CPU.

The second reason is the somewhat lack luster floating point performance of the Intel 486 CPU. OpenGL is extremely floating point intensive. Other 3D API’s of the time used integer math internally to get better performance at the sacrifice of rendering quality. It wasn’t until the Pentium processor and beyond where some floating point operations can actually be faster than some integer operations that high fidelity 3D graphics could be done in software. At least as long as you weren’t using Microsoft's OpenGL for Windows.

Enter Direct X

Meanwhile, back at the bat cave…. Microsoft was doing everything they could to get game developers to abandon DOS and build native Windows games. Not just solitaire and minesweeper mind you, but real blood spurting, engine revving, alien blasting computer games. They tried a variety of strategies including the ill fated WinG API to make raster graphics as fast as possible under Windows. Out of chaos, some order did emerge in the form of Direct X.

Direct X is actually a pretty good family of game development API’s for Windows, as long as you don’t mind Microsoft’s COM (Component Object Model) interface. Direct Draw gives you fast raster graphics, Direct Sound for low level and quick access to sound hardware, Direct Play and Lobby give you lots of great pre-built Internet functionality, etc. Then of course, there’s Direct 3D for direct low level access to 3D graphics hardware.

It’s ironic that Microsoft needed a "direct path to 3D hardware", when OpenGL is defined as "a software interface to graphics hardware". In essence OpenGL was intended to be nothing more than a thin binding layer that would let software applications directly access the underlying 3D hardware.

The sudden popularity of 3D games such as Doom dramatically highlighted the utility of 3D graphics for computer arcade-like games. Microsoft suddenly found itself needing a 3D graphics software solution for its Direct X family of API's that was fast enough for games, and they needed it yesterday. OpenGL is perfectly suitable for games as far as an API is concerned, especially since it gives the developer so much freedom in how they approach their rendering and optimizations. The problem was that up to this time no one had spent any time tuning the software implementation of OpenGL on the Wintel platform.

Hind sight is 20X20, so I won’t berate Microsoft to badly for doing next what any sane business would have done. Faced with the impossible task of throwing several man years into maturing their OpenGL implementation in only a few months time, they decided to buy someone else’s 3D game technology; RenderMorphics. Essentially they purchased a very fast Retained Mode library and tore it apart to expose the Immediate Mode API that lay beneath.

This is where Microsoft got one foot stuck in the muck, and another one stuck in the mire. Now they had two 3D API stories to tell. Simple, Direct 3D is for "real-time" graphics and games, OpenGL is for high-end applications with "precise" rendering needs. To the established 3D community, it was like telling Dale Ernhardt that VW beetles were for NASCAR racing (based on what they’d seen in Herbie the Love Bug), and Porche 911’s were for taking the family to church on Sunday.

But then everyone else knew how slow OpenGL was, they’d seen the screen savers, they’d tried some samples from books and magazine articles. Obviously OpenGL was a slow API. The Microsoft Direct 3D samples and screen savers seemed very fast running on ordinary 2D hardware, an 3D OpenGL hardware cost thousands of dollars. The conclusion seemed obvious. Microsoft's "official" position was that Direct 3D was for real-time and Games, and OpenGL was for "high-end" stuff.

Silicon Graphics, naturally wouldn't stand for this. Arguments about OpenGL's superiority to Direct 3D seemed somewhat academic in the face of the seemingly obvious facts. So, in early 1996 SGI decided to prove to the world that OpenGL didn't have to be any slower for any reason than Direct 3D. The SGI OpenGL for Windows implementation was born. Originally called Cosmo GL, they demonstrated it along side some Microsoft D3D demos at the 1996 SIGGRAPH conference. It turns out that D3D programs ported to SGI's version of OpenGL ran about as fast or often a little faster than D3D. They also took less than half the code to implement. So much for Microsoft's "real-time" solution.

Microsoft wasn't sitting on it's hands all this time either. By the time Microsoft delivered OpenGL 1.1 for Windows NT 4.0 and Windows 95, they had improved the software performance considerably. Some operations were four or five times faster, and some even an order of magnitude. By the time all was said and done, Microsoft's software OpenGL was pretty fast, and often faster than D3D in full color mode, with SGI's OpenGL being slightly faster than D3D in color index mode (palletized display modes). Whatever your needs, OpenGL’s "precise" rendering capabilities were available, and just as fast or faster than Microsoft’s "other" real time API, D3D.

The brutal truth of the matter however was that neither Direct 3D or SGI OpenGL for Windows was fast enough for good (fast) 3D games. Game developers were rolling their own specialized 3D engines that were getting end-users 20 frames a second or better when playing their games. Being more generalized neither OpenGL or D3D could cut the mustard. At least until hardware vendors started putting out consumer 3D hardware.

Slowly but surely, 3D hardware for the masses crept onto the scene. At first most boards offered very little in the way of real 3D acceleration, and nearly all supported Direct 3D first. Today the story is changing with nearly every 3D hardware vendor pledging support for both OpenGL and Direct 3D on their hardware. It would appear that rumors of OpenGL's death have been greatly exaggerated! Microsoft still maintains that OpenGL is for professional applications in the NT space, and that D3D is for the consumer segments (games). Unfortunately (for Microsoft), a well written OpenGL driver should perform no slower than a D3D driver on the same hardware. In addition, as they evolve the D3D feature set to look more and more like OpenGL, they are making it even easier to build hardware that serves both the D3D and OpenGL programming communities well. The boon to NT developers is that decent OpenGL hardware acceleration is going to be available for low cost on NT workstations.

OpenGL Driver Models

There are two models hardware vendors can follow to build OpenGL drivers for Windows. The first called the Mini-Client Driver (or MCD) is probably the fastest and easiest way to creating an OpenGL driver for your hardware. The second is the Installable Client Driver (or ICD), is considerably more work, but offers better performance and more flexibility.

The MCD driver is primarily for rasterization hardware (hardware that doesn't do lighting and coordinate transformations). When you write an MCD driver it is incorporated into your 2D GDI display driver. What you implement are a series of callbacks that the Microsoft OpenGL implementation calls in your driver. These callbacks perform functions such as "draw a triangle at these screen coordinates". If you don't implement a certain feature in your driver, you return an error code and the Microsoft implementation does the rendering for you. There are three advantages to this approach. First, any feature you don't implement is still present in the API and can be used by OpenGL applications. Second, you get to take advantage of Microsoft's work in tuning their OpenGL implementation. The third advantage is that you aren't required to do an entire OpenGL implementation; whatever functionality your hardware supports can be exported, and vola! you accelerate at least some if not a lot of OpenGL functionality.

The ICD is a more substantial commitment. With this driver model, the OpenGL interface to your hardware is also integrated directly into your 2D GDI driver, but now you are responsible for the entire OpenGL implementation. There are no neat callbacks and you can't rely on Microsoft's OpenGL tuning work. When you get an ICD kit from Microsoft, you get SGI's sample implementation ported to Windows in an ICD form, without any software performance optimizations. If there is a feature in OpenGL that your hardware does not implement, you have to provide an optimized software solution. This can take many man years to tune and optimize for your hardware. Generally, the ICD approach was only taken by vendors who were very serious about OpenGL (3D Labs and Intergraph for example) and had the time and money to put into a good optimized ICD.

For months Microsoft recommended that hardware vendors just entering the OpenGL market first implement an MCD to get up and going, then they would have time to spend on developing and fine tuning their ICD drivers. This is just what most major 3D hardware vendors did, and most had working MCD's up and running at least in alpha form early this year (1997). Getting an MCD driver up and running in only two weeks was not unheard of. A few months of tuning, and a decent OpenGL driver could be had quite easily. This Christmas (1997) would have seen a bonanza of cheap OpenGL accelerating hardware had things gone as planed. Microsoft didn't want OpenGL competing with Direct 3D in the consumer space however, and a good number of game developers were sitting up and paying attention when John Carmack announced that ID software would be using OpenGL instead of Direct 3D for all future game development. For various "official" reasons that I won’t go into, Microsoft canceled MCD driver support for Windows 95 and Windows 98 after first sending many IHV’s down the MCD road. Fortunately, MCD code for Windows 95 was easily ported to NT and a good number of these drivers have survived as OpenGL implementations on Windows NT.

This looked like bad news for software developers developing OpenGL applications, unless they were targeting NT only. However, "from the ashes of disaster, grow the roses of success"! SGI in an effort to keep OpenGL universal (which is what all the ARB members are supposed to do, including Microsoft) contributed the source for SGI’s OpenGL for Windows to a new ICD driver kit. They are currently working with several hardware vendors on a new DDK that will make writing ICD's for NT or 95 nearly as simple as providing an MCD under NT. Instead of the Sample Implementation, their kit is based on their very fast software implementation tuned specifically for the Intel processors. In fact the latest code from SGI takes advantage of the MMX instruction set for speeding up rasterization. For some applications, it can speed up OpenGL performance by almost an order of magnitude. The end result will likely be ICD OpenGL implementations that will perform better than most MCD implementations would have. Open standards live on!

OpenGL on NT

All said and done, OpenGL is still the API of choice for 3D (technical) graphics development on Windows NT (this is still Microsoft's official stand too). Microsoft naturally, will evolve Direct 3D to the point in a few years that it will have many of the advanced features of OpenGL, but for the foreseeable future OpenGL is here to stay, and already has many of the advanced rendering features required by the workstation market. In fact, there are some features of OpenGL that are present on Windows NT that won't ever be available on Windows 95 or Windows 98 that are very useful.

One of the nicest features is the ability to do OpenGL rendering to a printer device context. A full color OpenGL scene can be rendered to a 9-pin dot matrix printer, and you'll actually get something that looks like the original image (albeit grey scale, and dithered to smithereens!). You can also use OpenGL to render into and play back 3D commands from an enhanced metafile. Persistent OpenGL scenes can be used for a variety of purposes including 3D clip art, or thumbnails of 3D objects in a database.

Next month I'll go into greater detail about these NT only features, and present some program samples for printing your OpenGL graphics, and for saving them and playing them back from metafiles. If you want more information on programming with OpenGL, visit the official OpenGL web site at www.opengl.org. This site contains pointers to information on books, magazine articles, and scores of sample OpenGL programs.