Hi,

I decided that my operating system needs some graphics. I have seen loads of tutorials on drawing pixels, and I have used some. I now want to use 32bit protected mode (before I was using real mode) and I can't find any tutorials or documentation on drawing with VESA without the bios.

Can anyone point me in the right direction? If I can plot a single pixel, without the bios, I will be happy. :)

Thanks in advance.

Member Avatar for iret

...Can anyone point me in the right direction? If I can plot a single pixel, without the bios, I will be happy. :)...

Since you're using 32-bit Protected Mode to program VBE (VESA BIOS Extensions), then you can program for LFB (Linear Frame Buffer). With LFB, you can write to video memory without having to worry about Bank Switching.

The following Wikipedia article contains useful links at the end with more information:
http://en.wikipedia.org/wiki/VBE

I learned how to program the VBE LFB from Charles Sandman's vbetest.c. The following link contains Sandman's vbetest.c source, as well as what seems to be an excellent background on the concepts behind VBE 2.0 LFBs, and DJGPP protected mode:
http://pages.cpsc.ucalgary.ca/~walpole/325/DJ_GRAPH.txt

Note that turning off protected memory in DJGPP is generally not a good idea since it could cause conflicts with 3rd party libraries.

Also note that it's better to adapt these concepts to a compiler such as OpenWatcom, which is free and uses 32-Bit Protected Flat Mode by default:
http://openwatcom.mirrors.pair.com/open-watcom-c-dos-1.9.exe


The calculations below are off the top of my head...

The generic calculation to plot a pixel follows:

BPP = (VBEModeInfoBlock.BitsPerPixel + 1) / 8;
Offset = (PixelY * VBEModeInfoBlock.BytesPerScanline) + (PixelX * BPP);
memcpy( VidMem + Offset, &Pixel, BPP );

Plotting a pixel in 256 color mode (8-BPP) follows:

Offset = (PixelY * VBEModeInfoBlock.BytesPerScanline) + PixelX;
((u8_t*)VidMem)[Offset] = (u8_t)Pixel;

Plotting a pixel in 32768/65536 color mode (15/16-BPP) follows:

Offset = (PixelY * VBEModeInfoBlock.BytesPerScanline) + (PixelX << 1);
((u16_t*)VidMem)[Offset] = (u16_t)Pixel;

Plotting a pixel in 16 million color mode (24-BPP) follows:

Offset = (PixelY * VBEModeInfoBlock.BytesPerScanline) + (PixelY * 3);
((u8_t*)VidMem)[Offset + 0] = (u8_t)PixelByte0;
((u8_t*)VidMem)[Offset + 1] = (u8_t)PixelByte1;
((u8_t*)VidMem)[Offset + 2] = (u8_t)PixelByte2;

Plotting a pixel in 4 billion color mode (32-BPP) follows:

Offset = (PixelY * VBEModeInfoBlock.BytesPerScanline) + (PixelY << 2);
((u32_t*)VidMem)[Offset] = (u32_t)Pixel;

Ah the memories :) Let me know if you need more information, and I'll write some code using OpenWatcom to demonstrate the important concepts.

Member Avatar for iret

Err.. realized that you asked in reference to an OS..

VBE 2.0 is simple to target, but VBE 3.0 would likely be better suited for an OS (assuming it's implemented consistently well across graphics cards).

VBE 3.0 at its core supports hardware page flipping, and provides a direct PMode32 interface. I haven't coded for VBE 3.0 though, so not sure of the pros and cons.

Your OS needs to be able to map physical memory to linear memory so that you can use VBEModeInfoBlock.PhysBasePtr. Your OS also needs to handle BIOS calls properly.

I'll post some VBE 2.0 code by the end of next week for DOS PM32, using OpenWatcom. Although it'll be for DOS, at least you will see what API calls your OS needs.

wow, I wasn't expecting such a good answer. Thanks, I am looking forward to the VBE 2.0 code ;)

Member Avatar for iret

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

I have had a look at the code and it looks rather good but I have no idea how to compile them.

As OpenWatcom was mentioned, I assume that is the logical choice to compile them with but I have no idea how to use it.

My DOS skills are way out of practice. In fact I have only used DOS a few times before.

Please explain how to use OpenWatcom to compile the code files.

Thanks,
Kieran ;)

Member Avatar for iret

I have had a look at the code and it looks rather good but I have no idea how to compile them.

Right, sorry 'bout that! Attached is a zip file of the main source, the makefile is included. Also, there is a BMP and a GIF, those are for demo3.

The makefile is for convenience, but compiling is as simple as: wcl386 demo vbe gfx -q -q operates the compiler in silent mode, which keeps quiet until there is an error.

Member Avatar for iret

Attached to this reply is a more recent vbesrc.zip file.

This release focuses on demo2, which shows driver and mode information. Don't be surprised if you see mode numbers such as 810E. Whatever display modes demo2 shows are valid.

To build, just type

wmake

