Advanced SVGA II by Anthony Tyler 08.01.99

Hi, everybody, and welcome back to part 2 of "Advanced SVGA". First of all I recommend that you read part 1 of this series, before you read this, because this builds on the knowledge we acquired in part 1. This time, we will learn how to write pixels to the screen in a 640x480 screen mode. Okay, enough of the introduction! Let's start programming! download the files

Theory
The SVGA, like the VGA, is written to by the video segment, &HA000. So to write pixels to a SVGA screen we must simple write the value to the proper location in &HA000. This is rather simple, but we do arrive at one problem. SVGA screen modes require more than the measly 64k that the video bios requires us to use, so VESA made function 05h(remember all VESA function are prefixed with a 4Fh). This function changes the bank (read Aaron Severn's documents for more info on banks). The bank is basically a window used to access video memory. To write to video memory we must first find the bank in which to write to, we then must find where in that 64k to write a pixel to.

Writing Pixels
First of all, let's find which screen mode we want to use. Let's use 112h. This is a 640x480 screen mode, with 16,777,216 colors. This is a 24 bit screen mode(or 1 byte per attribute). This makes it quite easy to write pixels all we have to do is write the RGB values to the proper offsets. Let me show you how to write pixels, and then we will step through it one line at a time.

SUB Pixel (X%, Y%, R%, G%, B%)
offset& = (Y% * 4) * 640& + (X% * 4)
BANK% = INT(offset& \ 65536)
offset& = offset& - 65536 * BANK%
IF BANK% <> curbank% THEN
Regs.ax = &H4F05
Regs.bx = 0
Regs.dx = curBank
CALL INTERRUPTX(&H10, InRegs, OutRegs)
END IF
curbank% = BANK%
DEF SEG = &HA000
POKE offset&, b%
POKE offset& + 1, g%
POKE offset& + 2, r%
END SUB

Let us begin to analyze this code. The first line is:

offset& = (Y% * 4) * 640& + (X% * 4)

This is the most important part, of the sub. What this does is it calculates where we should put the pixel. The reason we multiply the X and Y values by 4 is because each pixel takes four bytes(red, green, blue, and reserved). Reserved can be any value, and it does not effect the pixel. We multiply the Y * 4 by 640 because that is the width of X, video memory is stored the same in SVGA modes as in VGA modes:

        0   1   2   3   4   5   6   7   8   9
        640 641 642 643 644 645 646 647 648 649

We then just add the X value(times 4). The next piece of code is:

BANK% = INT(offset& \ 65536)

This calculates our bank. Since screen modes can only be accessed 64k at a time(65536 bytes). We must divide our offset by 64k to find the right bank. This is rather simple to understand.

offset& = offset& - 65536 * BANK%

This piece of code adjusts our offset to be within the 64k boundaries. Since we found the right bank. We then must subtract the bank * 65536 by our offset. For example, when we calculate our offset we get 65537. We find that our bank is bank 1. We then must find where in this bank, is our pixel. We do this calculation offset& = offset& - 65536 * BANK%. And our result is 1, so our pixel is at offset 1 in the first bank. Our next piece of code, is the bank setting code.

IF BANK% <> curbank% THEN
Regs.ax = &H4F05
Regs.bx = 0
Regs.dx = curBank
CALL INTERRUPTX(&H10, InRegs, OutRegs)
curbank% = BANK% END IF

This code saves us quite a bit of time. What it does is checks to see if the BANK our pixel is at is the BANK we are already at. If not, we set the BANK and change the variable curbank% to equal our current BANK, if so we do not need to waste our time setting a bank that we are already at.

DEF SEG = &HA000
POKE offset&, b%
POKE offset& + 1, g%
POKE offset& + 2, r%

The final piece of code, is the code that actually sets the pixel. All we do is set the segment to the video segment, and POKE the RGB values in reverse order. We do this because that is the way VESA made it.

Optimizations
Now is the fun part. Our current pixel routines, are really slooooow. We cannot use these routines anywhere, because they are so slow. What we need to do is optimize them. We do this by writing the code in assembly. Since most of you probably don't have an assembler I will post the library at the end of this document. Here's the assembler code for the pixel routine:


     bank dw ?
     PUBLIC Pixel
Pixel     PROC FAR X:WORD,Y:WORD,R:WORD,G:WORD,B:WORD
     MOV AX,0A000h
     MOV ES,AX
     MOV AX,Y
     SHL AX,2
     MOV BX,AX
     SHL EAX,9
     SHL EBX,7
     ADD EAX,EBX
     XOR EBX,EBX
     MOV BX,X
     SHL BX,2
     ADD EAX,EBX
     MOV EBX,EAX
     SHR EBX,16
     MOV ECX,EBX
     SHL ECX,16
     SUB EAX,ECX
     CMP BX,bank
     JNE bankset
pixelset:     MOV DI,AX
     MOV AX,B
     STOSB
     MOV AX,G
     STOSB
     MOV AX,R
     STOSB
     RET
bankset:     PUSH AX
     MOV DX,BX
     MOV AX,4F05h
     XOR BX,BX
     INT 10h
     POP AX
     MOV bank,DX
     JMP pixelset
ENDP     PIXEL

Without a great knowledge of assembly language this code would be very hard to decipher, therefore I will not step through this code line by line. Optimizing it in assembly language made the procedure 20 times faster. Well, since this document is getting pretty large, I guess I will wrap up this part. The next part of this series will be on more pixel drawing, and maybe line and circle drawing (thru the Bresenham Algorithms). Oh, and before I forget get our current library here. Have fun! Happy programming!!

SVGA Standards
by zkman

"SVGA" is not a standard as VGA was, it's just a term meaning "Super VGA" which represents any card using features above and beyond the VGA standard (i.e., uses more than the computer vga card's on-board memory). After the first few years of svga (much like in 3d acceleration now) had a standards called the VESA VGA BIOS Extensions introduced, which specifies certain pixel size and colour depths to be standard (such as 640x480x65k or 1024x768x16m). Later on, a standard called UVGA (Ultimate VGA) was coined to represent a colour depth of 1024x768 or higher, but never caught on, which is why SVGA's various sizes and color amounts (basically, anything over 640x480x16 is svga) amount to a somewhat confusing code.

With VESA BIOS, which represents nearly every 2d card nowadays, though, there's less to worry about in terms of whether your code will work on a certain computer. All the SVGA tuts at qb:tm use VESA BIOS calls.

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

(c) 1999 Grand Scimitar Studios.