A problem with drawing in VESA

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Al3x4nder
Posts: 4
Joined: Fri Apr 09, 2010 2:07 pm

A problem with drawing in VESA

Post by Al3x4nder »

Hi,

I read displaying a bitmap in Vesa-Mode and plotting pixels .

1. I tried the first one and it worked fine, displaying a purple 640*480*8 bitmap, but when I tried to plot pixels after that with this,

Code: Select all

mov   edi,[ModeInfo_PhysBasePtr]       
mov   ecx,640*30   ; Size of screen
mov   al,0xff   ; This is for the color of one pixel (white)
rep   stosb
the color was purple instead of white :? :cry:

2. When I call only the plotting-code instead of the bitmap code, the screen is totally black :?

3. When I call the code for displaying the bitmap and then call the code, which is nearly the same except

Code: Select all

   add   esi,edx                       ; start of next bmp line
   dec   ebp
   jnz   new_line
   ret 
is

Code: Select all

   add esi,edx		       ; start of next bmp line
   dec	 ebp
   cmp ebp, 30
   jbe	 new_line2
   ret  
for displaying a second bitmap with 640*30, the second one is displayed correctly, but the first one´s colors get weird.

Obviously there is something I have to reset, but I don´t know what.
Thank´s for helping in advance!!

Alex

Edit: I uploaded a picture of the problem under [3]
Attachments
1.jpg
Selenic
Member
Member
Posts: 123
Joined: Sat Jan 23, 2010 2:56 pm

Re: A problem with drawing in VESA

Post by Selenic »

XxYx8 always uses a palate. Your problem appears to be that, when you display one bitmap, it replaces the palate (because it must), causing the other bitmap to look wrong.
Al3x4nder
Posts: 4
Joined: Fri Apr 09, 2010 2:07 pm

Re: A problem with drawing in VESA

Post by Al3x4nder »

Thank you Selenic!
So I can´t simply overwrite parts of the screen?
What do I have to do for displaying it the way I´d like to?
I can´t keep the palate of the first image, because the second one needs a new one (Is there a way to avoid a palate?).
That means, that every time you make a change to the screen, the whole screen is refreshed ( the old image is loaded again ). That is inefficient :shock:
Selenic
Member
Member
Posts: 123
Joined: Sat Jan 23, 2010 2:56 pm

Re: A problem with drawing in VESA

Post by Selenic »

Al3x4nder wrote:So I can´t simply overwrite parts of the screen?
What do I have to do for displaying it the way I´d like to?
Best bet: try to get a >8-bit colour depth, preferably 24-bit or 32-bit (as 8-bit is always palette-based, 16-bit rarely is, everything higher is always true-colour)
Then you use the palate yourself to translate the 8-bit bitmap to the correct RGB and draw that on-screen
Al3x4nder wrote:I can´t keep the palate of the first image, because the second one needs a new one (Is there a way to avoid a palate?).
Two methods: one is to use true-colour, the other is to use a 'universal palette', which is the same thing but at a lower colour-depth.
Al3x4nder wrote:That means, that every time you make a change to the screen, the whole screen is refreshed ( the old image is loaded again ). That is inefficient :shock:
No, it just means that if you display a bitmap with a palette-based display, you'd better either have a universal palette or display nothing but the bitmap, because it'll screw up your other colours.

The basic solution to this is, seeing as you're using VBE and not directly doing VGA programming, is to just use a higher bit depth. The other solution is to not use any code which you don't *fully* understand - if you'd read our wiki and programmed it based on that, you wouldn't have this problem :wink:
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: A problem with drawing in VESA

Post by Brendan »

Hi,
Selenic wrote:
Al3x4nder wrote:I can´t keep the palate of the first image, because the second one needs a new one (Is there a way to avoid a palate?).
Two methods: one is to use true-colour, the other is to use a 'universal palette', which is the same thing but at a lower colour-depth.
For 8-bpp video modes I've always use a universal palette - 3 bits for red, 3 bits for green and 2 bits for blue (it works out much easier to use).

There is a third way though, which can give much better results (at the cost of much more overhead). You can draw everything in a 32-bpp (or better?) buffer, then (each time you need to copy the buffer to video display memory) you calculate the optimum palette, convert the first buffer into a second 8-bpp buffer that uses the optimum palette, then set the new/optimum palette and copy the 8-bpp buffer to video display memory.

