Examining the VESA VBE 2.0 Specification

The recently released VESA BIOS Extension 2.0 specification extends the common, device-independent interface for accessing high-resolution/color-depth video modes on graphics controllers.


July 01, 1995
URL:http://www.drdobbs.com/architecture-and-design/examining-the-vesa-vbe-20-specification/184409592

JUL95: Examining the VESA VBE 2.0 Specification

Examining the VESA VBE 2.0 Specification

Extending the VESA standard

Brad Haakenson

Brad is the manager of advanced software research at Cirrus Logic and a member of the VESA Software Standards Committee. He can be contacted at [email protected].


In November 1994, the Video Electronic Standards Association (VESA) released Version 2.0 of the VESA BIOS Extension (VBE). Based upon the earlier-generation VBE (originally the "Video BIOS Extension"), the VESA VBE specification is a widely accepted, device-independent interface that allows programmers to access high-resolution/color-depth video modes on SVGA graphics controllers.

Our goals for VBE 2.0 were to provide an extensible framework for future growth, a high-performance interface for application programs, and support for advanced features present in current-generation graphics controllers--all while maintaining compatibility with the VBE specification. Consequently, VBE 2.0 is a true superset of VBE 1.2. All of the features and behaviors from previous versions are present. New VBE 2.0 features include support for non-VGA compatible controllers, a protected-mode interface for higher-performance graphics, support for linear frame buffers, digital-to-analog converter (DAC) services for palette operations, more OEM data, BIOS certification, and support for supplemental specifications. All VBE supplemental specifications are named "VBE/xxx," where xxx identifies the supplemental specification. For this reason, the name of the basic specification has been changed to "VBE Core Functions."

VBE 2.0

The hard copy of the VBE 2.0 specification is about three times the size of Version 1.2. While new features contribute about half of the bulk, we also added material to clarify existing features. (One of the biggest problems with previous versions was the ambiguity that led programmers to interpret it differently.)

VBE 2.0 also provides many more implementation notes within the VBE functions, along with new sections on BIOS implementation and application programming. These sections provide rules and suggestions on writing code that will work cleanly with all versions of VBE. We tried to make VBE 2.0 compatible with all properly written VBE applications so that, with a little work, any VBE 2.0 application will work properly with all previous versions of the specification.

To this end, VBE 2.0 includes an example program that demonstrates a "correct" VBE 2.0 application. This code is the basis for the program in Listings One and Two. While it can be compiled into a working program, the example code's main purpose is to demonstrate as many of the programming elements of a correctly written VBE 2.0 program as possible. If your compiler supports in-line assembly, you can combine the two listings into a single module. You are welcome to lift the code from the specification (or this article) and use it as-is. If you want to write your own code or adapt existing code to work with VBE 2.0, that's okay too. However, if it performs differently than the source code in the specification, your program needs to change.

Supplemental Specifications

Even though VESA was founded to define the interface that evolved into VBE, it has also endorsed a variety of other software specifications. Since most supplemental software specifications use the same extensions to the INT 10h interface as VBE, Version 2.0 provides a mechanism for them to extend VBE without requiring the core functions to be rewritten.

The first 16 VBE functions are reserved for the VBE Core Functions. Currently, only 11 have been assigned. The other five functions allow for future growth. Since the core functions were designed as an unaccelerated application-program interface to the graphics controller, any new requirements in this area will be added to future versions of the core functions.

Each supplemental specification is assigned one of the remaining function calls. This allows for a total of 240 specifications. The calls for each supplemental specification are subfunctions of the basic function call. Currently, VBE 2.0 defines the supplemental specifications; see Table 1. Some of these supplemental specifications, such as DPMS power management services, were released prior to the adoption of VBE 2.0 and will be rewritten to comply with all of the requirements for VBE Supplemental Specifications. Most of the other interfaces are currently being worked on by the VESA Software Standards Committee (SSC), which is responsible for VBE 2.0

VBE Video Modes

