How to draw a pixel in VESA graphic mode?
I am trying interrupt
0ch, but it’s not working. What is wrong?
(Note: I wrote this code in NASM syntax and tested it with qemu)
; Code: Mov ax, 4F02h Mov bx, 0105h ; 1024x768 pixels Int 10h Mov ah, 0ch ; Draw pixel function Mov cx, 2 ; column Mov dx, 3 ; row Mov bh, 0 Mov bl, 00000101b ; colour Int 10h Jmp $ ; jump forever Times 510-($-$$) db 0 Dw 0xaa55
The function Int 10h/AH=0Ch should work even when using a VESA VBE mode.
Make sure to use it correctly, the pixel’s colour goes into
;Set video mode mov ax, 4f02h mov bx, 105h int 10h ;Draw pixel mov ax, 0c09h ;09h = Blue mov cx, 2 mov dx, 3 xor bx, bx int 10h
Technically, you should use Int 10h/AX=4F01h to retrieve the video mode information, including bit 2 (2 BIOS output supported) of the mode attributes field, to check if the BIOS functions will work.
Writing a high-resolution image using the BIOS function could be too slow, it may be worth investing in writing directly to a linear or windowed frame buffer.
Writing to a linear framebuffer will probably require using the unreal mode, it’s possible to avoid that by using a windowed framebuffer.
This, besides being slower, is also more cumbersome.
Here is a very simple program that fills 30 rows with a horrible shade of grey.
Note that I stripped all the checks for the sake of compactness and clarity, I made a lot of assumptions to avoid making some math.
This is a bad practice, I used it only for prototyping.
I strongly encourage you to read the full information returned by
Int 10h/AX=4F01h and use that information to select the correct window, do the right padding and calculations.
BITS 16 ORG 100h mov ax, ds mov es, ax ;Set video mode mov ax, 4f02h mov bx, 105h int 10h ;Get video mode info mov ax, 4f01h mov cx, 105h mov di, modeInfo int 10h ;Assume first window is valid mov ax, WORD [es:modeInfo + 08h] mov es, ax ;Example of how to change the window mov ax, 4f05h xor bx, bx mov dx, 5 ;This is granularity units int 10h xor di, di mov al, 0f1h mov cx, 3*1024*20 rep stosb ;Wait for key xor ax, ax int 16h ;Restore DOS text mode mov ax, 0003h int 10h ;Exit mov ax, 4c00h int 21h modeInfo TIMES 256 db 0
This is in NASM syntax, I usually use TASM (out of affection) for DOS programs but this time I was in a hurry.
The result is
Remember that each scanline can, in general, be padded (the size of a scanline is returned in the video mode information).
For a 1024 pixel wide scanline, with 3x8bpp we have 3072 bytes/scanline, since this is divisible by 4, no padding is likely to happen.
The window start address is given in the granularity unit (also found in the video mode information), the total framebuffer is 1024x768x3 bytes = 2.25 MiB, assuming no padding.
The window size is also found in the video mode information.
All this is enough to write to the framebuffer.
A linear framebuffer is easier to handle (padding is still an aspect to consider) once the unreal mode has been set up.