The following have changed since the previous vbesrc.zip upload:
- Added stubs for FillRect, PutImage, and other functions
- Added missing comments to function implementations
- Added demo2.c and demo3.c
- Added image_t type
- Minor changes to cliprect_t structure
- Fixed minor bug in Clear functions (scaled down lfbsize according to rep stosX)
- Converted BMP file to PCX file
- Deleted BMP file and GIF file
- Tested on a PIII computer

Next up is demo3 which will be a graphics demo including filled rectangles (clipped), image blits (clipped), imaged loading (via PCX), simple pixel conversion (for loading images), and a general interface. With demo3, you will see how clipping a pixel differs from clipping a filled rectangle, and how it differs from clipping an image.

Iret i just found this thread searching for information on VBE, and (though im on a mobile device and unable to read the source at this time) it seems awesome. Im in the same boat as the OP, trying to write an OS, and ive been looking for this information. Is there any chance you could do that tutorial you said youve wanted to do? It would be most appreciated by me and the many other people it will help (and im sure it will help many many people if its as detailed as your posts are). Thank you.

Member Avatar for iret

Is there any chance you could do that tutorial you said youve wanted to do?

When I complete these demos, definitely :)

Member Avatar for iret

I tested the VBE source in a virtual machine (VirtualBox) using FreeDOS. I dug up 2 computers, but they were 32-BPP.

So the 24-BPP clear function doesn't quite work, but I'm close. I converted Seg:Ofs real mode addresses to a linear address. It works under emulation, but doesn't work consistently on two old computers so I'll need to figure out a better way to access the Real Mode data. There may also be a miscalculation with TotalMemory, I multiplied by 64. Once I straighten out the Real Mode pointers, I will be able to verify the TotalMemory calculation.

The VBE code works flawlessly, it's based on tested code from a graphics library that I worked on a while back. The graphics code will work flawlessly. Sorry for the errors so far. I won't post anything else until the code is fully tested.

Thank you.

Member Avatar for iret

Just a quick update.

I've ironed out a couple of bugs, especially the available mode list being corrupted. Now, 2K of low memory is allocated: 1K for VBE Driver Info + 1K for Mode Info. Also, I rearranged the vbe_SetMode code a bit since for some reason 32-BPP modes didn't want to run.

Regarding the TotalMemory calculation:
- TotalMemory x 64 = Video Memory size in KB
- Total Memory x 65536 = Video Memory size in Bytes

I didn't realize until the previous release that 32-BPP modes don't run. I fixed that by setting the video mode first, then doing all the LFB set up after.

So far, 8/15/16/32-BPP modes work flawlessly. 24-BPP needs a minimal amount of work.

I don't really have a choice but to code 24-BPP under emulation. The demos have crashed where I needed them to under VirtualBox, which helps me find any bugs. When the 24-BPP code is stable under VirtualBox, it will be stable on hardware. I'm working on locating a video card that supports VBE 2.0, LFB, and has 24-BPP video modes.

Member Avatar for iret

Moderator: Please remove previous attachments in this thread with extensions C, H, and ZIP. They had bugs which could potentially cause confusion to readers of this thread.

Attached is the most recent source release. This release is fully tested, and obsoletes all previous releases I have attached. Kieran, hopefully this release will make up for my previous releases :/

To compile, simply run wmake from the VBE directory

The following have changed since the last release:
- Changed from DOS/4G stub to PMode/W stub in previous release makefile
- Changed from PMode/W to Causeway stub in current release makefile
- demo1 functions without error for 8/15/16/32-BPP VBE modes on real hardware, and under emulation
- demo1 functions without error for 24-BPP VBE modes under emulation, but should work flawlessly on real hardware (I am working on testing this and will follow up to confirm, when I eventually get a 24-BPP hardware set up)
- vbe_Init() now allocates 2K of low memory where 1K is for VBE Driver Info, and 1K is for VBE Mode Info
- demo2 available modes list is no longer corrupt
- Fixed vbe_SetMode() by re-arranging each major section such that the display mode is changed, the VBE selector is set up, and the VBE physical address is set up
- gfx_Clear24() implemented and tested
- gfx_FillRect24() implemented and tested
- Added stubs and partial functionality to draw/load images for next release
- Updated gfx_t structure to include FillRect and PutImage function pointers


I've decided to make two more releases before letting this thread rest:
- next: image loading, drawing and clipping in demo3
- last: generic API interfacing in demo4; self-sufficient demonstration for video mode changing, setting up the LFB, and drawing a pixel in demo5


After the last release, I will work on a tutorial and will follow up with a link.

This stuff is amazing! I can't believe you have gone to this length to help someone :)

When you say:

The following have changed since the last release:
- Changed from DOS/4G stub to PMode/W stub in previous release makefile

Do you mean that you don't need DOS to run the code??

