lurkertech.com Lurker's Guide DMbuffers for Video and OpenGL

Support
This Site
I work on this site in my off hours. Please help me to push aside my day job and work on it more by supporting the site in one of these ways:
donate now   Donate Now
Use your credit card or PayPal to donate in support of the site.

get anything at all from amazon.com
Use this link to Amazon—you pay the same, this site gets 4% from Amazon.
get the best thai-english phrasebook app
Experience Thailand richly with my Talking Thai-English-Thai Phrasebook app.
get the best thai-english dictionary app
Learn Thai with my Talking Thai-English-Thai Dictionary app for iOS, Android, Windows.
get a cool thai-english paper dictionary
Don't leave home without the Thai-English English-Thai Compact Dictionary I co-authored.
get thailand fever
I co-authored this bilingual cultural guidebook to Thai-Western romantic relationships.
get the best chinese phrasebook app
Visit China easily with my Talking Chinese-English-Chinese Phrasebook app.

Submit
This Site
Like what you see?
Help spread the word using these social sites:
StumbleUpon
del.icio.us
del.icio.us

Note: Updated Lurker's Guide available (but not this page!)

This page belongs to the old 1990s SGI Lurker's Guide. As of 2008, several of the Lurker's Guide pages have been updated for HDTV and for modern OS platforms like Windows and Mac. This particular page is not one of those, but you can see what new stuff is available here. Thanks!

DMbuffers for Video and OpenGL

Brian Beach

Note: This document uses the O2 VL DMbuffer API instead of the cross-platform VL DMbuffer API (see What Are the SGI Video-Related Libraries? for more info). It refers to IRIX 6.3 man pages and documentation.

DMbuffers are used to store images in various formats, which can be passed from video to graphics, graphics to video, video to programs, and programs to video.

For a general introduction to DMbuffers, see Chapter 5 of the IRIX 6.3 Digital Media Programming Guide. The short summary is that an application wanting to use DMbuffers for video and graphics first creates a pool of buffers, specifying the number of buffers in the pool. Then, buffers can be

The trick to using DMbuffers effectively is making sure that the format of the images in them is compatible with both the image producer and the image consumer.

Image Layouts

Before getting into the details of DMbuffers and how they are used with the digital media libraries, let's take a look at image formats. There are two basic image layouts in the O2 machine: linear and graphics.

The linear layout is familiar one. It comes in two varieties: top-to-bottom and bottom-to-top. With top-to-bottom (the natural order for video), the first pixel in a image buffer is the upper-left pixel. Following it are the rest of the pixels on the top row. After the top row is the next-to-the-top row, and so on, finally ending at the bottom-right pixel. This is the scan order for a linear image:

OpenGL more naturally supports the bottom-to-top order. More about this later.

The other layout is called the graphics layout. It is the internal image layout used by the CRM graphics engine. The details of the layout are not published; SGI reserves the right to change this layout at any time. The basic idea is that the image is divided into rectangular tiles, which allow the rendering engine to be more efficient. The scan order looks something like this:

Video on O2 supports both linear and graphics layouts. glDrawPixels and glReadPixels support only the linear layout, but images in pbuffers (see below) are always in the graphics layout.

Pixel Packing

There are three pixel formats that can be used both by video and graphics. The video library (libvl), the digital media library (libdmedia), and the graphics library (libGL) all have different names for the same things. The names are:
libvllibdmedialibGL
rgba-8888VL_PACKING_ABGR8DM_IMAGE_PACKING_RGBAGL_RGBA
rgba-5551VL_PACKING_ARGB_1555DM_IMAGE_PACKING_XRGB5551GL_RGB5_A1_EXT
rgb-332VL_PACKING_X444_332DM_IMAGE_PACKING_RGB332GL_RGB with
GL_UNSIGNED_BYTE_3_3_2_EXT

DMbuffers

The man page, DMbuffer(4), has an overview of DMbuffers, what they are, and how they are used. For our purposes here, suffice it to say that a DMbuffer is a chunk of memory, obtained from dmBufferAllocate(), vlEventToDMBuffer(), or dmICReceive(), and is used to store a single image.

