Issue 5-13, March 29, 2000

Be Engineering Insights: The World of OpenGL® After BeOS 5

By R. Jason Sams

As many of you may have noticed, there is no hardware acceleration for OpenGL in BeOS 5. One reason for this is that we were in the middle of a major re-write of OpenGL which would not support hardware acceleration of BGLView. Another reason is that there were a number of bugs in the previous drivers that prevented other parts of the Be API from functioning normally. As a result, we didn't ship a new version of experimental drivers with BeOS 5, knowing that we would be able to provide much better drivers based on the new implementation shortly after BeOS 5 shipped.

The latest changes dramatically improve both performance and stability with hardware acceleration. The triangle throughput and texture upload speeds have been greatly enhanced and multitexture support has been added. Device enumeration now allows the application to properly determine if it is using a full screen device, eliminating the annoying problem of apps taking over the entire screen.

What's New in the Rewrite?

  1. The geometry pipeline has been rewritten to take full advantage of SIMD processors. This results in large performance improvements on SIMD enabled CPUs such as the PIII. We also improved the scalar pipeline that enhances performance on the Celeron and PII line.

  2. There's a new OS-specific interface layer for OpenGL. Previously, a number of issues limited our ability to provide proper (i.e., good) hardware support within the constraints of the existing BGLView API. To fix these and add a number of new features we created a new API. BDirectGLWindow.

  3. Multiple monitors and hardware devices are supported. It's now possible to render to multiple monitors and hardware cards using OpenGL. Monitors other than your primary display are treated as full screen-only devices.

  4. There's a new locking model. A limitation of BGLView was that each application had a global GL lock that only allowed one thread to render at a given time, even if the rendering was to multiple windows. This limitation has been lifted, allowing apps to better leverage multiple CPUs.

  5. The primary display gets proper full screen support. This allows applications to resize the display and change color depth and still be cleaned up safely should they crash. Previously, applications needed to use the BScreen API that was not safe.


One of the biggest changes between the old and new versions is the introduction of a completely new locking model for OpenGL. The purpose of locking in OpenGL is to associate a context with a window. This is necessary because OpenGL is a C-based API with no explicit connection between a function and the rendering context (Window). The old mechanism handled this by requiring an application to grab a global lock for a window. Once the lock was acquired, all calls to the C API would go to the locked window. The major problem with this is that when you have multiple CPUs and Windows, since the lock is global, you effectively force single threading across windows.

The new locking mechanism now locks the drawing to a window to a specific thread. This is done through three functions in BDirectGLWindow:

  • MakeCurrent() Makes the current thread the drawing thread for the window. If another thread is already current for the window this function will block until the previous owner releases it.

  • ReleaseCurrent() Release the current thread. This allows other threads to grab the context.

  • YieldCurrent() Release and reacquire the context. This is exactly the same as calling ReleaseCurrent() followed by MakeCurrent(). The purpose is to provide a very low cost method to allow others to grab the context if necessary. If no other process is blocked on the context, this will just return without the release/acquire overhead.

Holding a lock for too long blocks other OS functionality, as this lock will block a DirectConnected call and some other internal OpenGL functionality. As a result, an application should release the context before beginning any long non-drawing functions and should call Yield within your rendering loop.

Device Enumeration

The second major new feature is device enumeration and multidevice support. Devices are divided into two categories. Primary devices are those managed by the App server. Rendering in a window is supported on these devices. Secondary devices are full screen-only devices. The functions that follow support this mechanism:

void EnumerateDevices(
        uint32 monitor_id,
        uint32 color,
        uint32 depth,
        uint32 stencil,
        uint32 accum)

This function provides a list of devices that meet the requirements specified. The value of monitor_id is BGL_MONITOR_PRIMARY, to return devices that can render to the standard desktop. BGL_MONITOR_OTHER returns a list of non-desktop monitors. You can also specify a specific monitor. The other parameters will specify the application's minimum requirements for buffer depths. The most common parameters to use will be BGL_NONE, BGL_ANY, BGL_FASTEST, BGL_HIGH_QUALITY. You can specify a specific buffer depth, but in most cases you'll want to use one of the above.

virtual void DeviceInfo(
        uint32 device_id,
        unit32 monitor_id,
        const char *name,
        bool depth,
        bool stencil,
        bool accum)

A call to EnumerateDevices generates one or more calls to this function to describe the devices. The application should record the device_id for devices the application may wish to use. The name will contain a human readable description of the device. The three booleans indicate whether the device can support some form of buffer of the specified type.