Even if you use a universal palette (and don't dynamically calculate the optimum palette) using a 32-bpp buffer is probably a good idea. It would make it easier to support other video modes (for e.g. to support 4 different colour depths you only need 4 pieces of code to convert the 32-bpp buffer into the desired colour depth, and all the code to draw stuff in the 32-bpp buffer stays the same). It'd also be easier to add support more variations of the bitmap file format and allow you to support transparency (e.g. "RGBA"); and you could even use dithering to compensate for the reduced number of colours.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Al3x4nder
Posts: 4
Joined: Fri Apr 09, 2010 2:07 pm

Re: A problem with drawing in VESA

Post by Al3x4nder »

Thank you for helping!
So I switched to 640*480*24 (4112h). It might be much simpler to have only one palette.
But now the method for plotting pixels is wrong:

Code: Select all

mov   edi,[ModeInfo_PhysBasePtr]       
mov   ecx,640*480/4   ; Size of screen
mov   eax,0xffffffff    ; This is for the color of one pixel
rep   stosd
Are there any tutorials about this?
I read http://wiki.osdev.org/Drawing_In_Protected_Mode#Color and unterstand what a palette is and what is does.

1. But I don´t understand, how e.g. the hexadecimal color #ff0000 is translated to 7800h.
2. The starting point of coloring on the screen is moved about 400 pixels to the right. The first pixel is red and the last one is cyan.
Could you explain in detail what has changed?
3.

Code: Select all

mov   eax,0xffffffff    ; This is for the color of one pixel
Why isn´t it only 0xffffff?
4.Is there a tutorial that explains how you load a bitmap? How and where do I load it?
5. How do I set up the palette? I don´t have any data from an image now. And I read that the colors now have fixed values in 24bit.
But in bitmaps a palette is included and the color values correspond to this palette. Or is the palette only included in 8bit bitmaps?!

Sorry for asking so many questions, but I could only find (lots of) information about VGA and low resolution/depth VBE modes.
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: A problem with drawing in VESA

Post by Gigasoft »

The code you have sets 4 8-bit pixels at once, to the value 0xff.

The 0x7800 is a typo, it should be 0x7c00. This is a 15-bit representation of the color red where MSB=red. In binary, this is:

Code: Select all

0111 1100 0000 0000
-rrr rrgg gggb bbbb
Selenic
Member
Member
Posts: 123
Joined: Sat Jan 23, 2010 2:56 pm

Re: A problem with drawing in VESA

Post by Selenic »

Al3x4nder wrote:Thank you for helping!
So I switched to 640*480*24 (4112h). It might be much simpler to have only one palette.
Firstly, you want X*Y*32 (ideally) because then the code you're suggesting does work. 24 bits has the same information content and is denser (because 8 bits of the higher depth are ignored), but 32 bit depth allows you to use 32-bit loads and stores without problems.
In addition, you have to remember that each 32-bit load/store does one pixel, so in your example code you set ecx to simply 640*480.

Finally, as has been mentioned before, higher colour depths don't have a palette; instead, you're programming it in a much more direct manner (so, assuming a 24-bit depth, 0x123456 means something like '0x12 red, 0x34 green, 0x56 blue' rather than 'look up palette entry 0x123456')
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: A problem with drawing in VESA

Post by pcmattman »

Building upon what Selenic said, a 24-bit mode means you can no longer reference video memory as a big array of uint<pixel-depth>_t - it's packed. Iterating over the video memory therefore becomes a little more involved.

That is, unless you can find a 24-bit type ;)
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: A problem with drawing in VESA

Post by Brendan »

Hi,