Before you can use DMbuffers with OpenGL or dmIC, you must first create a DMparams that describes the format of the image. To do this, you need to know the size of the image (width and height), the pixel packing, and the image layout (graphics or linear). Here is code that creates a DMparams for linear, top-to-bottom, 640x480, RGBA-8888 images:

    DMparams* imageFormat;
    DMstatus s;

    s = dmParamsCreate( &imageFormat );
    if ( s != DM_SUCCESS )  error();

    s = dmSetImageDefaults( imageFormat,
            640, 480, DM_IMAGE_PACKING_RGBA );
    if ( s != DM_SUCCESS )  error();

    s = dmParamsSetEnum( imageFormat,
            DM_IMAGE_ORIENTATION,
            DM_TOP_TO_BOTTOM );
    if ( s != DM_SUCCESS )  error();

    s = dmParamsSetEnum( imageFormat,
            DM_IMAGE_LAYOUT,
            DM_IMAGE_LAYOUT_LINEAR );
    if ( s != DM_SUCCESS )  error();

For images in the graphics layout, the DM_IMAGE_ORIENTATION parameter is meaningless.

To set up a pool of DMbuffers that can be used with video and graphics, you do something like this:

    DMparams* imageFormat;  /* see above */
    
    VLServer server;
    VLPath path;
    VLNode node;
    
    DMbufferpool pool;
    
    /* Set up the video path before trying to create the pool. */
    
    {
        DMstatus s;
        int v;
        DMparams* poolSpec;
        int count = NUMBER_OF_BUFFERS_NEEDED_BY_APPLICATION;
        DMboolean cacheable = DM_FALSE;
        DMboolean mapped = DM_FALSE;
        
        s = dmParamsCreate( &poolSpec );
        if ( s != DM_SUCCESS )  error();
        
        s = dmBufferSetPoolDefaults( poolSpec, count, 0, cacheable, mapped );
        if ( s != DM_SUCCESS )  error();
        
        v = vlDMPoolGetParams( server, path, node, poolSpec );
        if ( v != 0 )  error();
        count += dmParamsGetInt( poolSpec, DM_BUFFER_COUNT );
        dmParamsSetInt( poolSpec, DM_BUFFER_COUNT, 0 );
        
        s = dmBufferGetGLPoolParams( imageFormat, poolSpec );
        if ( s != DM_SUCCESS )  error();
        
        dmParamsSetInt( poolSpec, DM_BUFFER_COUNT, count );
        s = dmBufferCreatePool( poolSpec, &pool );
        if ( s != DM_SUCCESS )  error();
        
        dmParamsDestroy( poolSpec );
    }

The count is the number of buffers in the pool. When a pool is created, it has a fixed number of buffers that never changes. To figure out the number of buffers required in the pool, you must add up all of the simultaneous requirements:

  1. Each video path to or from memory needs buffers. vlDMPoolGetParams will set BUFFER_COUNT to the minimum number required by that path. For input paths, the minimum number assumes that the application will process all VL events immediately. For output paths, it assumes that the application delivers buffers at the last possible moment.
  2. Each digital media pbuffer (see below) and texture object that is bound to a DMbuffer may require its own buffer. Add one for each of these. (In the example above, it assumes a single pbuffer owning one DMbuffer.)
  3. The application, itself, will need some number of buffers. This number might include an extra allowance for video buffers, if video events are not processed immediately. (It is usually a good idea to allow at least one extra buffer per video path.)

vlDMPoolGetParams will increase the BUFFER_COUNT in the parameter list to the minimum required for that one video path. To find out the actual number required by the path, BUFFER_COUNT should be 0 when it is called, and then queried afterwards.

A single buffer pool can be created once and then used for multiple purposes. To use one pool with multiple video paths, just call once for each video path before creating the pool. If the paths are to be used simultaneously, the buffer counts from each call should be added.

IMPORTANT: never call dmBufferMapData() on a buffer containing an image in the graphics layout. Cache coherency is not guaranteed if you do this.

Video I/O

To get video into a DMbuffer:

  1. Set up a video input path from a video node to a memory node.
  2. Create a buffer pool.
  3. Call vlDMPoolRegister
  4. Start the video transfer with vlBeginTransfer.
  5. Use vlEventRecv and vlEventToDMBuffer to get a DMbuffer holding one frame.

To take a DMbuffer that already contains an image and send it to a video output device:

  1. call vlDMBufferSend.

OpenGL: Rendering Into DMbuffers

