SVGA Part 1

By Aaron Severn

(this is some very advanced stuff. If you’re a newbie to coding, I suggest you try some less advanced stuff.-ed)

1 Introduction

1.1 What is SVGA
----------------

For a long time PC graphics were limited to a small 64 kilobyte piece of memory, and for a long time this was fine. No one needed more than 16 colours and low resolution, and even if they did computers weren't fast enough to handle it. But we all know what happens next. To fulfill the demand for better graphics the VGA was introduced. With 256k of memory now possible and up to 256 colours in one mode it satisfied a lot of people. But that barely quenched our thirst for good graphics, so something more had to be done.

Thus Super VGA came in to existence allowing multiple megabytes of video memory, screen modes with resolutions as high as 1600x1200 and as many as 16.8 million colours. What more could one ask for. Unfortunately, SVGA graphics cards came out by the dozens, each with their own method of use. A program that used SVGA graphics would need to have dozens of different graphics routines to do the same thing on different cards. Something had to be done to end the confusion, which brings us to the next section.

1.2 What is VESA

----------------

VESA (Video Electronics Standards Association) was put together to create a standard method for using SVGA graphics. They came up with a VGA BIOS extension that handles the details of various SVGA cards so that you don't have to. It supplies a standardized set of screen modes listed in appendix B that are used in the same way on all cards. At this point in time I can say that most PCs around today have VESA compatible graphics cards, thus it is safe to write software for VESA SVGA rather than for individual cards. That is what this document will discuss.

1.3 Background Knowledge

------------------------

Before I can start discussing the details of programming VESA SVGA, there's a few things you should be familiar with first. I don't intend to teach these things, I will give only an overview. If you are already familiar with the topics, by all means, skip them.

1.3.1 The Hexadecimal number system

-----------------------------------

I have found a lot of confusion among QBasic programmers as far as hexadecimal (hex) is concerned. There is nothing special about it, it is just another was of counting. Our decimal number system is base 10, that is, one digit can have 10 different values. Hex is a base 16 system where one digit can have 16 different values. It's nothing special, if we had 8 fingers on each hand we'd all be very familiar with it, too bad we have 5.

QBasic represents hex numbers with the &H prefix, this document will use the same method. Many of you may have seen this in programs and wondered what it meant, well now you know. The following is a small table of hex numbers with their decimal equivalent so you can see what I'm talking about.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17

The reason we use hex is because it makes a lot more sense with respect to computers. We've all heard that computers are based on the binary (base 2) number system because they are made up of electrical switches which can be either on or off, because of this it is much more useful to have a number system based on a power of 2 (like 16). Any hardware programming will be easier with hex, SVGA is no exception.

1.3.2 Using CALL INTERRUPT

--------------------------

If you are using QBasic 1.1, you can ignore this section because you can't use CALL INTERRUPT, but in QuickBasic it is a very handy command to know. What is does is generate an interrupt (named interrupt because the CPU interrupts whatever it was doing to perform the required task) that will do various things for you. It would help to have knowledge of CPU registers when using this command since that is what you are manipulating, but it is not necessary.

The first thing you need is a user defined variable type. This is defined in the QB.BI header file but I will list it here anyway.

    TYPE RegType
        AX AS INTEGER
        BX AS INTEGER
        CX AS INTEGER
        DX AS INTEGER
        BP AS INTEGER
        SI AS INTEGER
        DI AS INTEGER
        FLAGS AS INTEGER
        DS AS INTEGER
        ES AS INTEGER
    END TYPE

When using CALL INTERRUPT, you will create a variable of the above type (DIM Regs AS RegType) and assign values to the pseudo-registers. What values you give depends on what you want to do. There are hundreds of BIOS calls that you can perform and the documentation for each one will give you the details. After assigning the proper values you then use CALL INTERRUPT (or CALL INTERRUPTX if you need the DS and ES registers) to generate the proper interrupt. The format for CALL INTERRUPT is as follows.

    CALL INTERRUPT (interruptNumber, inRegs, outRegs)

InterruptNumber defines which interrupt you want executed (the VGA is interrupt &H10), inRegs is a variable of type RegType which you pass to the function with the required information stored in it, and outRegs is another variable of type RegType which you pass to the function to be filled by it. It returns error info or other things that the interrupt was supposed to return.

