Full-Screen Exclusive Mode API

 


 

Overview

This lesson covers an API introduced in the latest release of the JavaTM 2 Platform Standard Edition, version 1.4. Visit the J2SE 1.4 download page.

Do you want to use high-performance graphics in the Java development environment? Have you always wanted to program a game, but your images wouldn't move fast enough? Has your slide show program not worked properly because you had no control over the user's display resolution? If you've been asking any of these questions, then the full-screen exclusive mode API may be what you're looking for.

 


 

Display Mode

Once an application is in full-screen exclusive mode, it may be able to take advantage of actively setting the display mode. A display mode (java.awt.DisplayMode) is composed of the size (width and height of the monitor, in pixels), bit depth (number of bits per pixel), and refresh rate (how frequently the monitor updates itself). Some operating systems allow you to use multiple bit depths at the same time, in which case the special value BIT_DEPTH_MULTI is used for the value of bit depth. Also, some operating systems may not have any control over the refresh rate (or you may not care about the refresh rate setting). In this case, the special value REFRESH_RATE_UNKNOWN is used for the refresh rate value.

 

How to Set the Display Mode

To get the current display mode, simply call the getDisplayMode method on your graphics device. To obtain a list of all possible display modes, call the getDisplayModes method. Both getDisplayMode and getDisplayModes can be called at any time, regardless of whether or not you are in full-screen exclusive mode.

Before attempting to change the display mode, you should first call the isDisplayChangeSupported method. If this method returns false, the operating system does not support changing the display mode.

Changing the display mode can only be done when in full-screen exclusive mode. To change the display mode, call the setDisplayMode method with the desired display mode. A runtime exception will be thrown if the display mode is not available, if display mode changes are not supported, or if you are not running in full-screen exclusive mode.

 

Reasons for Changing the Display Mode

The main reason for setting the display mode is performance. An application can run much more quickly if the images it chooses to display share the same bit depth as the screen. Also, if you can count on the display to be a particular size, it makes drawing to that display much simpler, since you do not have to scale things down or up depending on how the user has set the display.

 

 

Programming Tips

Here are some tips for choosing and setting the display mode:

 


 

Double Buffering and Page Flipping

Suppose you had to draw an entire picture on the screen, pixel by pixel or line by line. If you were to draw such a thing directly to the screen (using, say, Graphics.drawLine), you would probably notice with much disappointment that it takes a bit of time. You will probably even notice visible artifacts of how your picture is drawn. Rather than watching things being drawn in this fashion and at this pace, most programmers use a technique called double-buffering.

The traditional notion of double-buffering in Java applications is fairly straightforward: create an offscreen image, draw to that image using the image's graphics object, then, in one step, call drawImage using the target window's graphics object and the offscreen image. You may have already noticed that Swing uses this technique in many of its components, usually enabled by default, using the setDoubleBuffered method.