The DMbuffer extension to OpenGL allows you to create a pbuffer, and then attach a DMbuffer to it to use as the color buffer. See the man page for glXAssociateDMPbufferSGIX (it's not in 6.3, but should be in 6.3.1).

Before you can associate a DMbuffer width a pbuffer, you must first create a special kind of pbuffer, called a digital media pbuffer. You do it like this:

        GLXFBConfigSGIX config = ...;
        int width = 640;
        int height = 480;
        GLXFBconfig int attribs [] = {
            GLX_DIGITAL_MEDIA_PBUFFER_SGIX, True,
            GLX_PRESERVED_CONTENTS_SGIX, True,
            (int) None
        };
        GLXPbufferSGIX pbuffer;
        pbuffer = glXCreateGLXPbufferSGIX(
            display,
            config,
            width,
            height,
            attribs
            );
        if ( pbuffer == None )  error();

The frame buffer configuration that is used when the pbuffer is created must match the image format of the image in the DMbuffer that will be used with it. This means that the width and the height must match, the image layout must be "graphics", and the pixel packing must match the depth of the red, green, blue, and alpha planes in the frame buffer. The allowed pixel packings are: DM_IMAGE_PACKING_RGBA, and DM_IMAGE_PACKING_XRGB1555, and DM_IMAGE_PACKING_RGB332.

The code above will create a pbuffer that does not yet have an associated color buffer, but will have all of the other buffers (depth, stencil, accumulation, etc.) that are specified in the fbconfig:

Allocating a DMbuffer from a pool is easy:

    DMbufferpool pool = ...;
    DMstatus s;
    DMbuffer buffer;
    s = dmBufferAllocate( pool, &buffer );
    if ( s != DM_SUCCESS )   error();

Now you have a DMbuffer and a pbuffer:

The next step is to associate the DMbuffer with the pbuffer. This makes the DMbuffer be the color buffer.

    DMparams* imageFormat = ...;
    DMbuffer  buffer = ...;
    Bool ok;
    ok = glXAssociateDMPbufferSGIX(
        display, 
        pbuffer,
        imageFormat,
        buffer
        );
    if ( ! ok )   error();

As noted above, the imageFormat must specify that the layout is graphics, must match the width and height of the pbuffer, and must have a compatible pixel packing. This will make a link from the pbuffer to the DMbuffer, so that any rendering done to the pbuffer will be drawn into the DMbuffer.

Before you can render, of course, you must have a graphics context. This is created in the normal way, but must be created using a visual or fbconfig that is compatible with the pbuffer. Once you have a context, you can make the pbuffer current with a context:

    GLXContext context = ...;
    Bool ok;
    ok = glXMakeCurrent( display, pbuffer, context );

This makes the context current, and now, any rending that happens will be done into the DMbuffer:

OpenGL: Using DMbuffers as Textures

In addition to rendering into a DMbuffer, you can also use the contents of a DMbuffer as a texture. This is done by associating the DMbuffer with a pbuffer and then using glCopyTexSubImage2DEXT to load the contents of the DMbuffer as a texture. When certain criteria are met, the image is not actually copied, but is used as a texture directly.

For this example, say you have an image in a DMbuffer that you want to use as a texture when drawing to a window. This image may have come from a video input path, or it may have been rendered with OpenGL. Either way, the procedure for using it as a texture is the same. You start with a window and a pbuffer/DMbuffer pair:

Calling glXMakeCurrentReadSGI will attach a context so that the glCopy calls (glCopyPixels, glCopyTexImage2D, etc.) will copy pixels from the DMbuffer to the window or to texture:

At this point, any of the glCopyTexImage calls will get the image into texture memory. But, if certain criteria are met, then glCopyTexSubImage2DEXT will not actually copy. It will free the memory holding the previous texture and use the DMbuffer instead:

The conditions that enable this "copy by reference" are (see the man page for glCopyTexSubImage2DEXT):

When creating the texture to "copy" into, specifying GL_RGBA8_EXT, instead of GL_RGBA, will force the depth to be 8 bits per component. Normally, the texture will be the same depth as the current drawable.

Support
This Site
I work on this site in my off hours. Please help me to push aside my day job and work on it more by supporting the site in one of these ways:
donate now   Donate Now
Use your credit card or PayPal to donate in support of the site.

get anything at all from amazon.com
Use this link to Amazon—you pay the same, this site gets 4% from Amazon.
get the best thai-english phrasebook app
Experience Thailand richly with my Talking Thai-English-Thai Phrasebook app.
get the best thai-english dictionary app
Learn Thai with my Talking Thai-English-Thai Dictionary app for iOS, Android, Windows.
get a cool thai-english paper dictionary
Don't leave home without the Thai-English English-Thai Compact Dictionary I co-authored.
get thailand fever
I co-authored this bilingual cultural guidebook to Thai-Western romantic relationships.
get the best chinese phrasebook app
Visit China easily with my Talking Chinese-English-Chinese Phrasebook app.
CopyrightAll text and images copyright 1999-2017 Chris Pirazzi unless otherwise indicated.