1.3.3 Assembly language

-----------------------

This is something this document definitely will not teach. Learning assembly language can be a long and tedious process and there are plenty of tutorials available on the internet to help you out. This is not one of them. If you are using QBasic 1.1, you won't be able to do any of this without knowledge of assembly language. If you are using QuickBasic you can do all the SVGA programming you want without assembly code, however it will never be fast enough for most practical purposes. Thus, I recommend that you learn some basic assembly before you do too much with this document.

1.4 Use in QBasic compared to QuickBasic

----------------------------------------

As explained above, in order to use SVGA in QBasic 1.1 you must know how to program in assembly language and you must know how to incorporate that code into your QBasic programs with the CALL ABSOLUTE function. In QuickBasic, everything can be done (and a lot should be done) with the CALL INTERRUPT command. However, in order to obtain enough speed to get any practical use out of this knowledge, you will need assembly code. A very fast put routine for 256 colour modes is included in appendix D, it is fast enough for practical purposes, feel free to use it or learn from it.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

2 Setting Up

2.1 VESA function calls

-----------------------

VESA has defined function calls in what they call the VGA BIOS Extension. That is, the functions are simply an extension of the standard set of VGA BIOS functions. So you call them the same way you would any other VGA BIOS function, with interrupt &H10. All VESA function calls are prefixed with &H4F, you can have a look at them in appendix C.

2.2 Detecting the VESA

----------------------

The first thing you have to do to use VESA SVGA graphics is make sure that the computer can handle it. This is done by calling VESA function &H00. If the VESA is present then it will return &H4F in AX and will fill an array with info on the VESA. The following variable type is used.

    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

For full details on what each field means see appendix A. None of them are important for the basic VESA SVGA program.

Anyway, here is what you have to do to detect the VESA. Sample code will be provided in Part III.

  1. DIM a variable of type VgaInfoBlock defined above.
  2. Set AX to &H4F00, VESA function &H00
  3. Set ES to the segment address of the VgaInfoBlock variable.
  4. Set DI to the offset address of the VgaInfoBlock variable.
  5. Generate interrupt &H10, make sure you use CALL INTERRUPTX because ES is used.
  6. Check the value returned in AX, if it is &H4F, the VESA is present, any other value and it is not.

2.3 Setting a screen mode

-------------------------

Once you have confirmed the presence of VESA support, the next step is to set a mode. For a list of VESA defined screen modes see appendix B. The set SVGA mode function is function &H02. You will also need to run function &H01 to return info on the mode. Like function &H00 it will fill a variable with info, this time on the screen mode. The following is the type definition for the info returned by function &H01.

    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
        WinFuncPtr 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
        Rsvd 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
        DirectColorModeInfo AS STRING * 1
        Reserved AS STRING * 216
    END TYPE

For a complete description of what everything is, wait for Part III of this series. The important fields are as follows.

So, anyway, when setting an SVGA screen mode, the following should be done. Again, sample code will be available in part III.

  1. DIM a variable of type ModeInfoBlock.
  2. Set AX to &H4F01, VESA function &H01.
  3. Set CX to the mode number (listed in appendix B).
  4. Set ES to the segment address of the ModeInfoBlock variable.
  5. Set DI to the offset address of the ModeInfoBlock variable.
  6. Generate interrupt &H10, remember to use CALL INTERRUPTX for ES.
  7. Check (ModeAttributes AND 1), this should be 0.
  8. Set AX to &H4F02, VESA function &H02.
  9. Set BX to the mode number.
  10. Generate interrupt &H10.
  11. Check the value returned in AX, it should be &H4F.

I can always be reached by posting a message on the www board at my website, the address is www.geocities.com/SiliconValley/Peaks/9572/ Also go there for more demo code on using SVGA in QuickBasic as well as many other useful routines and fun games.

Appendix G - Works Cited

------------------------

Super VGA BIOS Extension, Standard #VS911022, October 22, 1991, Document Version 1.0, VBE Version 1.2.

(this is a 3 part document. All code references from appendices will be included in Part III- ed)

That’s all for this time. Next issue, we’ll look at stuff like bank switching and what ports you can use to get a set resolution and number of colors, as well as page flipping.

Back to Top




This tutorial originally appeared in QBasic: The Magazine Issue 1.