[ / main / writing / dga ]

    The XFree86 DGA Extension

1998 Jeff Weeks and Codex software

The speed and technique of XShm is surpassed by only one; DGA. This X11 extension allows for direct access to the video frame buffer. Unlike XShm, DGA provides you with the actual frame buffer address, not functions to acess it

The difference here is two fold; With direct access you have no API's slowing you down, but this means you also have to write your own graphics code. Code that supports banks. That's right, more banking code. While X11 will try to get a linear frame buffer whenever possible there are still some cards which do not support them, and so must resort to banking.

Like XShm, we must first see if the DGA extension exists on this server before using it. We do this as follows:

      Display *display;
      int major, minor, event_base, error_base;
      if(!XF86DGAQueryExtension(display,&event_base,&error_base)) {
        printf("DGA extension not found\n");
        return 1;
      if(!XF86DGAQueryVersion(display,&major,&minor)) {
        printf("Cannot determine DGA version");
        return 1;

Just as we did in the XShm tutorial, there is another file you'll need to #include to use DGA code. It's

You might want to check the version number to see that it's above 1.0. Certain X servers may have a pre-release of DGA which may not be garaunteed to work with the DGA code I present to you. To the best of my knowledge, however, no server contains a DGA version less than 1.0.

Okay, now you've determined that the system does indeed have DGA. Now it's time to get the address of video memory, as well as its size. This is done with the following function calls:

      Display *display;
      int width, height, bytes_per_line, bank_size, ram;
      char *address;
      /* Get the size of the video view port, or bank size */
      XF86DGAGetViewPortSize(display, DefaultScreen(display), &width, &height);
      /* get the address of the video frame buffer, as well as some other information */
      XF86DGAGetVideo(display,DefaultScreen(display), &address, &bytes_per_line, &bank_size, &ram);
      /* Now tell X11 of what we've just done */
                         XF86DGADirectGraphics /*| XF86DGADirectMouse | XF86DGADirectKeyb*/);

Those should be fairly self explanatory. XF86DGAGetViewPortSize returns the screen dimensions in width and height so that you can adopt your drawing procedures to this area. XF86DirectVideo tells X11 to give up control of the frame buffer to the X client. You'll notice I've got two other options there commented out. Those are options to enable reporting of pointer movement as relative motion (XF86DGADirectMode) and to enable direct reporting of keyboard events (XF86DGADirectKeyb). XF86DGAGetVideo returns the address and other memory related variables, which you can use to check wether the card requires banking or not.

      Display *display;
      Bool banking;
      if(bank_size < (ram * 1024)) {
        XF86DGASetVidPage(display, DefaultScreen(display), 0);
        banking = True;
      } else banking = False;

So, you can get two things out of the above code snippet. First of all, the card's memory size is returned in kilobyte units, which means we must multiply by 1024 to get a byte count. Secondly, you can use XF86DGASetVidPage to set the bank number on banked cards. For those of you who are new to banks, they are a system utilized by some cards to access large ammounts of memory. Basically you have a memory window which can be moved throughout a larger window. When you write to this memory window, or bank, you're writing to a changeable portion of all the video memory.

That's really all there is to it. There is but one more initialization step you must take, and that is setting the viewport position. Remember how X11 allows you to have a scrollable viewport larger than your physical resolution? Well, it's always a good idea to set the viewport back to the top-left hand corner so that when you write to graphics memory it is centered in the users view.

      Display *display;
      XF86DGASetViewPort(display, DefaultScreen(display),0,0);

Now that's everything. Except, ofcourse, the shutdown code. When you're finished with all your DGA code you can shut it down using the following code:

      XF86DGADirectVideo(display, DefaultScreen(display), 0);

Yep, that's all there is to it. What you're doing is returning control of the frame buffer back to X11. As a final resource I will include the README.DGA I just happened to find. It documents (although not in depth) some of the things I haven't covered here.