home *** CD-ROM | disk | FTP | other *** search
-
- ─────────────────────────────────────────────────────────────────────────────
-
- VGOVBE20.TXT - Vesa 2.0 implementation, activation, and just plain how
- it works.
-
- ─────────────────────────────────────────────────────────────────────────────
-
- Doc by: Vector/Vertigo
- Code by: TimJ/Vertigo
-
- If I were TimJ a quote would go here....
-
- Vertigo Webpage = http://demoscene.interstat.net/~vertigo/
-
- email: tim@legend.co.uk = TimJ
- cowan@gold.guate.net = Vector
- irc: #coders #vertcode
-
-
- revision history:
-
- 24/03/97 v1.0 - Initial version
-
-
- ─────────────────────────────────────────────────────────────────────────────
- INTRODUCTION
- ─────────────────────────────────────────────────────────────────────────────
-
- Well, it's been about a month since TimJ released vgophong.doc, and we
- decided it was time to release a few more tutorials (two in fact). These
- tutorials should be pretty messed up, since I am writing a tutorial on
- TimJ's Vesa code, and he is writing one on my faith code ;).
-
- The reason of this tut is because lately the trend has been moving on to
- Vesa 2.0. Vesa 2.0 is a standard that enables all cards to be able to do
- certain acts, using the same exact functions. These commands are quite basic,
- but very powerful. One can use high resolutions and high colors, just as easy
- as writing to the normal VGA mode 13h.
-
- Unfortunately, there is no good documentation out there on how to set
- the Vesa 2.0 modes ( which are a little harder to set than mode 13h ;).
- There are a few libraries out there that give the user the functions to set
- Vesa 2.0. But obviously most people out there don't want to have to kludge
- in someone elses libraries just to use this. Also, many people who do manage
- to set the modes, notice that for some reason their code is very buggy.
- This is usually because they forgot to set LFB, remap the LFB, check to see
- if the mode is available, or even if they are setting the right mode.
-
-
- ─────────────────────────────────────────────────────────────────────────────
- BEFORE WE START
- ─────────────────────────────────────────────────────────────────────────────
-
- This TXT assumes that you have knowledge of working with VGA mode 13h and
- protected mode. Also, some knowledge of assembler would be beneficial =).
- The PMode Header you use MUST support DPMI function 800h. (DOS32 Free Version
- does not=( ).
- If you want to use the included source, you should have an assembler (it
- has been tested with TASM 3.1 and TASM 5.0). But just in case, I have also
- included an .OBJ file. Also included is a C header file, so that this may
- be included in your C/C++ programs. Finnally, a 2 short C programs have been
- included, to show a bit on the use of the code (They have been tested with
- Watcom C 10.5a and 10.6).
- Also, This Document and its companion code is provided free, and as-is.
- Put all that other disclaimer junk here too... oh, if any harm comes to your
- machine from this, then send flames to president@whitehouse.gov . We are not
- responsible =).
-
-
- ─────────────────────────────────────────────────────────────────────────────
- WHAT WE WANT
- ─────────────────────────────────────────────────────────────────────────────
-
- First lets ask ourselves, what would the perfect Vesa 2.0 mode setting
- library do for us? Well this is what we need:
-
- A) Most important, we want usage of an LFB (Linear Frame Buffer). This
- allows us to write to video memory just as easy as writing to mode 13h.
- I read in imphobia that All PCI video cards support LFB, and most cards
- found on 486's support it, so requiring support for bank switched
- modes should not be neccessary (Thank god).
- B) We want to remap this LFB to usable memory. Most times the Vesa mode
- will work without doing this, but we should do this to get 100%
- compatibility.
- C) We also want good error detection. Like selecting an unavailable mode,
- and detecting to see if Vesa 2.0 is available.
- D) The interface should be easy & intuitive. Instead of selecting a mode,
- we should pass an X resolution, Y resolution, and Bit Depth. Not only is this
- easier, but the vesa standard states that modes do not need be static. So in
- the future, mode 147h may not always be 320*240*32Bits.
- E) We want to receive as much information as possible. We want to know how
- many bits are R,G, and B, where they start, and what order they are in.
- we want to know how much available video memory there is, etc....
-
- ─────────────────────────────────────────────────────────────────────────────
- WHAT TO DO
- ─────────────────────────────────────────────────────────────────────────────
-
- Okey, first, lets lay out the functions we are going to make:
-
- -= VBEINFO *vbeDetect(void) =-
- This will detect to see if Vesa 2.0 is available, and return information
- on the video card.
-
- -= long vbeGetModeInfo(int mode,VBEMODEINFO *bla) =-
- This will get every bit of info on a video mode, resolution, depth, video
- window stuff, bit organizing, etc... and return it into bla. It will return
- a 1 on success (Mode found, etc..) and 0 on failure.
-
- -= VBESURFACE *vbeOpen(long X,long Y,long BPP) =-
- This will actually set the mode. It will set an X*Y*BPP mode (BPP being
- bits per pixel, not bytes). It will return a pointer to VBESURFACE,
- containing the location of LFB, the actual mode number, bits & bytes per
- pixel,etc...
-
- -= vbeClose(VBESURFACE *bla) =-
- Of course we need to close the mode. This will get rid of all the vbe stuff,
- and return us to good old mode 3h.
-
- -= vbeSetScanWidth(long width) =-
- This function will set the logical scanline width of video memory. This way
- we can set how far we can horizontally scroll. Remember, to set a pixel its
- (x+(y*logicalWidth)) not (x+(y*screenWidth)) Unless you make them the same.
- Which for starting out, we will. We will set this in pixels.
-
- -= long vbeGetScanWidth(void) =-
- This function returns the logical scan width. We will get this in pixels.
-
- -= vbeSetStart(long X,long Y) =-
- This will flip the screen to a certain X and Y position in video memory.
- Very usefull for page flipping and scrolling.
-
- -= vbeGetStart(int *X, int *Y) =-
- This will return the screens logical X & Y position in video memory.
-
- -= vbeVR() and vmode(int mode) =-
- Complimentary functions that wait for the vertical retrace (So there is no
- screen shearing) and set a standard vga mode respectively.
-
- ─────────────────────────────────────────────────────────────────────────────
- LETS START THE CODE
- ─────────────────────────────────────────────────────────────────────────────
-
- Please note, I will not list the structures here, as they are VERY commented
- in the code, and quite large. I also won't go through the code step by step,
- but rather explain what is happening. I would recommend either printing the
- code up, or having it on hand in another window.
- Also note that we are going to be calling most functions through real mode,
- this is because many VBE functions require the real mode trait of passing
- pointers through ES:DI.
-
- DPMI Interrupts
- ~~~~~~~~~~~~~~~
- First, I should probably list the DPMI interrupts we are going to use:
- (All DPMI interrupts use INT 31h)
-
- -= Allocate Dos Memory =-
- AX = 0100h
- BX = # of paragraphs to allocate. (A paragraph is 16 bytes)
- Returns:
- AX = Real mode segment of Block.
- DX = Selector for the allocated block.
- CF = 0 on success,1 on error
-
- We are going to need this function to allocate memory for our information
- blocks. Like VBEINFO and such.
-
-
- -= Free Dos Memory =-
- AX = 0101h
- DX = Selector of Block
- Return
- CF = 0 on success, 1 on error
-
- Free the memory we just allocated of course.
-
-
- -= Simulate Real Mode Interrupt =-
- AX = 0300h
- BL = Interrupt number
- BH = should be kept to 0.
- CX = Number of words to copy from protected to Real mode stack.
- ES:DI = selector:offset or RM structure (See RMREGS in asm code)
- Returns:
- RMREGS = Filled with return info
- CF = 1 on error, 0 on success
-
- We need this function to make real mode calls from protected mode.
-
-
- -= Physical Address Mapping =-
- AX = 0800h
- BX:CX = Physical address we want to map.
- SI:DI = Size we want to map
- Return:
- CF = 0 on success, 1 on error
- BX:CX = linear address that maps the memory
-
- This function is very helpfull, because it lets us write to memory we
- normally wouldnt be able to reach. Since a video card mey be crazy
- enough to put its LFB out there ;).
-
-
- - Free Physical Address Mapping -
- AX = 0801h
- BX:CX = Address returned by function 0800h.
- Return
- CF = 0 on success, 1 on error.
-
- Free up the memory we mapped, like the good coders we are =).
-
- VBE Interrupts
- ~~~~~~~~~~~~~~
- Now that we have the DPMI interrupts out of the way, I will state the VBE
- interrupts we will be using. Remember that some of them will be called
- through a real mode interrupt. All Vesa interrupts use INT 10h.
- VBE instructions will always return 04Fh in EAX. if a VBE function does not
- return this, it means there was an error (VBE driver not loaded and such).
-
- -= Return VBE controller Info =-
- AX = 4F00h
- ES:DI = Pointer to 512 Allocated bytes to put VbeInfoBlock
-
- This function will put a lot of info about the video card into a VbeInfoBlock
- pointed to by ES:DI (So it needs to be called from real mode).
- Remember to set VbeSignature inside VbeInfoBlock to 'VBE2'. This will tell
- the interrupt that we want vbe2.0 information returned. After the Int is
- called, 'VESA' should be returned in VBE Signature. To see everything
- returned, check the VbeInfoBlock structure in the code.
-
-
- -= Return VBE Mode Info =-
- AX = 4F01h
- CX = Mode Number
- ES:DI = Pointer to ModeInfoBlock structure.
-
- This will fill up a ModeInfoBlock pointed to by ES:DI (also needs to be
- called from RM) with all sorts of goodies about the mode in CX. To see
- everything returned, please check ModeInfoBlock structure inside the code.
-
-
- -= Set VBE Mode =-
- AX = 4F02h
- BX = Mode Number. Bits 9-13 must be 0. OR bit 14 with 1 to indicate we
- want to use LFB. OR bit 15 with 1 to clear video memory.
-
- Here is the Actual meat of the modeSetting. You will notice that there is no
- structure passed here. That is because all the info on the mode is obtained
- through Function 4F01h (Like LFB location and stuff).
- Notice that since we don't need to pass info through ES:DI this function can
- be called Directly.
-
-
- -= Get/Set Display Start =-
- AX = 4F07h
- CX = First Displayed Pixel Scanline (X pos)
- DX = First Displayed Scanline (Y pos)
- BH = Must be kept to 0
- BL = 0 to set display, 1 to get display, 80h=Set during V. Retrace.
- Return:
- AX = VBE return status (Returned in ALL functions)
- BH = Always 00h.
- CX = First Displayed Pixel Scanline (On get display)
- DX = First Displayed Scanline (On get display)
- Imagine the screen as a small rectangle, held completely inside a larger
- rectangle (video memory). This function will move the little rectangle around
- the big rectangle very smoothly. This allows such things as page flipping,and
- scrolling at very high speeds. This same function is also used to get the
- location of the screen in memory, by setting BL to 1.
-
- -= Get/Set Logical Display Width =-
- AX = 4F06h
- BX = 0 to set width in pixels, 2 to set width in bytes,
- 1 to get width, 3 to get maximum width.
- CX = Width in pixels (Or bytes, depending upon BX) to set width.
- Return:
- AX = VBE return status (returned in ALL functions)
- BX = Width in bytes of scanline.
- CX = Width in pixels.
- DX = Maximum number of scanlines.
- This sets or gets the width we want the big rectangle of video memory holding
- our screen to be. This way we can scroll horizontally as well as vertically.
- The only problem with this is that finding Y coordinates varies with the
- logical scanline width. (PixelPos= x+(y*LogicalWidth))
-
- ______________________
- Whats In The Functions
- ~~~~~~~~~~~~~~~~~~~~~~
- It feels good to get all those damn interrupts out of the way. Now I can
- safely explain all the functions in pseudocode. After this, you should be
- able to piece the actual ASM code together with this pseudocode quite
- smoothly.
-
- -= VBEINFO *vbeDetect(void) =-
- start:
- 'DPMI 100h' Get memory to put vbeInfo Block into
- Ready RmRegs for 'VBE 4F00h'
- Put VBE2 into vbeInfo.VbeSignature
- 'DPMI 300h' Call VBE 4F00h in real mode.
- Check to see If everything ok.
- 'DPMI 101h' Free the vbeInfoBlock
- end:
-
- -= int vbeGetModeInfo(int mode,VBEMODEINFO *bla) =-
- start:
- call VbeDetect JIK
- 'DPMI 100h' Get memory to put modeInfo Block into
- Ready RMREGS for 'VESA 4F01h'
- 'DPMI 300h' to call VBE 4f01h in real mode
- move everything from modeInfo Block to bla
- free modeInfo Block with 'DPMI 101h'
- return Success
- End:
-
- -= VBESURFACE *vbeOpen(int X,int Y,int BPP) =-
- start:
- Make sure we arent already in a vesa mode
- call VbeDetect JIK
- 'DPMI 100h' to allocate for ModeInfo block (To check every available mode)
- Go through all available modes returned by VbeDetect until finding a match
- OR the Mode found with 4000h to say we want LFB
- If It worked, map the LFB memory to accessible memory with 'DPMI 800h'
- Set vbeInit variable so from now on we know a mode is set
- Make sure logical scanline width is equal to screen scanline width.
- Set everything in the return structure
- end:
-
- -= vbeClose(VBESURFACE *bla) =-
- start:
- Check to see if a vbe mode is set
- Free the mapped LFB memory with 'DPMI 801h'
- Set VGA mode 0x3h
- end:
-
- Almost direct functions:
- -= vbeSetScanWidth(int width) =-
- Set logical screen width in pixels, with 'VBE 4F06h'
- -= int vbeGetScanWidth( void) =-
- Get logical screen width in pixels, with 'VBE 4F06h'
- -= vbeGetStart(int *X, int *Y) =-
- Get logical screen pos with 'VBE 4f07h'
- -= vbeSetStart(int X, int Y) =-
- Set logical screen pos with 'VBE 4f07h'
-
-
-
- We are done with the Code!
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- Well, you should be able to piece everything together by now. If not, don't
- worry, take a breather and read over a nice refreshing 386 asm manual with a
- nice glass of pepsi.
-
-
- ─────────────────────────────────────────────────────────────────────────────
- NOW HOW DO I PUT THE CODE IN?
- ─────────────────────────────────────────────────────────────────────────────
-
- Now that you have the asm at hand, and understand it, it is time to get using
- Vesa 2.0. First, lets get the thing to compile. It should go in as easy as
- a snap of your fingers, just include the ASM in your makefile, or the .OBJ
- in your project file (Or .asm if the project manager is set to a compatible
- assembler). After that, just include the .h in your C files. If you want to
- use the functions in other ASM programs, make sure to mark them as External
- wherever you use them.
- If you get any troubles with tasm, the switches I use are:
- tasm -q -p -t -ml -zi -m3 vgovbe20
- To compile the simple C example file, if you have Watcom, you can run
- M.bat and then run test.exe.
-
- ─────────────────────────────────────────────────────────────────────────────
- COOL! IT COMPILES! NOW HOW DO I USE THEM?
- ─────────────────────────────────────────────────────────────────────────────
- Well, ill explain how in C (Im sure everyone who uses ASM can figure this
- out ;). First off, you probably want to call vbeDetect, to see if everything
- is in there fine.
- After that, we can set any mode with ease. Just make sure to have
- VBESURFACE *myScreen; defined. (Make sure to see the VBESURFACE struct
- in the .H file).
- After that, just call myScreen = vbeOpen(X,Y,BPP);
- X=The x resolution you want, Y=duh, BPP is the bits per pixel to use.
-
- --BPP can normally be one of:
- 4 = 16 palleted colors,
- 8 = 256 palleted colors,
- 15 = 5.5.5.1 RGBA colors.
- 16 = (Arbitrary, but I think UniVBE always sets this to 5.6.5) RGB colors
- 24 = 8.8.8 RGB Colors.
- 32 = 8.8.8.8 RGBA colors.
-
- To actually plot a pixel is as simple as writing to mode 13h, except the
- screen isnt static at 0A0000h. Just get the screen pointer from myScreen.LFB;
- after that, you are free to play around =).
-
- --Lets do a few Experiments with High/True color:
- Remember how in paletted 13h to write a white pixel, you would get whatever
- palette entry was white and write that? Well now you basically write that
- palette straight to the screen.
- In 24bit mode, the screen is layed out as:
- byte =0,1,2,3,4,5,6,7,8 957,958,959
- |B G R|B G R|B G R|...............|B G R|
- pixel= 1 , 2 , 3 , 319
-
- So, to write a white pixel to the screen in 24 bit value, you would do:
- (char *)(myScreen)[0]=255; //Write Blue value of pixel 0
- (char *)(myScreen)[1]=255; //Write Green value of pixel 0
- (char *)(myScreen)[2]=255; //Write Red value of pixel 0
- //Next pixel starts at [3], if 32bit mode, next pixel would be at [4].
-
- You probably noticed 2 things. One is that the screen is layed out with first
- byte being B, then G, then R (Instead of RGB) (Some cards have the ability to
- flip this around, but I have never come across this, same as non 565 16bit
- modes. just to be safe, check the mode after you set it). Another thing is
- that 24bit mode is a bitch. It's no fun having to write byte by byte.
- Thats why 32Bit mode was invented, it is much faster, because you can write
- a Dword at a time, except you have that Alpha byte at the end. (An alpha byte
- is a padding byte, this byte doesnt neccessarilly need to be wasted memory,
- You can store many things in here if you put your mind to it).
- Anyways, to set a white pixel in 32bit mode, you can do this:
- (long *)(myScreen)[0] = 00FFFFFFh
- Whats real cool, is that you can set the pixel real easy in hex, by splitting
- the number up like so:
- |00 |FF |FF |FF |
- A R G B
- To use high color (15/16 bit modes) Is a tiny bit trickier, but if you use
- them right, they can actually be faster since there is much less data to
- move.
- A white pixel in 16BIT mode= (short *)(myScreen)[0] = FFFFh
- and 15bit mode= (short *)(myScreen)[0] = 7FFFh (can also be FFFFh).
- The formula to convert a 24bit pixel to a 16bit pixel is:
- (short *)(myScreen)[0] = ((char *)(yourScreen)[0]>>3) |
- (((char *)(yourScreen)[0]<<3)&7E)|
- (((char *)(yourScreen)[0]<<8)&F8);
- It may seem annoying at first, but once you get it integrated into your
- functions it starts to become automatic. (Just don't call a 24to16bit
- conversion every pixel!)
- One last cool thing I want to mention, is that you can do REAL fast 50%
- transparencies in True/High color using bit-wise operations. Simply do this:
- For 32Bit mode:
- --------
- //PixelA = source pixel. PixelB=Destination pixel
- pixelA >>=1; //Divide the pixel values in half
- pixelB >>=1;
- pixelA &=0x7F7F7F7F; //Clear the residual bit
- pixelB &=0x7F7F7F7F;
- //By now pixelA & Bs maximum R,G,and B values are 7F=127 out of 255.
- pixelB +=pixelA;
- //Now pixelB is equal to A+B transparency.
- -------
-
- For 16Bit mode:
- --------
- //PixelA = source pixel. PixelB=Destination Pixel
- pixelA >>=1; //Divide the pixel Values in half
- pixelB >>=1;
- pixelA &=0x7FEB; //Clear the residual bit
- pixelB &=0x7FEB;
- //By now pixelA & Bs maximum R,G,and B values are 7F=127 out of 255.
- pixelB +=pixelA;
- //Now pixelB is equal to A+B transparency.
- -------
-
- With this you can do many effects, such as Motion Blur (By recursively making
- one screen transparent over the other with 2 screen buffers, and fliping
- which one you write to). Or quick transparencies.There are many other effects
- you can do with bitwise operations, Enjoy =). Thanks very much to Brazil for
- showing me this previous technique when I started Vesa coding last year.
-
-
- ─────────────────────────────────────────────────────────────────────────────
- WELL, IM ALL SET TO GO, ANYTHING ELSE I SHOULD BE AWARE OF?
- ─────────────────────────────────────────────────────────────────────────────
-
- Yes actually, a few things:
- A) Even though it's not neccessary, you should do a vbeGetModeInfo mode after
- you set a mode, do this to ensure a few things: If you are doing a 16bit mode
- to, see if it's 5.6.5(if not either quit, or adjust your functions) And check
- to see if the screen is ordered BGR not the other way around. I have actually
- never encountered these problems, but there are cards that have options to
- change this, and VBE specs say it is liable to happen. (Although I think
- UNIVBE always makes this BGR & 5.6.5)
- B) Under most cases, write to an Offscreen buffer and copy to screen. This
- is because reading from video memory is PAINFULLY slow. Here is where the
- biggest benefits of using 16bit VS 32bit pay off.
- C) If you are going to clear the screen, I have found it much faster to clear
- with the FPU. Although copying with FPU seems to be slower (Because of
- reading Invalid FPU numbers (NaN)). Try and see, different people get
- different results.
- D) UniVBE is actually real nice, It does many things for you like make sure
- LFBs are Always available, for any and every card. It also makes sure 16bit
- modes are always 5.6.5 and data is organized in BGR fashion. Univbe does have
- an option for switching this... but thats the users fault ;).
-
-
- ─────────────────────────────────────────────────────────────────────────────
- HOW COULD I MAKE THIS VBE20 LIBRARY BETTER?
- ─────────────────────────────────────────────────────────────────────────────
-
- Well, many ways. I originally set this document to teach VBE mode setting
- only (VBE function 4f07h was just a bonus ;). There are still many ways you
- can make this better:
- A) We had an A), but we put this in for you, ain't that sweet? =).
- B) Get support for VBE/AF (accelerator functions) in there. Unfortunately
- we haven't been able to try these out since uniVBE currently only provides
- this for the MACH64 video card. These functions should allow us to use
- 3D and 2D accelleration features as easily (?) as setting vesa modes are now.
- C) Actually make it a library ;) This is by far not complete. Add function
- pointers to different 2D primitives according to the mode. Or go full steam
- ahead and make a full OOP engine. The sky is the limit.
-
-
- ─────────────────────────────────────────────────────────────────────────────
- THE LAST WORD
- ─────────────────────────────────────────────────────────────────────────────
-
- It's now 5:30AM and I haven't slept for like 24 hours, so I better go get
- some coffee and stay awake... just not writing tutorials where not writing
- coherently can make universes collide. Wow... the keys on my keyboard look
- all fuzzy and wavy... must 7BEF em... This is the reason there were no
- ASCII pictures in here =). Hopefully the descriptions where good enough
- where you did not need them.
- If you got any use out of this Tutorial or this code, make sure to email us
- and/or greet us in your productions, it's all we ask =). If you want more
- information on the VBE, make sure to download the oficial VBE specs at
- www.scitechsoft.com and many other popular places. If you want more help,
- I have released the source to my truecolor 4K intro 'Faith', which should be
- available on hornet (ftp.cdrom.com/pub/demos). This intro shows how to do
- more advanced true-color tricks than the included test.c.
- Finally I want to thank TimJ for giving me the original VBE code way back,
- which helped me through a lot of bugs that would have taken a long time to
- figure out otherwise. All the attached code was done by him, and without it,
- this DOC probably wouldn't have existed.
-
- Greets:
- Everyone else In Vertigo, Vastator the typo tamer(Just a little too late)
- Midnight, Fysx, Phred, GooRoo, Vor, Brazil, God, MrData, Grimace...
- These fly out to many people, please check the our web pages greet list,
- being greeted in there is just as good as being greeted in all of our
- productions ;).
-
- Peace & Werd or something...
- Vector/Vertigo
-