VESA v1.2 thru v2.0 Programming Created : Nov 23/96 Updates : Nov 24/96 Updates : Nov 28/96 Updates : Sept 24/97 Table of Contents •Intro •Reference of all VESA functions •Appendix A : Tables •Appendix B : Logical/Physical scan lines •Appendix C : Banking vs. Linear Frame Buffer •Appendix D : Examples •Sources Notice : First a little note, do not get VESA VBE (Video BIOS Extensions) confused with VESA local bus. They are two totaly different things. VESA VBE is a device-independant way of using your video card, wether it be ISA, EISA or PCI or VLB. The VESA local bus (VLB) is a type of slot. VESA functions are all called by loading registers as needed, loading ah=4fh and calling INT 10h in real mode. There are advanced funcs that can be called in PMODE which will be discussed later. This tutor is intended for using VESA VBE 2.0+ but will show when functions require VBE 2.0. It also does not explain in detail things you need not worry about. If you want more information then consult the VBE20.ZIP file in my Files Page. 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 dl0h) 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) BACK