The first part of the VBE 2.0 LFB demo is ready. Nothing exciting on the surface, but there's a lot going on behind the scenes.
The development environment I used was DOSBOX, which as you may know is a DOS emulator. The following link is to a zip file with all the files necessary to develop the VBE demos. The folder can be mounted in DOSBOX, and run. The files can be copied to a native, or emulated, DOS installation. Note, you'll need to provide an e-mail address, otherwise filehosting.org will make you download a client (which you don't want to do :P)...
VBE development environment
DEMO1.C sets VBE graphics mode 640x480 at depths of 8-BPP (256 colors), 15-BPP (32768 colors), 16-BPP (65536 colors), 24-BPP (16.8 million colors), 32-BPP (16.8 million colors with a padding byte).
I didn't have a chance to test the 24-BPP screen clear, but am reasonably confident that it works. The 24-BPP SetPixel should not have any issues though. By the third demo, I'll dig up an old computer and set it up for 24-BPP testing :)
Note that a real mode Seg:Ofs can be converted into a linear address as follows: LinAddr = (Seg * 16) + Ofs. This is valid for 32-bit Flat Protected Mode. Segmented 32-bit Protected Mode may require a couple of extra steps. According to the VBE spec, the extra steps include getting the base address of the program's data selector, then subtracting it by the Linear Mapped Physical Address.
Using VBE in 32-bit Protected Mode depends heavily on DPMI services. Your OS will need to provide equivalent services.
vbectx_t
This structure holds the required information needed to draw graphics. VBEDriverInfo_t and VBEModeInfo_t contain a lot of information that is typically only used once.
Of note are fields rshift, gshift, bshift, and ashift. These values are the number of LSBs that need to be shifted for a more correct RGB value. These values are non-zero in 15-BPP and 16-BPP display modes.
The rmask, gmask, bmask, and amask fields store bit masks in the exact position where the component lies in the encoded pixel. These fields are used in 15/16/24/32-BPP display modes. EncodePixel uses component masks to remove bits which overlap with other component bits. DecodePixel uses component masks to isolate specific component bits.
vbe_SetPal()/vbe_GetPal()
Under DOS the palette DACs interpret RGB component values as 6-bits. By writing 0xFF to port 0x3C6, the palette DACs interpret RGB component values as 8-bits. The catch, apparently, is that not all video cards support changing the palette DAC mask size. What I do instead is shift the LSB of each RGB component by 2. [7][6][5][4][3][2][1][0] -> [-][-][7][6][5][4][3][2]
demo1_Run8()
The display mode is set to 640x480x256 colors. As you already may know, RGB values are used indirectly, so each pixel is actually a color index into a palette. Setting two RGB values is the equivalent of encoding two pixels in higher bit depths.
demo1_Run15() and demo1_Run16()
The display mode is set to 640x480x32768 and 640x480x65536, respectively. 15-BPP and 16-BPP modes are run separately, however, both depths use two bytes per pixel. As a result, they can use the same graphics functions.
In the Real World, most people test for specific cases of RGB pixel formats, such as A1_R5_G6_B5, in order to mask by constants and shift by constants -as opposed to referencing a pointer, to retrieve a value, to store the value into a register, to finally manipulate the pixel.
demo1_Run24_32()
The display mode is set to 640x480x16.8M. If the bit depth is 24, then 24-BPP graphics functions are used. Otherwise, 32-BPP graphics functions are used. For some reason, VESA separated 15-BPP and 16-BPP modes, but not 24-BPP and 32-BPP modes. New display modes exist specifically 32-BPP, but they are graphics card specific since VESA stopped pre-defining video modes.
The basic process to use VBE 2.0+ LFB follows:
1) Get mode information and test a specific ModeAttributes bit to confirm whether or not LFB is supported.
2) Create an LDT selector, set the granularity and access rights to read/write, set the base address to the mapped linear address.
3) Map the physical address into a linear address.
4) Set the LDT selector base address to the LFB linear address.
5) Set display mode to specified LFB mode.
6) Use the LFB pointer like a data pointer.
With VBE 2.0+ LFB (Linear Frame Buffer), you only need the BIOS to set the display mode.
Hopefully, you'll find this information useful so far. I've always wanted to write a tutorial on VBE graphics, so please feel free to ask if you (or anyone reading this) has any questions.
The following links to references I used to write the demo:
Dr Dobb's Journal: Using the VESA BIOS 2.0 Linear Frame Buffer
VBE 3.0 Specification (hosted by 3rd party)
Inverse Reality: Setting the VGA Palette
Inverse Reality: Setting VESA Video Modes