Advanced SVGA I by Anthony Tyler 07.03.99

Most of you probably remember the three articles on SVGA that Aaron Severn wrote. These articles touched on the basics of SVGA programming. I am hoping to go into a more in depth look at the SVGA. I will teach you how to program the SVGA by creating a library of SVGA functions. First of all, you will need an assembler, such as TASM or MASM. This is pretty important, but since most people don't have one I will write my code using the Call Absolute command. You will also need a SVGA card with at least 1 MB of video memory (512 kb might be okay). It's a good idea to get UNIVBE if you don't have a VESA card.

A recap of svga basics

Review of basic SVGA
First, I will review the basics of SVGA. If you grasped Aaron's articles well, then you could skip this part, but I suggest you read over it anyways. Since Aaron went into this well, I will not go into detail on this subject. Just the hard facts.

Detecting the VESA
When dealing with the VESA we must first check to see if the computer has a VESA card. We do this by calling VESA function 00h(remember all VESA functions are preceded by &H4F). VESA function 00h is also used, for finding information on the VESA card. We find information on the card by setting a TYPE.

TYPE VGAInfoBlock
VESASignature AS STRING * 4
VESAVersion AS INTEGER
OEMStringPTR AS LONG
Capabilities AS STRING * 4
VideoModePTR AS LONG
TotalMemory AS INTEGER
Reserved AS STRING * 236
END TYPE

The segment and offset of the VGAInfoBlock is loaded into the ES and DI registers, respectively. We do this by doing the following:

Regs.AX = &H4F00 ' VESA function 00h
Regs.ES = VARSEG(VGAInfoBlock)
Regs.DI = VARPTR(VGAInfoBlock)
CALL InterruptX (&H10, Regs, Regs)

Don't forget to put in the beginning of the programming a DIM SHARED Regs as RegTypeX. Because, this allows us to use the InterruptX procedure. If a VESA is found then it returns &H4F in AX, if any other value is found then there is not a VESA card on the computer. After this function, is called, it stores at ES:DI the following information.


VESASignature: always 'VESA' if there is a VESA card
VESAVersion: returns the VESA version number usually 1.2 or higher.
OEMStringPTR: pointer to a string that can be used to identify the video chip, video board, memory configuration, etc.
Capabilities: describes the capabilities of the video card
VideoModePTR: a pointer to a list of supported screen modes
TotalMemory: the total memory of the video card in 64 kb blocks.
Reserved: Reserved for future use.

So our complete DetectVESA function is as follows.

'$INCLUDE: 'QB.BI'
TYPE VGAInfoBlock
VESASignature AS STRING * 4
VESAVersion AS INTEGER
OEMStringPTR AS LONG
Capabilities AS STRING * 4
VideoModePTR AS LONG
TotalMemory AS INTEGER
Reserved AS STRING * 236
END TYPE
DIM SHARED Regs as RegTypeX, VGAInfo as VGAInfoBlock

DEFINT A-Z
FUNCTION DetectVESA%
RegsX.ax = &H4F00
RegsX.es = VARSEG(VGAInfo)
RegsX.di = VARPTR(VGAInfo)
CALL INTERRUPTX(&H10, RegsX, RegsX)
IF RegsX.ax = &H4F AND VGAInfo.VESASignature = "VESA" THEN
DetectVESA = 1
ELSE
DetectVESA = 0
END IF
PRINT "VESA Version:"; RTRIM$(STR$(VGAInfo.VESAVersion \ 255)); ".";
PRINT LTRIM$(STR$(VGAInfo.VESAVersion AND 255))
END FUNCTION

Finding information on, and setting a VESA screen mode.
The next step we need to take in our VESA library, is to set a VESA screen mode. Here is a list of VESA screen modes, not all of them are supported on all cards, or monitors.

  
      VESA Mode        Resolution      Colors

100h 640x400 256
101h 640x480 256
102h 800x600 16
103h 800x600 256
104h 1024x768 16
105h 1024x768 256
106h 1280x1024 16
107h 1280x1024 256
108h 80x60 text
109h 132x25 text
10Ah 132x43 text
10Bh 132x50 text
10Ch 132x60 text
10Dh 320x200 32k
10Eh 320x200 64k
10Fh 320x200 16.8m
110h 640x480 32k
111h 640x480 64k
112h 640x480 16.8m
113h 800x600 32k
114h 800x600 64k
115h 800x600 16.8m
116h 1024x768 32k
117h 1024x768 64k
118h 1024x768 16.8m
119h 1280x1024 32k
11Ah 1280x1024 64k
11Bh 1280x1024 16.8m

Before we set the screen mode, we need to find information on the mode. We do this by using VESA function 01h. In this function we set CX to the desired mode(see above) and ES and DI to the segment and offset of the following TYPE.

