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.
Copyright © 1995, Dr. Dobb's Journal
<b>Function Description</b>
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 <B>Return VBE controller information</B>
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 <B>Return VBE mode information</B>
CX= Mode number
ES:DI= Pointer to ModeInfoBlock structure
Output*: AX= VBE return status
Input: AX=4F02h <B>Set VBE mode</B>
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 <B>Return current VBE mode</B>
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 <B>Save/restore state</B>
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 <B>VBE display-window control </B>
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 <B>VBE set/get logical scan-line length</B>
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 <B>VBE set/get display start control</B>
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 <B>VBE set/get palette format</B>
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 <B>VBE load/unload palette data</B>
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 <B>VBE 2.0 protected-mode interface</B>
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