Thanks for all of the code. This is the best (although the only I've seen) tutorial on VESA. You could make a book and get some money from it ;)

Thanks iret!

Member Avatar for iret

This stuff is amazing! I can't believe you have gone to this length to help someone :)

No problem, I know what a pain it is to research VBE stuff (banked VBE included!).

Do you mean that you don't need DOS to run the code??

You actually do still need DOS, but now you don't need DOS/4GW :P PMode/W and Causeway are DOS Extender Stubs, which are embedded in the DOS Executable. So the executables will run standalone.

DOS was the only alternative to creating an OS (I'm not up to par for that yet :P).

Thanks for all of the code. This is the best (although the only I've seen) tutorial on VESA. You could make a book and get some money from it ;)

Thanks iret!

;)

You actually do still need DOS, but now you don't need DOS/4GW PMode/W and Causeway are DOS Extender Stubs, which are embedded in the DOS Executable. So the executables will run standalone.

DOS was the only alternative to creating an OS (I'm not up to par for that yet ).

I see, understandable ;)

I still need to learn a bit more about DOS. My skills have got a bit dusty (to say the least). I am sure I can adapt the code for my operating systems functions, or current lack of them ;)

Thanks again! :)

Hey iret,
I just wanted to thank you again for this. I know its months later, but i just rediscovered it and its helped me AGAIN. Haha.

Thanks

Member Avatar for iret

Hey iret,
I just wanted to thank you again for this. I know its months later, but i just rediscovered it and its helped me AGAIN. Haha.

Thanks

Cool :)

BTW, I haven't forgotten about the tutorial. I was stopped by a dumb bug in PCX loading (yeah.. I know), and then became really busy. Not sure exactly when, but I will pick this up again.

Member Avatar for iret

First, I know that this article has been dead for a while, but I'm not done yet :)

Still been really busy, but I needed a break so I'm on this again. Turns out the PCX bug was partially due to loading an 8-BPP file, when the file itself is 24-BPP. PCX is an obsolete and annoying format, but few others are as simple to decode (and still around).

I'll follow up when the next demo is ready, which will hopefully be within 2 weeks.

Member Avatar for iret

Ok, finally done with the PCX loading and image blitting. demo3 is now complete.

This release invalidates all previous releases.

The following have changed since the last release:
- Added function vbe_FindMode(p_width, p_height, p_bpp) which searches the mode list for a display mode with the exact specified resolution.
- Added stub for vbe_NearestMode(p_width, p_height, p_bpp) which searches the mode list for a display mode that is either an exact match, or the next size up. Not yet implemented.
- Added pcx.c and pcx.h which decodes 8-BPP and 24-BPP PCX files.
- Added dumppcx.c as a self-contained diagnostic program to split an 8/24-BPP PCX file into a text header, binary data, and a binary palette (if the PCX file is 8-BPP).
- Completed gfx_PutImageXYZ functions.
- PCX decodes 8-BPP pixels upwards to 8/15/16/24/32-BPP pixels.
- PCX decodes 24-BPP PCX pixels upwards to 24/32-BPP pixels.
- PCX does not quantize pixels (convert downwards).
- demo1 has been split into demo1_Run8/demo1_Run15/demo1_Run16/demo1_Run24/demo1_Run32 thanks to vbe_FindMode.
- demo2 has been split into a series of functions.
- demo2 now has a parameter all which shows mode information for all available display modes
- demo2 now reports that a display mode is not supported, instead of incorrectly showing mode information with a bunch of 0's.
- demo3 has been split into demo1_Run8/demo1_Run15/demo1_Run16/demo1_Run24/demo1_Run32 thanks to vbe_FindMode.
- demo3 decodes both an 8-BPP and 24-BPP PCX file
- demo3 displays an 8-BPP image in 8/15/16/24/32-BPP display modes, with and without clipping.
- demo3 displays a 24-BPP image in 24/32-BPP display modes, with and without clipping.
- Made function header comments more consistent.

A quick note on clipping. Clipping an image ensures that only the visible portion is drawn. I wrote each PutImageXYZ function to clip because it's something I learned the hard way. Hopefully it'll save you time.

A quick note on vbe_PutImageXYZ. The algorithms scale nicely. All you have to do is multiply certain values by the number of bytes per pixel. Look for XYZ * 2, XYZ * 3, XYZ * 4.

A quick note on vbe_FindMode/vbe_NearestMode. I created vbe_FindMode and vbe_NearestMode to make everything more flexible. vbe_NearestMode will be implemented in the next release.

I tested under both DOSBox and VirtualBox, and everything is pretty solid. Funny thing is VirtualBox supports both 24-BPP and 32-BPP VBE modes. Not sure if it's always done that.

If you no longer have DOSBox installed, please let me know.

To build, simply unzip the file, then type wmake from within the emulated/real DOS environment.

Next up are demo4 (generic graphics interface), and demo5 (self-contained VBE LFB set mode and plot a pixel). Also next up is an implementation of vbe_NearestMode.

To comment ahead on the VBE banked/LFB tutorial, not sure yet when it's going to happen. After I complete these demos, I'll need to get back to some stuff I'm working on. But, it will happen.

Please let me know if you have any questions.

Wow - you've been busy. The demos you have provided are very good. I am currently busy myself, when I get a chance I will put these files to good use.

Thank you so much.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.