TYPE ModeInfoBlock
ModeAttributes AS INTEGER
WinAAttributes AS STRING * 1
WinBAttributes AS STRING * 1
WinGranularity AS INTEGER
WinSize AS INTEGER
WinASegment AS INTEGER
WinBSegment AS INTEGER
WinFuncPointer AS LONG
BytesPerScanLine AS INTEGER
XResolution AS INTEGER
YResolution AS INTEGER
XCharSize AS STRING * 1
YCharSize AS STRING * 1
NumberOfPlanes AS STRING * 1
BitsPerPixel AS STRING * 1
NumberOfBanks AS STRING * 1
MemoryModel AS STRING * 1
BankSize AS STRING * 1
NumberOfImagePages AS STRING * 1
SizeOfBank AS STRING * 1
RedMaskSize AS STRING * 1
RedFieldPosition AS STRING * 1
GreenMaskSize AS STRING * 1
GreenFieldPosition AS STRING * 1
BlueMaskSize AS STRING * 1
BlueFieldPosition AS STRING * 1
RsvdMaskSize AS STRING * 1
RsvdFieldPosition AS STRING * 1
DirectColorModeInfo AS STRING * 1
Reserved AS STRING * 216
END TYPE

For time reasons, I will not explain all of these(see Aaron's articles if you need information on these). I will only explain the important ones:

  • MemoryModel is used for detecting if the mode is available
  • XResolution is the amount of pixels going across
  • YResolution is the amount of pixels going down
  • NumberOfImagePages is the most important one, it tells how many pages of video
  • memory can be used(more about this later).

To actually set the mode we use VESA function 02h. In BX we store the desired mode. AX returns 4Fh if the operation was successful. This makes our set mode function as follows.

'$INCLUDE: 'qb.bi'
COMMON SHARED xRes, yRes
TYPE ModeInfoBlock
ModeAttributes AS INTEGER
WinAAttributes AS STRING * 1
WinBAttributes AS STRING * 1
WinGranularity AS INTEGER
WinSize AS INTEGER
WinASegment AS INTEGER
WinBSegment AS INTEGER
WinFuncPointer AS LONG
BytesPerScanLine AS INTEGER
XResolution AS INTEGER
YResolution AS INTEGER
XCharSize AS STRING * 1
YCharSize AS STRING * 1
NumberOfPlanes AS STRING * 1
BitsPerPixel AS STRING * 1
NumberOfBanks AS STRING * 1
MemoryModel AS STRING * 1
BankSize AS STRING * 1
NumberOfImagePages AS STRING * 1
SizeOfBank AS STRING * 1
RedMaskSize AS STRING * 1
RedFieldPosition AS STRING * 1
GreenMaskSize AS STRING * 1
GreenFieldPosition AS STRING * 1
BlueMaskSize AS STRING * 1
BlueFieldPosition AS STRING * 1
RsvdMaskSize AS STRING * 1
RsvdFieldPosition AS STRING * 1
DirectColorModeInfo AS STRING * 1
Reserved AS STRING * 216
END TYPE

DIM Regs as RegTypeX, ModeInfo as ModeInfoBlock
DEFINT A-Z
FUNCTION SetMode (mode)
Regs.AX = &H4F01
Regs.CX = mode
Regs.ES = VARSEG(ModeInfo)
Regs.DI = VARPTR(ModeInfo)
CALL INTERRUPTX(&H10, Regs, Regs)
IF ModeInfo.ModeAttributes AND 1 = 0 THEN PRINT "Cannot access mode"
xRes = ModeInfo.XResolution
yRes = ModeInfo.YResolution
IF ModeInfo.WinSize < 64 THEN
PRINT "This program only works with those modes with more than 64k of window"
SetMode = 0
EXIT FUNCTION 'these routines.
END IF
IF ASC(ModeInfo.MemoryModel) <> 6 THEN
PRINT "This Screen Mode is not available"
SetMode = 0
EXIT FUNCTION
END IF

Regs.AX = &H4F02 'Set the mode.
Regs.BX = mode
CALL INTERRUPT(&H10, Regs, Regs)

IF Regs.AX <> &H4F THEN 'Make sure it worked.
PRINT "Screen mode could not be initialized"
SetMode = 0
EXIT FUNCTION
END IF

SetMode = ASC(ModeInfo.NumberOfImagePages) + 1
END FUNCTION

This function returns the amount of video pages and sets the screen mode. This is all we have time for today, sorry I didn't get to anything new, but the next part of the article will be completely new. (Editor: Look for the next part of this series coming very soon).

What'd you think of this article? Let us know

(c) 1999 Grand Scimitar Studios.