virtual void videoModeInfo(
        uint32 mode_id,
        uint32 width,
        uint32 height,
        uint32 color,
        uint32 depth,
        uint32 stencil,
        uint32 accum )

For each call to DeviceInfo, one or more calls to VideoModeInfo will follow to describe the abilities of the device. If width is zero the device is a windowed device. width and height that contain a non-zero value describe a full screen mode. The color, depth, stencil, and accum parameters will contain the specific depths of each buffer.

Using the information obtained from the above calls you can initialize the OpenGL window and context by calling InitializeGL.

status_t InitializeGL(
        uint32 device_id,
        uint32 color,
        uint32 depth,
        uint32 stencil,
        uint32 accum )

The device_id is one of the ids returned in one of the DeviceInfo calls. The other buffer information can be any of the four standard defines (none, any, fastest, high_quality) or the info from VideoModeInfo. After the call to InitializeGL, you are free to call MakeCurrent and begin rendering.


Destroys the OpenGL context and releases any resources it was using.

Window Maintenance Routines

By default, the OpenGL rendering area consumes the entire window. It's illegal to draw into the area of a window owned by OpenGL using any means other than the GL API. The results of doing so are not defined. The same applies to reading pixels back from the window. The routines described below are provided to reserve a portion of the window for other drawing.

virtual BRect UpdateGLRect( BRect window_rect )

This function should be overloaded if the application desires to restrict drawing to a portion of the window. It must be DirectConnected safe, meaning that it cannot call normal App server routines. The full window rect is passed in as window_rect and the function should return the area that OpenGL will use for its drawing.

void SetGLRect()

Trigger a call to UpdateGLRect to set the GL drawing area.

void SetFullScreen( bool full_screen)

Toggles the window between full screen and windowed modes. Setting a window to full screen changes the video mode to the nearest supported full screen resolution to the current window size. Therefore, to set the video mode to 800x600 you would set the window size to 800x600 and the call SetFullScreen( true ) to change the video mode.

Note: This function actually resides in DirectWindow, but the functionality changes slightly when a GL context is active.

Be Engineering Insights: to Kernel Debugging Land (Again...)

By Brian Swetland

Not long ago, Dominic wrote an article about the kernel debugger Be Engineering Insights: Welcome to Kernel Debugging Land

It's about time to talk about such things again.

BeOS 5 brings a number of changes to kernel debugging. Some of them are quite visible, others are a little more subtle. Let's take a look at what's new:

Invoking the Kernel Debugger

We've seen a number of bug reports along the lines of "ALT-PrintScreen" freezes BeOS. What's actually happened is that you've entered the kernel debugger. And if you didn't have some type of serial terminal connected to your first serial port (at 19200 bps, 8 data bits, no parity, 1 stop bit, aka 19200N81), you might have been confused by the lack of response. We've listened! Starting with BeOS 5, you'll need to hold down ALT-PrintScreen and then tap the "d" key. This should prevent people who are trying to save a screenshot from being accidentally teleported to the strange and wonderful habitat of the kernel debugger.

On-Console Debugging

Of course, sometimes bad things happen and the kernel crashes. Previously, this would look as if the machine had just stopped. In BeOS 5, the app_server is kind enough to let the kernel know where screen memory lives, so the kernel debugger can display information on-screen when something goes wrong.

By default, if you invoke the debugger or the system crashes, you'll see your screen partially overwritten with a friendly message from the kernel debugger that includes processor registers, a stack crawl, some information about what team and thread were running, etc. Right now this only happens on x86. If you're a frequent user of the kernel debugger you may prefer the serial debug version. If you have a line in /boot/home/config/settings/kernel/drivers/kernel that looks like

bluescreen false

you won't get the on-screen debugger. The display is actually black text on a white background, even though the option is called "bluescreen".

If you're in the on-screen debugger, input is accepted from the PS2 or AT keyboard. The USB stack is far, far too complex to operate inside the kernel debugger. You can type "set serial" at the prompt to cause input to be taken from the serial port instead.

If things are scrolling off-screen (e.g., the ps command), you may want to do something like set paginate on and set pagesize 40.

In the event of a crash or debugger request, you'll see some information dumped immediately. The following is an example:

kernel debugger: Welcome to Kernel Debugging Land...
eax 600cf0b0  ebp fc003a28  cs 0008 | area 00393058  (kb_mouse_seg0)
ebx 600d056c  esp fc003a08  ss 0010 | addr 600cb000  size 00005000
ecx fffffedf  edi fc003a1b  ds 0010 |
edx 00000060  esi fffffee0  es 0010 | Thread: idle thread 1
eip 600cdee0 flag 00000013  fs 0000 | Team:  kernel_team
trap ffffffff  err 00000000  gs 0000 | Stack Trace follows:

00000000  600cdee0  _end+1f31c
fc003a28  001309ca  general_io_interrupt_handler+00ca
fc003a60  0016dde4  done_user_hook1+0010
fc003cd8  0016a0f9  ---- iframe ----
fc003cd8  0013974e  null_thread+000a
fc003ce0  0012ecb8  sysinit1_after_stack_switch+019c


Kernel Debugger Modules

The kernel debugger provides many commands by default (type help at the prompt to see a pretty extensive list). This code and related data takes up memory that is locked and not paged. In low-memory conditions (perhaps on some form of appliance...) you might want to avoid using memory for debugging code in the final shipping environment. Now it's as easy as removing the modules you don't want.

/system/add-ons/kernel/debugger contains several modules:

disasm (26k)the disassembler (provides "dis" command, etc)
gdb-stub (7k)allows for remote GDB debugging (experimental)
i586 (5k)some x86 specific extensions (machine specific regs, fp regs, single step, and runto support)
internals (48k)debugging commands for fsil, devfs, threads, modules, ports, elfloader, cache and vm
parser (7k)allows expressions to be entered in the debugger
symbols (5k + 200k)loads the kernel symbols and allows load_driver_symbols() to work, ads "lkup"

If you want to write your own debugger module (to add some neat new functionality not previously available), it's pretty easy:

#include <OS.h>
#include <module.h>

static int do_test(int argc, char **argv)
    int i;

    kprintf("test command: ");
    for(i=0;i<argc;i++) kprintf("%s ",argv[i])

    return 0;

static status_t std_ops(int32 op, ...)
    if(op == B_MODULE_INIT) {
        add_debugger_command("test", do_test);
    } else {
        return B_ERROR;

static module_info test_info =
    { "debugger/test/v1", 0, &std_ops };

module_info *modules[] = { &test_info, NULL };

Yeah, right!

By Jean-Louis Gassée

That's no doubt what many of our would be downloaders will say when they hear about our last minute misadventure. At 4:45 a.m. PST, we lost our Net connection. On the very morning of the release of BeOS 5, users and mirror sites could not get what we promised to deliver this Tuesday, March 28th—access to the free, Personal Edition. The cyber highway isn't the only one that's congested today. Outside our office, El Camino has a familiar Parisian look—traffic is jammed, two drivers just bent some metal, lanes are closed, and people with hard hats and orange vests are milling around an open trench. The rumor is that the proverbial backhoe has struck again. We're sorry to cause frustration and we apologize for the untimely broken connection.

Other than that, it's a great day. We finally released BeOS 5, with many improvements, including an MP3 _encoder, new MIDI kit with microsecond resolution timing, support for 1394, isochronous USB, more drivers, a lower-memory footprint, new file systems support (such as read-only NTFS and CDDA), support for multiple networking cards, Lucent and PC-Tel softmodem, Pentium III optimization... The list is long and available at <>. Just as important as the free download, we now offer a "partition-free" install. This appears as a large file on your Windows system; when you launch BeOS, the host shuts down and BeOS runs by itself.

A caveat: as a sage here once announced on a sign above his cube, I'm moving to Theory because everything works in Theory. In other words, your experience may vary. The interaction between Windows and the hardware it runs on is nothing if not idiosyncratic. The shutdown process could leave your machine in an unknown state, which means that BeOS may or may not find a state it can reset to the values it needs. The situation is similar on dual-processor systems: Windows 98 automagically disables the second processor on some systems and leaves it in that state when shutting down.

Fortunately, there is an easy remedy: Please make a BeOS boot floppy. This is not an academic recommendation. If BeOS supports your hardware configuration but doesn't boot from Windows, it will boot unencumbered from your BeOS boot floppy.

As the media have already noted, we're also releasing the source code for the Tracker and the Deskbar, with a license that's a little more liberal than most. This allows interested programmers to modify the appearance and behavior of their systems and to gain better insights into the philosophy behind BeOS. Here again, we want to be cautious. We don't want to represent that we're open sourcing BeOS, nor are we implying anything about the future. This said, I'm personally curious to see what the most creative Be developers will do with the source code we're freeing today.

So far, in spite of our connection problems, thanks to one site in Germany, <>, we already had more than 25,000 downloads by mid-morning PST. This is much appreciated and, as I write this, we're doing our best to clear the clogged arteries.

Creative Commons License
Legal Notice
This work is licensed under a Creative Commons Attribution-Non commercial-No Derivative Works 3.0 License.