To add to everything else, there's a few other things you should be aware of:
  • Dex's example code isn't very good (inadequate error checking in video mode setup and in the bitmap decoder, ignores almost all information from the video mode information, etc). Cut & pasting his code (and his bugs) then adding your own changes (more bugs) adds up to a steaming pile of bugs.
  • The number of bytes between horizontal lines may not be equal to "horizontal resolution * the number of bytes per pixel"; and may be larger. For example, for a 640*480*8-bpp video mode, the first line would be at "offset 0" while the second line might be at "offset 1024" (not "offset 640"). You need to use the right "bytes per line" field in the video mode information to calculate the address of each horizontal line. There's actually 2 of these "bytes per line" fields - one for bank switched video modes and one for LFB video modes; and the "bytes per line" field for LFB is only supported for VBE 3 (if the "get controller information" function says the video card is not VBE 3 or later then you use the "bytes per line" field for bank switched video modes for LFB).
  • When you use the "get video mode information" function, usually the flags are ignored (e.g. if you ask for information for video mode 4112h you'll get the same information as you'd get for video mode 0112h). To determine if the video mode supports LFB or not, you should make sure bit 7 in the attributes field (in the video mode information) is set.
  • For the "get video mode information" function, *always* test the "video mode is supported" flag (bit 0 in the attributes field). If this bit is clear then the video mode is not supported.
  • The "standard" VBE mode numbers are obsolete and were removed from VBE when "VBE 2.0" was released. Most video cards still use them for backward compatibility, but there's no real reason for them to do so. Video mode 4112h might not be 640*480*24 (it could be anything, or nothing), and video mode 640*480*24 might be a different video mode number (if it's supported). The correct way to do it is to use the list of video mode numbers (returned by the "get controller information" function) and search this list (by using the "get video mode information" function for each video mode number in the list and checking the values in the video mode information) until you find a video mode you want.
  • Better code will use the list of video mode numbers (returned by the "get controller information" function) to find the "best" video mode that is supported by the video card and the software itself; and should support many different video modes (e.g. 8bpp, 15-bpp, 16-bpp, 24-bpp and 32-bpp, and not just 24-bpp; at any resolution) because different video cards support different video modes. If your code only supports one specific video mode like (for e.g.) 640 480 * 24-bpp, then it'll fail on all video cards that don't support that specific video mode (which is actually a lot of them - lots of video cards support 32-bpp or 24-bpp but not both, and 15-bpp or 16-bpp but not both).
  • Just because VBE says a video mode is supported by the video card, doesn't mean it is also supported by the monitor. Unless you verify that the monitor supports the video mode (which is messy and relies on EDID, and isn't entirely possible in some cases), then you should either refuse to use any video mode that isn't "standard VGA" (e.g. 640*480), or give the user a choice (e.g. a menu of video modes, where they can select one and then get a "press OK within 15 seconds if you can see this!" prompt which restores the standard VGA mode (and menu) if the user doesn't/can't tell you the video mode works.
  • For 8-bpp video modes; you should check if the video mode is "VGA compatible" (make sure bit 5 is clear in the attributes field in the video mode information) before assuming that the palette can be set via. the VGA's palette I/O ports and before assuming the palette is 6 bits for red, green and blue (and not 8 bits for red, green and blue, or something else). VBE also has a "set/get palette format" function that could be used to switch to "8-bits for red, green and blue" (if you want more precise colours) and a "get/set palette data" function (which can be used to set the palette data, even if the video mode doesn't support the VGA's palette I/O ports).
  • For higher colour depths (e.g. 15-bpp, 16-bpp, 24-bpp, 32-bpp) you should check the colour masks and bitshifts in the video mode information. "RGB" is *not* the same as "BGR", and 16-bpp could mean "2 bits for red, 1 bit for green and 13 bits for blue". Some video cards also support YUV video modes (that aren't RGB at all), and you should also check "memory model" field to determine if the video mode is YUV or "direct colour" (or planar or something else).
  • For the bitmap file format, there's about 6 different versions (with different headers), and for each version there's about 20 different pixel formats (everything from 1-bpp to 32-bpp, both with and without compression schemes, and for some bitmaps the data is "top to bottom" rather than "bottom to top"). Dex's code assumes the bitmap uses one specific version of the file format (with one specific header format) and assumes far too much about the pixel format. It can easily break if the bitmap file is slightly different (e.g. fail to detect that it's an unsupported bitmap file and display gibberish).
Finally, I'd recommend that you read the VBE specification/s yourself, and find out about the various bitmap file formats, and then write your own good code (and not use any of Dex's crappy code).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Al3x4nder
Posts: 4
Joined: Fri Apr 09, 2010 2:07 pm

Re: A problem with drawing in VESA

Post by Al3x4nder »

Thanks a lot!
1. Unfortunately VirtualBox doesn´t support 32 bit (0129h => 4129h) ( http://en.wikipedia.org/wiki/VESA_BIOS_ ... de_numbers ).

This is the 32 bit code for drawing 10 lines:

Code: Select all

mov   edi,[ModeInfo_PhysBasePtr]
mov   ecx, (ModeInfo_BytesPerScanLine/4)*10    ; 4 because of 32 bit; 10 lines
mov   eax,0xEEEEEEEE 
rep   stosd
In 24 bit "mov ecx, (ModeInfo_BytesPerScanLine/4)*10" would be:

Code: Select all

 mov   ecx, (ModeInfo_BytesPerScanLine/3)*10    ; 3 because of 24 bit; 10 lines 
But I can´t use "mov eax,0xEEEEEEEE" and "rep stosd" anymore :(

2. Moreover [ModeInfo_PhysBasePtr] doesn´t point at the first pixel address.
It points 1566 or 61E too far to the right. (see attachment)
And the first and last pixel doesn´t have the desired color.

When these problems are solved, the code would draw on the screen properly! [-o<
I hope you can help me.

@Brendan Thank you for the tips. I used Dex´s code, because it is nearly everywhere in the board and it worked so far in lower resolutions.
Attachments
1.jpg
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: A problem with drawing in VESA

Post by Gigasoft »

Dividing the address of ModeInfo_BytesPerScanLine by 3 won't do you any good, since first of all you want the value, not its address, and it most likely won't be an integer number of pixels anyway. What you have to do in 24 bit mode is something like this:

Code: Select all

mov ebx, whatever the width is
mov ecx, whatever the height is
mov ax, lower 16 bits of whatever color you want
mov dl, upper 8 bits of whatever color you want
snurr2:
push edi
push ebx
snurr:
add edi,3
dec ebx
mov [edi-3],ax
mov [edi-1],dl
jnz snurr
pop ebx
pop edi
add edi,[ModeInfo_BytesPerScanline]
loop snurr2
In 32 bit mode, you could do this:

Code: Select all

mov ecx, whatever the width is
mov ebx, whatever the height is
mov eax, whatever color you want
snurr:
push edi
push ecx
rep stosd
pop ecx
pop edi
add edi,[ModeInfo_BytesPerScanline]
dec ebx
jnz snurr
It could be optimized much more, of course, but this just illustrates how you might do it.
Post Reply