In the past, the SSC has defined double-byte-mode numbers to be used by VBE applications. For VBE 2.0, the Software Standards Committee decided that, rather than define new double-byte-mode numbers, we would encourage vendors to use their own single-byte-mode numbers for VBE-mode numbers. The double-byte-mode numbers have always caused problems: They can't be used with a standard VGA set-mode function call; they require video-card manufacturers to support two different numbers for every extended video mode; and the BIOS data area only reserves a single byte for the mode number at 0040:0049h.

The VBE specification recommends looking in the VbeInfoBlock returned by function 0h (Return VBE Controller Information) to determine the available video modes. Function 1h (Return VBE Mode Information) needs to be called for each reported video mode to find out if it is the correct color depth and resolution. If so, use it; if not, check the next mode until the end of the list.

VBE 2.0 requires that any mode reported in function 0h be fully supported by function 1h. Standard VGA modes may or may not be supported, depending on the OEM. Applications which assume that a specific mode number represents a given resolution and color depth may have serious problems in VBE 2.0. For compatibility, we recommend that VBE BIOSs support the existing double-byte-mode numbers wherever possible (but don't assume that they will always be there).

Function by Function

The best way to see how VBE 2.0 works is to examine the 11 core functions and how they differ from VBE 1.2. The VBE 2.0 Specification is over 80 pages long. Table 1 provides an overview of the function calls and how they relate to each other.

Function 0h (Return VBE Controller Information) requires a larger buffer than previous versions. The VbeInfoBlock size has been increased from 256 to 512 bytes. This allows for a longer video-mode list as well as increased vendor information. The vendor strings in VBE 2.0 include the VBE BIOS release number, the vendor and product names, and the revision of the hardware that the VBE BIOS is meant to work with. In ROM implementations, the mode list is also returned in the VbeInfoBlock. The calling program tells the VBE BIOS that there is a 512-byte block available by placing the string VBE2 in the first four bytes of the VbeInfoBlock when function 0h is called. Because of the different types of data that can be returned by function 0h, application programs cannot use any areas of the VbeInfoBlock for their own data storage.

Function 1h (Return VBE Mode Information) returns a ModeInfoBlock that has minor extensions from the previous versions of VBE. The biggest differences are the new mode-attribute flags, an address for a linear frame buffer, and off-screen memory information. The mode-attribute flags tell you whether or not VGA-compatible hardware is available in this mode and whether the mode can use linear addressing, segmented addressing, or both. If the mode isn't VGA compatible, don't directly program any registers or make assumptions about the location of the display memory windows. The off-screen memory size is represented as an offset from the start of display memory and a size. This is important, since some graphics controllers need to use part of their off-screen memory for internal features like hardware cursors and scratch data. If you destroy this data, bad things can happen, ranging from corrupted pop-up icons or hardware cursors to lost screen-centering data. In extreme cases, you would need to reboot the computer.

Function 2h (Set VBE Mode) reserves bit 14 of the mode number as a flag for a linear frame buffer. If the bit is set, the mode will be set with the linear frame buffer enabled. If bit 14 is not set, the mode will use standard segmented addressing. If bit 14 is set to a state not supported by the mode, it will be ignored. Bit 15 of the mode is the only bit that can be used as a flag to not clear memory. Previous versions of VBE were ambiguous about this, so some programs were written using bit 7 when setting a single-byte mode.

Function 3h (Return Current VBE Mode) is the same as in VBE 1.2 except that the linear-frame-buffer flag and the clear-memory flag are returned in the mode number. These flags use the same bits as in function 2h (Set VBE Mode). Functions 4h and 5h (Save/Restore State and Display Window Control) are the same as in VBE 1.2, but function 5h has no effect while using the linear-frame-buffer memory model.

Function 6h (Set/Get Logical Scan Line Length) has had a safety net added. When the line length was longer than could be supported by the hardware, VBE 1.2 returned a failure code and went on its way. A VBE 2.0 BIOS will set the maximum line length that the hardware will support and return that value in CX. In VBE 2.0, you can select the scan-line length in bytes or pixels. (VBE 1.2 only supported line lengths in pixel units, making it impossible to set common scan-line lengths, such as 1024 bytes, in 24 bit-per-pixel modes.) VBE 2.0 also provides a parameter to request the maximum scan-line length in either bytes or pixels without setting it.

Function 07h (Set/Get Display Start) can be set to wait for the next vertical retrace to take effect. This will prevent the screen from flickering as two sets of data are displayed during the same frame. Function 8h (Set/Get DAC Palette Format) is the same as in VBE 1.2.

Function 9h (Set/Get DAC Palette data) is new in VBE 2.0. It is equivalent to the standard VGA BIOS function 0Bh (Set Color Palette), except that it adds support for a second palette (if the DAC supports the feature). VBE 2.0 also adds a flag to delay palette writes until the next vertical retrace to prevent a snow-like effect from showing up on the screen during RAMDAC programming. We added this function because VBE 2.0 doesn't require VGA-compatible hardware or a VGA-compatible BIOS.

Function Ah (Return VBE Protected Mode Interface) provides pointers and offsets to the protected-mode versions of the three time-critical functions. This was added to VBE 2.0 to support high-performance, protected-mode access to the VBE 2.0 interface. For most of the VBE 2.0 function calls, your program can switch to real mode, but functions 05h (Display Window Control), 07h (Set/Get Display Start), and 9h (Set/Get DAC Palette data) are likely to be used while your program is in the middle of drawing the screen. For a real-time graphics program, the state transitions will seriously degrade your performance. The protected-mode versions of these functions are completely relocatable, and are intended to be copied directly into your code segment and executed locally for the best performance. You can also execute them directly without relocating them. Function Ah returns all of the information necessary to locate, copy, and execute the three functions.

Conclusion

VBE 2.0 is the result of two years of hard work. When we started on the spec, we thought it would be simple to clean up a few issues, toss in some new functions, and get it out the door. Upon closely examining the comments and requests programmers had sent VESA, however, we realized we had more work ahead. VBE 2.0, the result of our efforts, has been formally approved by the VESA membership. For copies of the VBE 2.0 Programmer's Toolkit (which includes the specification), contact VESA.

For More Information

Video Electronic Standards Association

VBE 2.0 Programmer's Toolkit

2150 N. First Street, Suite 440

San Jose, CA 95131

408-435-0333

$100.00

Table 1: Supplemental specifications in VBE 2.0.

Function    Description

Function 10h  Power Management Extensions (PM), formerly known
               as "VESA DPMS."
Function 11h  Flat Panel Interface Extensions (FP) provide a
               software interface to control the flat panel in
               portable computers.
Function 12h  Cursor Interface Extensions (CI), formerly known
               as "VESA VCI," are an interface to hardware
               cursors.
Function 13h  Audio Interface Extensions (AI) are a
               specification that provides a hardware-
               independent audio interface.
Function 14h  OEM Extensions provide an address space for
               graphics-card manufacturers to define their own
               function calls for the specific configuration
               of their graphics controllers. Normally used
               only by the individual controller manufacturers.
Function 15h  Display Data Channel (DDC) provides plug-and-play
               for monitors.
Function 16h  Graphics System Configuration (GC) is an interface
               that provides a low-level configuration for
               graphics controllers.
Function 17h  Accelerator Functions (AF) give application
               programs access to accelerator functions such as
               blitters and video playback.
Table 2: VBE 2.0 function summary; changes from VBE 1.2 are in italics.

Input:    AX=4F00h  Return VBE controller information
          ES:DI=    Pointer to buffer in which to place
                    VbeInfoBlock structure.
                    (VbeSignature should be set to 'VBE2' when
                    function is called to indicate VBE 2.0
                    information is desired and the information
                    block is 512 bytes in size.)
Output*:  AX=       VBE return status

Input:    AX=4F01h  Return VBE mode information
          CX=       Mode number
          ES:DI=    Pointer to ModeInfoBlock structure   
Output*:  AX=       VBE return status   
Input:    AX=4F02h  Set VBE mode
          BX=       Desired mode to set
            D0-D8=  Mode number
            D9-D13= Reserved (must be 0)
            D14=0   Use windowed frame buffer model
               =1   Use linear/flat frame buffer model 
            D15=0   Clear display memory 
               =1   Don't clear display memory
Output*:  AX=       VBE return status        

Input:    AX=4F03h  Return current VBE mode   
Output*:  AX=       VBE Return Status 
          BX=       Current VBE mode
            D0-D13= Mode number
            D14=0   Windowed frame buffer model
               =1   Linear/flat frame buffer model
            D15=0   Memory cleared at last mode set
               =1   Memory not cleared at last mode set

Input:    AX=4F04h  Save/restore state
          DL=00h    Return save/restore state buffer size 
            =01h    Save state
            =02h    Restore state
          CX=       Requested states 
            D0=     Save/Restore controller hardware state 
            D1=     Save/Restore BIOS data state 
            D2=     Save/Restore DAC state 
            D3=     Save/Restore Register state   
          ES:BX=    Pointer to buffer  (if DL <> 00h)  
Output*:  AX=       VBE return status 
          BX=       Number of 64-byte blocks to hold the state
                     buffer (if DL= 00h)

Input:    AX=4F05h  VBE display-window control 
          BH=00h    Set memory window 
            =01h    Get memory window 
          BL=       Window number 
            =00h    Window A 
            =01h    Window B 
          DX=       Window number in video memory in
                     window-granularity units  (set memory
                     window only)
Output:   AX=       VBE return status 
          DX=       Window number in window-granularity units

Input:    AX=4F06h  VBE set/get logical scan-line length
          BL=00h    Set scan-line length in pixels
            =01h    Get scan-line length
            =02h    Set scan-line length in bytes
            =03h    Get maximum scan-line length
          CX=       If BL=00h desired width in pixels
                    If BL=02h desired width in bytes (ignored
                     for get functions)
Output:   AX=       VBE return status 
          BX=       Bytes per scan line 
          CX=       Actual pixels/scan line (truncated to
                     nearest complete pixel)
          DX=       Maximum number of scan lines   

Input:    AX=4F07h  VBE set/get display start control
          BH=00h    Reserved and must be 00h 
          BL=00h    Set display start 
            =01h    Get display start 
            =80h    Set display start during vertical retrace
          CX=       First displayed pixel in scan line (set
                     display start only)
          DX=       First displayed scan line (set display
                     start only)   
Output:   AX=       VBE return status 
          BH=       00h reserved and will be 0 (get display
                     start only)  
          CX=       First displayed pixel in scan line (get
                     display start only) 
          DX=       First displayed scan line (get display
                     start only)   

Input:    AX=4F08h  VBE set/get palette format
          BL=00h    Set DAC palette format 
            =01h    Get DAC palette format 
          BH=       Desired bits of color per primary (set
                     DAC palette format only)  
Output:   AX=       VBE return status 
          BH=       Current number of bits of color per primary

Input:    AX=4F09h  VBE load/unload palette data
          BL=00h    Set palette data
            =01h    Get palette data
            =02h    Set secondary palette data
            =03h    Get secondary palette data
            =80h    Set palette data during vertical retrace
                     with blank bit on
          CX=       Number of palette registers to update
          DX=       First palette register to update
          ES:DI=    Table of palette values (see below for format)
Output:   AX=       VBE return status
Format of           Alignment byte, red byte, green byte,
  palette values:    blue byte

Input:    AX=4F0Ah  VBE 2.0 protected-mode interface
          BL=00h    Return protected-mode table
Output:   AX=       Status
          ES=       Real-mode segment of table
          DI=       Offset of table
          CX=       Length of table, including protected-mode
                     code in bytes (for copying purposes)

*All other registers are preserved.

Listing One

/****************************************************************************
* Hello VBE!
* Language: C (Keyword far is by definition not ANSI, therefore to make it true
*           ANSI remove all far references and compile under MEDIUM model.)
* Environment:  IBM PC (MSDOS) 16 bit Real Mode
* Original code contributed by:     - Kendall Bennett, SciTech Software
* Conversion to Microsoft C by:     - Rex Wolfe, Western Digital Imaging
*                   - George Bystricky, S-MOS Systems
* Description:  Simple 'Hello World' program to initialize a user-specified 
*     256-color graphics mode, and display a simple moire pattern. Tested with
*     VBE 1.2 and above. This code does not have any hard-coded VBE mode 
*     numbers, but will use the VBE 2.0 aware method of searching for available
*     video modes, so will work with any new extended video modes defined by a
*     particular OEM VBE 2.0 version. For brevity, we don't check for failure 
*     conditions returned by the VBE (but we shouldn't get any).
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <conio.h>
/* Comment out the following #define to disable direct bank switching. 
 * The code will then use Int 10h software interrupt method for banking. */
#define  DIRECT_BANKING
#ifdef  DIRECT_BANKING
/* only needed to setup registers BX,DX prior to the direct call.. */
extern far setbxdx(int, int);
#endif
/*---------------------- Macro and type definitions -----------------------*/
/* SuperVGA information block */
struct
{
    char    VESASignature[4];       /* 'VESA' 4 byte signature          */
    short   VESAVersion;            /* VBE version number               */
    char    far *OEMStringPtr;      /* Pointer to OEM string            */
    long    Capabilities;           /* Capabilities of video card       */
    unsigned far *VideoModePtr;     /* Pointer to supported modes       */
    short   TotalMemory;            /* Number of 64kb memory blocks     */
    char    reserved[236];          /* Pad to 256 byte block size       */
} VbeInfoBlock;
/* SuperVGA mode information block */
struct
{
    unsigned short ModeAttributes;      /* Mode attributes                 */
    unsigned char  WinAAttributes;      /* Window A attributes             */
    unsigned char  WinBAttributes;      /* Window B attributes             */
    unsigned short WinGranularity;      /* Window granularity in k         */
    unsigned short WinSize;             /* Window size in k                */
    unsigned short WinASegment;         /* Window A segment                */
    unsigned short WinBSegment;         /* Window B segment                */
    void (far *WinFuncPtr)(void);       /* Pointer to window function      */
    unsigned short BytesPerScanLine;    /* Bytes per scanline              */
    unsigned short XResolution;         /* Horizontal resolution           */
    unsigned short YResolution;         /* Vertical resolution             */
    unsigned char  XCharSize;           /* Character cell width            */
    unsigned char  YCharSize;           /* Character cell height           */
    unsigned char  NumberOfPlanes;      /* Number of memory planes         */
    unsigned char  BitsPerPixel;        /* Bits per pixel                  */
    unsigned char  NumberOfBanks;       /* Number of CGA style banks       */
    unsigned char  MemoryModel;         /* Memory model type               */
    unsigned char  BankSize;            /* Size of CGA style banks         */
    unsigned char  NumberOfImagePages;  /* Number of images pages          */
    unsigned char  res1;                /* Reserved                        */
    unsigned char  RedMaskSize;         /* Size of direct color red mask   */
    unsigned char  RedFieldPosition;    /* Bit posn of lsb of red mask     */
    unsigned char  GreenMaskSize;       /* Size of direct color green mask */
    unsigned char  GreenFieldPosition;  /* Bit posn of lsb of green mask   */
    unsigned char  BlueMaskSize;        /* Size of direct color blue mask  */
    unsigned char  BlueFieldPosition;   /* Bit posn of lsb of blue mask    */
    unsigned char  RsvdMaskSize;        /* Size of direct color res mask   */
    unsigned char  RsvdFieldPosition;   /* Bit posn of lsb of res mask     */
    unsigned char  DirectColorModeInfo; /* Direct color mode attributes    */
    unsigned char  res2[216];           /* Pad to 256 byte block size      */
} ModeInfoBlock;
typedef enum
{
    memPL       = 3,                /* Planar memory model              */
    memPK       = 4,                /* Packed pixel memory model        */
    memRGB      = 6,                /* Direct color RGB memory model    */
    memYUV      = 7,                /* Direct color YUV memory model    */
} memModels;
/*--------------------------- Global Variables ----------------------------*/
char mystr[256];
char *get_str();
int     xres,yres;                  /* Resolution of video mode used    */
int     bytesperline;               /* Logical CRT scanline length      */
int     curBank;                    /* Current read/write bank          */
unsigned int bankShift;             /* Bank granularity adjust factor   */
int     oldMode;                    /* Old video mode number            */
char    far *screenPtr;             /* Pointer to start of video memory */
void    (far *bankSwitch)(void);    /* Direct bank switching function   */
/*------------------------ VBE Interface Functions ------------------------*/
/* Get SuperVGA information, returning true if VBE found */
int getVbeInfo()
{
    union REGS in,out;
    struct SREGS segs;
    char far *VbeInfo = (char far *)&VbeInfoBlock;
    in.x.ax = 0x4F00;
    in.x.di = FP_OFF(VbeInfo);
    segs.es = FP_SEG(VbeInfo);
    int86x(0x10, &in, &out, &segs);
    return (out.x.ax == 0x4F);
}
/* Get video mode information given a VBE mode number. We return 0 if the mode
 * is not available, or if it is not a 256 color packed pixel mode. */
int getModeInfo(int mode)
{
    union REGS in,out;
    struct SREGS segs;
    char far *modeInfo = (char far *)&ModeInfoBlock;
    if (mode < 0x100) return 0;     /* Ignore non-VBE modes             */
    in.x.ax = 0x4F01;
    in.x.cx = mode;
    in.x.di = FP_OFF(modeInfo);
    segs.es = FP_SEG(modeInfo);
    int86x(0x10, &in, &out, &segs);
    if (out.x.ax != 0x4F) return 0;
    if ((ModeInfoBlock.ModeAttributes & 0x1)
            && ModeInfoBlock.MemoryModel == memPK
            && ModeInfoBlock.BitsPerPixel == 8
            && ModeInfoBlock.NumberOfPlanes == 1)
        return 1;
    return 0;
}
/* Set a VBE video mode */
void setVBEMode(int mode)
{
    union REGS in,out;
    in.x.ax = 0x4F02; in.x.bx = mode;
    int86(0x10,&in,&out);
}
/* Return the current VBE video mode */
int getVBEMode(void)
{
    union REGS in,out;
    in.x.ax = 0x4F03;
    int86(0x10,&in,&out);
    return out.x.bx;
}
/* Set new read/write bank. Set both Window A and Window B, as many VBE's have
 * these set as separately available read and write windows. We also use a 
 * simple (but very effective) optimization of checking if the requested bank 
 * is currently active. */
void setBank(int bank)
{
    union REGS  in,out;
    if (bank == curBank) return;    /* Bank is already active           */
    curBank = bank;                 /* Save current bank number         */
    bank <<= bankShift;             /* Adjust to window granularity     */
#ifdef  DIRECT_BANKING
    setbxdx(0,bank);
    bankSwitch();
    setbxdx(1,bank);
    bankSwitch();
#else
    in.x.ax = 0x4F05; in.x.bx = 0;  in.x.dx = bank;
    int86(0x10, &in, &out);
    in.x.ax = 0x4F05; in.x.bx = 1;  in.x.dx = bank;
    int86(0x10, &in, &out);
#endif
}
/*-------------------------- Application Functions ------------------------*/
/* Plot a pixel at location (x,y) in specified color (8 bit modes only) */
void putPixel(int x,int y,int color)
{
    long addr = (long)y * bytesperline + x;
    setBank((int)(addr >> 16));
    *(screenPtr + (addr & 0xFFFF)) = (char)color;
}
/* Draw a line from (x1,y1) to (x2,y2) in specified color */
void line(int x1,int y1,int x2,int y2,int color)
{
    int     d;                      /* Decision variable                */
    int     dx,dy;                  /* Dx and Dy values for the line    */
    int     Eincr,NEincr;           /* Decision variable increments     */
    int     yincr;                  /* Increment for y values           */
    int     t;                      /* Counters etc.                    */
#define ABS(a)   ((a) >= 0 ? (a) : -(a))
    dx = ABS(x2 - x1);
    dy = ABS(y2 - y1);
    if (dy <= dx)
    {
        /* We have a line with a slope between -1 and 1. Ensure that we are 
         * always scan converting the line from left to right to ensure that 
         * we produce the same line from P1 to P0 as the line from P0 to P1. */
        if (x2 < x1)
        {
            t = x2; x2 = x1; x1 = t;    /* Swap X coordinates           */
            t = y2; y2 = y1; y1 = t;    /* Swap Y coordinates           */
        }
        if (y2 > y1)
            yincr = 1;
        else
            yincr = -1;
        d = 2*dy - dx;              /* Initial decision variable value  */
        Eincr = 2*dy;               /* Increment to move to E pixel     */
        NEincr = 2*(dy - dx);       /* Increment to move to NE pixel    */
        putPixel(x1,y1,color);      /* Draw the first point at (x1,y1)  */
        /* Incrementally determine the positions of the remaining pixels */
        for (x1++; x1 <= x2; x1++)

        {
            if (d < 0)
                d += Eincr;         /* Choose the Eastern Pixel         */
            else
            {
                d += NEincr;        /* Choose the North Eastern Pixel   */
                y1 += yincr;        /* (or SE pixel for dx/dy < 0!)     */
            }
            putPixel(x1,y1,color);  /* Draw the point                   */
        }
    }
    else
    {
        /* We have a line with a slope between -1 and 1 (ie: includes vertical
         * lines). We must swap x and y coordinates for this. Ensure that we
         * are always scan converting the line from left to right to ensure 
         * that we produce the same line from P1 to P0 as line from P0 to P1.*/
        if (y2 < y1)
        {
            t = x2; x2 = x1; x1 = t;    /* Swap X coordinates           */
            t = y2; y2 = y1; y1 = t;    /* Swap Y coordinates           */
        }
        if (x2 > x1)
            yincr = 1;
        else
            yincr = -1;
        d = 2*dx - dy;              /* Initial decision variable value  */
        Eincr = 2*dx;               /* Increment to move to E pixel     */
        NEincr = 2*(dx - dy);       /* Increment to move to NE pixel    */
        putPixel(x1,y1,color);      /* Draw the first point at (x1,y1)  */
        /* Incrementally determine the positions of the remaining pixels */
        for (y1++; y1 <= y2; y1++)
        {
            if (d < 0)
                d += Eincr;         /* Choose the Eastern Pixel         */
            else
            {
                d += NEincr;        /* Choose the North Eastern Pixel   */
                x1 += yincr;        /* (or SE pixel for dx/dy < 0!)     */
            }
            putPixel(x1,y1,color);  /* Draw the point                   */
        }
    }
}
/* Draw a simple moire pattern of lines on the display */
void drawMoire(void)
{
    int     i;
    for (i = 0; i < xres; i += 5)
    {
        line(xres/2,yres/2,i,0,i % 0xFF);
        line(xres/2,yres/2,i,yres,(i+1) % 0xFF);
    }
    for (i = 0; i < yres; i += 5)
    {
        line(xres/2,yres/2,0,i,(i+2) % 0xFF);
        line(xres/2,yres/2,xres,i,(i+3) % 0xFF);
    }
    line(0,0,xres-1,0,15);
    line(0,0,0,yres-1,15);
    line(xres-1,0,xres-1,yres-1,15);
    line(0,yres-1,xres-1,yres-1,15);
}
/* Return NEAR pointer to FAR string pointer*/
char *get_str(char far *p)
{
    int i;
    char *q=mystr;
    for(i=0;i<255;i++)
    {
       if(*p) *q++ = *p++;
       else break;
    }
    *q = '\0';
    return(mystr);
}
/* Display a list of available resolutions. Be careful with calls to function
 * 00h to get SuperVGA mode information. Many VBE's build the list of video
 * modes directly in this information block, so if you are using a common 
 * buffer (which we aren't here, but in protected mode you will), then you will
 * need to make a local copy of this list of available modes. */
void availableModes(void)
{
    unsigned far    *p;
    if (!getVbeInfo())
    {
        printf("No VESA VBE detected\n");
        exit(1);
    }
    printf("VESA VBE Version %d.%d detected (%s)\n\n",
        VbeInfoBlock.VESAVersion >> 8, VbeInfoBlock.VESAVersion & 0xF,
        get_str(VbeInfoBlock.OEMStringPtr));
    printf("Available 256 color video modes:\n");
    for (p = VbeInfoBlock.VideoModePtr; *p !=(unsigned)-1; p++)
    {
        if (getModeInfo(*p))
        {
            printf("    %4d x %4d %d bits per pixel\n",
                ModeInfoBlock.XResolution, ModeInfoBlock.YResolution,
                ModeInfoBlock.BitsPerPixel);
        }
    }
    printf("\nUsage: hellovbe <xres> <yres>\n");
    exit(1);
}
/* Initialize the specified video mode. Notice how we determine a shift factor
 * for adjusting the Window granularity for bank switching. This is much faster
 * than doing it with a multiply (especially with direct banking enabled). */
void initGraphics(unsigned int x, unsigned int y)
{
    unsigned far    *p;
    if (!getVbeInfo())
    {
        printf("No VESA VBE detected\n");
        exit(1);
    }
    for (p = VbeInfoBlock.VideoModePtr; *p != (unsigned)-1; p++)
    {
        if (getModeInfo(*p) && ModeInfoBlock.XResolution == x
                && ModeInfoBlock.YResolution == y)
        {
           xres = x;   yres = y;
           bytesperline = ModeInfoBlock.BytesPerScanLine;
           bankShift = 0;
           while ((unsigned)(64 >> bankShift) != ModeInfoBlock.WinGranularity)
               bankShift++;
           bankSwitch = ModeInfoBlock.WinFuncPtr;
           curBank = -1;
           screenPtr = (char far *)( ((long)0xA000)<<16 | 0);
           oldMode = getVBEMode();
           setVBEMode(*p);
           return;
        }
    }
    printf("Valid video mode not found\n");
    exit(1);
}
/* Main routine. Expects the x & y resolution of the desired video mode to be
 * passed on command line. Will print out a list of available video modes if
 * no command line is present. */
void main(int argc,char *argv[])
{
    int x,y;
    if (argc != 3)
        availableModes();       /* Display list of available modes      */
    x = atoi(argv[1]);          /* Get requested resolution             */
    y = atoi(argv[2]);
    initGraphics(x,y);          /* Start requested video mode           */
    drawMoire();                /* Draw a moire pattern                 */
    getch();                    /* Wait for keypress                    */
    setVBEMode(oldMode);        /* Restore previous mode                */
}
/*----------------------------------------------------------------------*/
/* The following commented-out routines are for Planar modes            */
/* outpw() is for word output, outp() is for byte output                */
/*----------------------------------------------------------------------*/
/* Initialize Planar (Write mode 2)
 * Should be Called from initGraphics
void initPlanar()
{
   outpw(0x3C4,0x0F02);
   outpw(0x3CE,0x0003);
   outpw(0x3CE,0x0205);
}
*/
/* Reset to Write Mode 0
 * for BIOS default draw text
void setWriteMode0()
{
   outpw(0x3CE,0xFF08);
   outpw(0x3CE,0x0005);
}
*/
/* Plot a pixel in Planar mode
void putPixelP(int x, int y, int color)
{
    char dummy_read;
    long addr = (long)y * bytesperline + (x/8);
    setBank((int)(addr >> 16));
    outp(0x3CE,8);
    outp(0x3CF,0x80 >> (x & 7));
    dummy_read = *(screenPtr + (addr & 0xFFFF));
    *(screenPtr + (addr & 0xFFFF)) = color;
}
*/

Listing Two

; This module performs the bank switching for HELLOVBE.EXE. If your compiler
; supports in-line assembly, this code can be incorporated into HELLOVBE.C
public _setbxdx
.MODEL SMALL            ;whatever
.CODE
set_struc       struc
        dw      ?       ;old bp
        dd      ?       ;return addr (always far call)
p_bx    dw      ?       ;reg bx value
p_dx    dw      ?       ;reg dx value
set_struc       ends
_setbxdx        proc far     ; must be FAR
        push    bp
        mov     bp,sp
        mov     bx,[bp]+p_bx
        mov     dx,[bp]+p_dx
        pop     bp
        ret                 
_setbxdx        endp
END        

Copyright © 1995, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.