Func 0h : Get VBE information
in : ax = 4f00h
es:di = ptr to buffer for VbeInfoBlock
out: ax = VBE status
Notes:
) The buffer must be 256 bytes for VBE 1.x.
) If the 1st four bytes in the buffer are 'VBE2' then the buffer must be 512
bytes and will be filled in with VESA 2.0 info.
) There are bugs in VBE 1.x that will copy more that 256 bytes of info to
the buffer so even if you plan on using just VBE 1.x make your buffer is 512
bytes just in case.
Func 1h : Get VBE mode information
in : ax = 4f01h
cx = mode #
es:di = ptr to buffer for ModeInfoBlock
out: ax = VBE status
Notes:
) The info block contains info such as the modes x,y and colour depth. What
the windows size is, if it supports linear mode and/or banking mode. etc...
Func 2h : Set VBE mode
in : ax = 4f02h
bx = bit 0-8 : mode # (0h thru 1ffh)
bit 9-13 : Reserved (must be 0)
bit 14 : =1 use linear/flat frame buffer model (VBE 2.0+ only)
=0 use windowed/banking frame buffer model
bit 15 : =1 clear display memory
=0 don't clear memory
out: ax = VBE status
Notes:
) Under VBE 1.x you could assume a video mode such as 010fh to always be
video mode (320x200x24bit), but under VBE 2.0 this is no longer true!!!
Under VBE 2.0 BIOS's are suppose to use 1 byte video modes (for good
reasons) but they should still support the 2 byte modes. So therefore
when using VBE you should check every mode avail until you find one that
suits the x,y and colour depth you need. Use func #0 to find avail modes
and func #1 to get info on each mode.
) If bit 14 in bx is set (use linear mode) and the video mode does not
support linear mode then this bit is simply ignored and banking mode is
used. It is up to you to make sure the mode supports linear mode. Func #1
can be used to determine if the mode support linear mode.
Func 3h : Get current VBE mode
in : ax = 4f03h
out: ax = VBE status
bx = Curret VBE mode (same as given to func #2)
Notes:
) The value returned in bx will be EXACTLY as given in func #2 included bit
14 and 15.
Func 4h : Save/restore state
in : ax = 4f04h
dl = 0 - get buffer size required for state info
1 - Save state
2 - Restore state
cx = bit 0 : save/restore controller hardware state
bit 1 : save/restore BIOS data state
bit 2 : save/restore DAC state
bit 3 : save/restore Register state
es:bx = ptr to buffer (if dl<>0h)
out :ax = VBE status
bx = # of 64byte blocks required for state buffer (if dl==0h)
Notes:
) DO NOT USE THIS FUNC. Although this function looks so powerful it's full
of too many bugs. Many BIOS's do not support it and many VBE Extenders
(such as UNIVBE or Display Doctor) do not either. It's too risky using it.
Func 5h : VBE display-window control
in : ax = 4f05h
bh = 0 - set memory window
1 - get memory window
bl = 0 - window A
1 - window B
dx = window # in VRAM in window-granularity units (if bh==0)
out: ax = VBE status
dx = window # in window-granularity units
Notes:
) This is used in windowed/banking mode to make the windows point to certain
areas of the VRAM. This func should not be used in linear buffering mode.
Most of the time (but not always) window A is at 0a0000h (linear address)
in system RAM and the window is 64K in size.
But not always, the Window segments and size can be found by func #1.
Func 6h : VBE set/get logical scan-line length
in : ax = 4f06h
bl = 0 - set scan-line length in pixels
1 - get scan-line length
2 - set scan-line length in bytes (VBE 2.0+ only)
3 - get maximum scan-line length (VBE 2.0+ only)
cx = desired pixels or bytes (only if bl==0 or bl==2)
out: ax = VBE status
bx = bytes per scan line
cx = actual pixels/scan line (truncated to nearest pixel)
dx = max # of scan lines
Notes:
) This is used to change the logical scan line length. This can be equal
to or bigger than the physical scan line length.
Physical scan line length = x * y * bytesperpixel
Func 7h : VBE set/get display start
in : ax = 4f07h
bh = 0 (reserved and must be 0)
bl = 0 - Set display start
1 - get display start (VBE 2.0+ only)
80h - set display start during vertical retrace (VBE 2.0+ only)
cx = 1st displayed pixel in scan line (if bl==0 or bl==80h)
dx = 1st displayed scan line (if bl==0 or bl==80h)
out: ax = VBE status
Notes:
) This is used to set/get the starting point in VRAM where the video card
should consider as the top left most corner of the output screen. Good for
scrolling and shaking the screen.
Func 8h : VBE set/get palette format
in : ax = 4f08h
bl = 0 - set DAC palette format
1 - get DAC palette format
bh = desired # of bits of colour per primary (if bl==0)
out: ax = VBE status
bh = curret # of bits of colour per primary
Notes:
) This applies to 256 colour modes only
) bh may be from 6 to 8
) Each time you set a mode this is reset to 6.
Func 9h : VBE set/get palette data (VBE 2.0+ only)
in : ax = 4f09h
bl = 0 - set palette data
1 - get palette data
2 - set secondary palette data
3 - get secondary palette data
80h - set palette during vertical retrace with blank bit on
cx = number of palette registers to set/get
dx = 1st palette register to update
es:di = buffer for palette
out ax = VBE status
Notes:
) I do not know how the secondary palette is used.
) The buffer is as follows:
1 byte for alignment (ignored)
1 byte for red
1 byte for green
1 byte for blue
Func 0ah : VBE get protected mode interface (VBE 2.0+ only)
in : ax = 4f01h
bl = 0 (return PMODE table)
out: ax = VBE status
es:di = real mode seg:off of table
cx = size of table (including code)
Notes:
) The table returned contains the address of a PMODE functions that can be
used to call func # 5,7 and 9. This table/code and everything in the
buffer is relocatable so you could copy it to your code segment and use it
from there for greater speed.
) Make sure to check the status (ax) register to check if this func is
supported.
) The table is as follows:
Offset Size Description
------ ---- -----------
00h word Offset in table of Protected mode code for Function 5
02h word Offset in table of Protected mode code for Function 7
04h word Offset in table of Protected mode code for Function 9
06h word Offset in table of Ports and Memory Locations that the
application may need I/O privilege for.
(Optional: if unsupported this must be 0000h)
? ? Variable remainder of Table including Code
) The Ports and Memory sub-table is as follows:
port dw ?,?,?... ; last entry is 0ffffh
memory dd ? (32bit linear address)
memsize dw ?
...
;last entry is 0ffffh
Examples:
Example 1. For Port/Index combination 3DE/Fh and Memory locations
DE800-DEA00h (length = 200h) the table would look like this:
DE 03 DF 03 FF FF 00 E8 0D 00 00 02 FF FF
Example 2. For only the ports it would look like:
DE 03 DF 03 FF FF FF FF
Example 3. For only the memory locations it would look like
FF FF 00 E8 0D 00 00 02 FF FF
) The code must be called in 32bit PMODE only with a 32bit stack and enough
room for it's operation. You must make sure that certain RAM is accessable
and IO ports as described in the Ports and Memory locations table. I'm
not sure how it access this RAM and the PAL LIB that comes with DOS32
ignores the PMODE functions if any memory is required. I'm not sure if
it can be used under PMODE/W which has a base of zero. Something cool
to find out.
Appendix A : Tables
VBE status :
AL == 4Fh: Function is supported
AL != 4Fh: Function is not supported
AH == 00h: Function call successful
AH == 01h: Function call failed
AH == 02h: Software supports this function, but the hardware does not
AH == 03h: Function call invalid in current video mode
VBEInfoBlock struct ;used in func #0
VbeSignature db 'VESA' ; VBE Signature (or VBE2)
VbeVersion dw ? ; VBE Version
OemStringPtr dd ? ; Pointer to OEM String
Capabilities db 4 dup (?) ; Capabilities of graphics cont.
VideoModePtr dd ? ; Pointer to Video Mode List
TotalMemory dw ? ; Number of 64kb memory blocks
; Following is VBE 2.0+ only
OemSoftwareRev dw ? ; VBE implementation Software revision
OemVendorNamePtr dd ? ; Pointer to Vendor Name String
OemProductNamePtr dd ? ; Pointer to Product Name String
OemProductRevPtr dd ? ; Pointer to Product Revision String
_Reserved_ db 222 dup (?); Reserved for VBE implementation
; scratch area
OemData db 256 dup (?); Data Area for OEM Strings
VBEInfoBlock ends
Notes:
) All pointers are real mode seg:off types.
) The version word is BCD coded. VBE 2.0 is 200h and VBE 1.2 is 102h.
) Under VBE 1.x the buffer is 256 bytes.
) If VbeSignature is 'VBE2' before the call then then VBE2.0 info is
returned and the buffer must be 512 bytes.
) VbeSignature will always be set to 'VESA' upon return (including VBE 2.0)
) Remember that some VBE 1.x BIOS's are buggy so you should always
use 512 bytes. (I believe some VBE 1.x BIOSs filled in 265 bytes or so...)
) Capabilities is as follows:
bit 0 = 0 DAC is fixed width, with 6 bits per primary colour
= 1 DAC width is switchable to 8 bits per primary colour
bit 1 = 0 Controller is VGA compatible
= 1 Controller is not VGA compatible
bit 2 = 0 Normal RAMDAC operation
= 1 When programming large blocks of information to the
RAMDAC use blank bit in Function 09h. i.e. RAMDAC
recommends programming during blank period only.
bits 3-31 = Reserved
) When ever you set a mode the DAC is always set to 6 bits/primary colour
) VideoModePtr is a seg:off pointing to a list of video modes the BIOS 'may'
support. Each mode is 16bits and the list ends with 0ffffh. You must
make sure the mode is available with func #1.
) TotalMemory is the # of 64K blocks totally available. (ie: 256k = 4)
VBEModeInfoBlock struct ;used in func #1
ModeAttributes dw ? ; mode attributes (flags)
WinAAttributes db ? ; window A attributes
WinBAttributes db ? ; window B attributes
WinGranularity dw ? ; window granularity
WinSize dw ? ; window size
WinASegment dw ? ; window A start segment
WinBSegment dw ? ; window B start segment
WinFuncPtr dd ? ; pointer to window function
BytesPerScanLine dw ? ; bytes per scan line
; Following is available if bit 1 of ModeAttributes is set
; Always true under VBE 1.2+
XResolution dw ? ; horizontal resolution in pixels or chars
YResolution dw ? ; vertical resolution in pixels or chars
XCharSize db ? ; character cell width in pixels
YCharSize db ? ; character cell height in pixels
NumberOfPlanes db ? ; number of memory planes
BitsPerPixel db ? ; bits per pixel
NumberOfBanks db ? ; number of banks
MemoryModel db ? ; memory model type
BankSize db ? ; bank size in KB
NumberOfImagePages db ? ; number of images
_Reserved db ? ; reserved for page function
; Direct Colour fields (required for direct/6 and YUV/7 memory models)
RedMaskSize db ? ; size of direct colour red mask in bits
RedFieldPosition db ? ; bit position of lsb of red mask
GreenMaskSize db ? ; size of direct colour green mask in bits
GreenFieldPosition db ? ; bit position of lsb of green mask
BlueMaskSize db ? ; size of direct colour blue mask in bits
BlueFieldPosition db ? ; bit position of lsb of blue mask
RsvdMaskSize db ? ; size of direct colour reserved mask in bits
RsvdFieldPosition db ? ; bit position of lsb of reserved mask
DirectColorModeInfo db ? ; direct colour mode attributes
; Following is VBE 2.0+ only
PhysBasePtr dd ? ; physical address for flat frame buffer
OffScreenMemOffset dd ? ; pointer to start of off screen memory
OffScreenMemSize dw ? ; amount of off screen memory in 1k units
__Reserved db 206 dup (?) ; remainder of ModeInfoBlock
VBEModeInfoBlock ends
Notes:
) ModeAttributes is as follows: (bits set if true)
bit 0 : hareware supports mode (must be checked)
bit 1 : VBE 1.2 extended info available (could be set in VBE 1.0 or 1.1)
bit 2 : TTY Output functions supported by BIOS
(this is rarely set - I said before to make sure this was set but that's wrong)
bit 3 : colour (else monochrome)
bit 4 : grafix (else text)
bit 5 : NOT VGA compatibility
bit 6 : windowed/banking mode available
bit 7 : linear frame mode available
bit 8-15 : Reserved
- When bit 2 is set then the following TTY functions are allowed in the mode
01 Set Cursor Size
02 Set Cursor Position
06 Scroll TTY window up or Blank Window
07 Scroll TTY window down or Blank Window
09 Write character and attribute at cursor position
0A Write character only at cursor position
0E Write character and advance cursor
- If bit 3 is clear (monochrome) then the CRTC is at 3B4h instead of 3D4h.
- If bit 5 is clear (VGA compat) then you may use standard VGA registers.
) WinGranularity : this is really weird but very important. It applies
to banking mode only. Basically when this equals 64, the banks do not
overlap. If this equals 32 then the banks overlap 50% of each other, and
if it is 16 then they overlap 75% of each other, etc...
Here's some code to show how banking should work.
) MemoryModel could be:
00h = Text mode
01h = CGA graphics
02h = Hercules graphics
03h = Planar
04h = Packed pixel
05h = Non-chain 4, 256 colour
06h = Direct Colour
07h = YUV
08h-0Fh = Reserved, to be defined by VESA
10h-FFh = To be defined by OEM
Colour formats:
VBE Version 1.1 and earlier defined Direct Colour graphics modes with
pixel formats 1:5:5:5, 8:8:8, and 8:8:8:8 as a Packed Pixel model
with 16, 24, and 32 bits per pixel, respectively. In VBE Version 1.2
and later, the Direct Colour modes use the Direct Colour memory model
and use the MaskSize and FieldPosition fields of the ModeInfoBlock to
describe the pixel format.
) BytesperScanLine indicates how many bytes are used in VRAM for each
physical scan line. This logical scan line size can be equal to or greater
than the physical one. Therefore you can not assume an image is a
continuous stream of data in VRAM. It could have extra (ignored) data at
the end of each scan line. But this data could be visiable if you use
func #7 (set/get display start)
) NumberofBanks indicates how many banks you can switch to in banking mode.
This should be 1 in modes 0dh-13h.
) Banksize (or WinSize) is size of banking window size in KBs.
This should be 0 in modes 0dh-13h which don't have scanlines.
) NumberofimagePages :(this -1) indicates how many full images can be loaded
into VRAM and then each could be displayed one at a time. (good for
flicker-free animations). ie: 0 means 1 image, 1 means 2 images, etc.
) OffScreenMemOffset & Size indicate what VRAM you are allowed to access out
side of the current active VRAM. Some VRAM is used by the BIOS for holding
info and if you trash it the system can become very unstable. The offset is
a 32bit offset into VRAM and the size is in 1KB units.
) PhysBasePtr is a 32bit linear address to access VRAM in linear frame mode.
Will be 0 if linear mode is not available.
) Win (A/B) Attributes is as follows:
bit 0 : 0 = Single non-relocatable window only
1 = Relocatable window(s) are supported
bit 1 : 0 = Window is not readable
1 = Window is readable
bit 2 : 0 = Window is not writeable
1 = Window is writeable
bit 3-7 = Reserved
) WinFuncPtr can be called to do func #5
Just load regs as if calling func #5 (only bx and dx need be loaded).
This is faster than calling INT 10h for func #5 but using the PMODE
functions is even faster when in PMODE.
Appendix B : Logical/physical scan lines
A physical scan line is exactly what you see on the video screen. But a
logical scan line may be much longer or it could be the exact same length.
Here is what the video memory what look if the logical lines were longer.
+-----------------+---------+
| | |
| | |
| | |
| | |
| | |
| | |
+-----------------+---------+
\ physical length /
\------- logical length ----/
And the physical "visable" area can be shifted left and right to perform
fast scrolling thru the use of VESA func #7.
I myself very use this scrolling though.
Appendix C : Banking vs. Linear Frame Buffer
When the VGA card was first introduced it used a small 64k memory
mapped region at 0a0000h (0a000h:0h). This was fine for the 320 x 200 x 256
video mode, but as higher resoltions were developed more then 64k was
needed to access the video cards memory. So what happened is that banking
was created and now the 64k of memory mapped address space owned by video
cards is a "window" into the video cards memory. And this "window" can
be moved around to point to any bank within the video cards memory. So
the video memory is usually broken up into 64k blocks and the 64k segment
at 0a0000h can be remapped to point to any of the 64k blocks of memory
in the video card by using VESA func #5. Note that each bank of the video
card may not be 64k (an example is given below to show how to handle this).
Scan lines may be divided across banks making copying to VRAM very difficult
and slow. There is also another problem to consider,
when some video modes are setup the logical scan line could be larger
than the phyical scan line by default. So it's a good idea to use set the
logical scan line to the phyical size. I don't
know why, but it may have to do with video card performance. Also remember
that you can not just use any VRAM you feel like. See ModeInfoBlock to see why.
Appendix D : Examples
;init first
bankshift=0;
while (( 64 >> bankshift) != wingranularity) bankshift++;
;to set bank use the following
setbank (int banknum) {
struct REGS in,out;
if (banknum==current_banknum) return;
in.x.ax=5;
in.x.bx=0;
in.x.dx=banknum << bankshift;
int86(10h,&in,&out); //set Window A
in.x.ax=5;
in.x.bx=0;
in.x.dx=banknum << bankshift;
int86(10h,&in,&out); //set Window B
}
Everything is pretty straight forward. Don't forget to convert the linear
address in linear mode to a physical address using DPMI func #800h.
If you found this tutorial confusing then get VBE20.ZIP and you'll get your
socks knocked off! It's a book...
Sources :
1) Dr. Dobbs Journal : July, 95
2) VBE20.TXT : SciTech Labs (can be found in my Files Page)