The screen surface is commonly referred to as the primary surface, and the offscreen image used for double-buffering is commonly referred to as the back buffer. The act of copying the contents from one surface to another is frequently referred to as a block line transfer, or blitting (blt is typically pronounced "blit" and shouldn't be confused with a BLT sandwich).

Double Buffering

The primary surface is usually manipulated through the graphics object of any showing component; when in full-screen mode, any operation using the graphics of the full-screen window is a direct manipulation of screen memory. For this reason, you can take advantage of other capabilities in full-screen exclusive mode that may otherwise be unavailable due to the overhead of the windowing system. One such technique that is only available in full-screen exclusive mode is a form of double-buffering called page-flipping.

 

Page Flipping

Many graphics cards have the notion of a video pointer, which is simply an address in video memory. This pointer tells the graphics card where to look for the contents of the video to be displayed during the next refresh cycle. In some graphics cards and on some operating systems, this pointer can even be manipulated programmatically. Suppose you created a back buffer (in video memory) of the exact width, height, and bit depth of the screen, then drew to that buffer the same way as you would using double-buffering. Now imagine what would happen if, instead of blitting your image to the screen as in double-buffering, you simply changed the video pointer to your back buffer. During the next refresh, the graphics card would now use your image to display. This switch is called page-flipping, and the performance gain over blt-based double-buffering is that only a single pointer needs to be moved in memory as opposed to copying the entire contents from one buffer to another.

When a page flip occurs, the pointer to the old back buffer now points to the primary surface and the pointer to the old primary surface now points to the back buffer memory. This sets you up automatically for the next draw operation.

Page Flipping

Sometimes it is advantageous to set up multiple back buffers in a flip chain. This is particularly useful when the amount of time spent drawing is greater than the monitor's refresh rate. A flip chain is simply two or more back buffers (sometimes called intermediary buffers) plus the primary surface (this is sometimes called triple-buffering, quadruple-buffering, etc.). In a flip chain, the next available back buffer becomes the primary surface, etc., all the way down to the rearmost back buffer that is used for drawing.

 

Benefits of Double-Buffering and Page-Flipping

If your performance metric is simply the speed at which double-buffering or page-flipping occurs versus direct rendering, you may be disappointed. You may find that your numbers for direct rendering far exceed those for double-buffering and that those numbers far exceed those for page-flipping. Each of these techniques is for used for improving perceived performance, which is much more important in graphical applications than numerical performance.

Double-buffering is used primarily to eliminate visible draws which can make an application look amateurish, sluggish, or appear to flicker. Page-flipping is used primarily to also eliminate tearing, a splitting effect that occurs when drawing to the screen happens faster than the monitor's refresh rate. Smoother drawing means better perceived performance and a much better user experience.

 


 

BufferStrategy and BufferCapabilities

 

BufferStrategy

In Java 2 Standard Edition, you don't have to worry about video pointers or video memory in order to take full advantage of either double-buffering or page-flipping. The new class java.awt.image.BufferStrategy has been added for the convenience of dealing with drawing to surfaces and components in a general way, regardless of the number of buffers used or the technique used to display them.

A buffer strategy gives you two all-purpose methods for drawing: getDrawGraphics and show. When you want to start drawing, get a draw graphics and use it. When you are finished drawing and want to present your information to the screen, call show. These two methods are designed to fit rather gracefully into a rendering loop:

BufferStrategy myStrategy;

while (!done) {
    Graphics g = myStrategy.getDrawGraphics();
    render(g);
    g.dispose();
    myStrategy.show();
}

Buffer strategies have also been set up to help you monitor VolatileImage issues. When in full-screen exclusive mode, VolatileImage issues are especially important because the windowing system can sometimes take back the video memory it has given you. One important example is when the user presses the ALT+TAB key combination in Windows--suddenly your full-screen program is running in the background and your video memory is lost. You can call the contentsLost method to find out if this has happened. Similarly, when the windowing system returns your memory to you, you can find out using the contentsRestored method.

BufferCapabilities

As mentioned before, different operating systems, or even different graphics cards on the same operating system, have different techniques available at their disposal. These capabilities are exposed for you so that you can pick the best technique for your application.

The class java.awt.BufferCapabilities encapsulates these capabilities. Every buffer strategy is controlled by its buffer capabilities, so picking the right ones for your application is very crucial. To find out what capabilities are available, call the getBufferCapabilities method from the GraphicsConfiguration objects available on your graphics device.

The capabilities available in Java 2 Standard Edition version 1.4 are:

isPageFlipping
This capability returns whether or not hardware page-flipping is available on this graphics configuration.

isFullScreenRequired
This capability returns whether or not full-screen exclusive mode is required before hardware page-flipping should be attempted.

isMultiBufferAvailable
This capability returns whether or not multiple buffering (two or more back buffers plus the primary surface) in hardware is available.

getFlipContents
This capability returns a hint of the technique used to do hardware page-flipping. This is important because the contents of the back buffer after a show are different depending on the technique used. The value returned can be null (if isPageFlipping returns false) or one of the following values. Any value can be specified for a buffer strategy so long as the isPageFlipping method returns true, though performance will vary depending on the available capabilities.

FlipContents.COPIED
This value means that the contents of the back buffer are copied to the primary surface. A "flip" is probably performed as a hardware blt, which means that hardware double-buffering is probably done using blitting instead of true page-flipping. This should (in theory) be faster, or at least as fast, as blitting from a VolatileImage to the primary surface, though your mileage may vary. The contents of the back buffer are the same as the primary surface after a flip.

FlipContents.BACKGROUND
This value means that the contents of the back buffer have been cleared with the background color. Either a true page-flip or a blt has occurred.

FlipContents.PRIOR
This value means that the contents of the back buffer are now the contents of the old primary surface, and vice versa. Generally this value indicates that true page-flipping occurs, though this is not guaranteed and, once again, your mileage on this operation may vary.

FlipContents.UNKNOWN
This value means that the contents of the back buffer are undefined after a flip. You may have to experiment to find which technique works best for you (or you may not care), and you will definitely have to set up the contents of the back buffer yourself each time you draw.
To create a buffer strategy for a component, call the createBufferStrategy method, supplying the number of buffers desired (this number includes the primary surface).  If any particular buffering technique is desired, supply an appropriate BufferCapabilities object. Note that when you use this version of the method, you must catch an AWTException in the event that your choice is not available. Also note that these methods are only available on Canvas and Window.

Once a particular buffer strategy has been created for a component, you can manipulate it using the getBufferStrategy method. Note that this method is also only available for canvases and windows.

 

 

Programming Tips

Some tips about using buffer capabilities and buffer strategies:

 


 

Examples

You can only run these examples if you're using Java 2 Standard Edition version 1.4 or higher. CapabilitiesTest demonstrates the different buffering capabilities available for the machine on which it is run.

DisplayModeTest shows a Swing application that uses passive rendering. If full-screen exclusive mode is available, it will enter full-screen exclusive mode. If display mode changes are allowed, it allows you to switch between display modes.

MultiBufferTest enters full-screen mode and uses multi-buffering through an active render loop.

 

Home