24 bit graphics mode in assembly

542 Views Asked by At

I want to make an OS (64 bit). I made a compiler in it, input, output, I just need to have a 24 bit graphics mode to make a GUI. I tried to display all of the colors but I just get this mess:

this is the mess

the code which ran it: (just in a test 16 bit environment)

[org 0x7c00]
  mov ax,4f02h
  mov bx,103h
  int 10h


        mov ax, 0a000h
mov es, ax
mov al, 0
 

mov edi, 0
mov eax, 0
sl:
stosw
inc edi
inc eax
jmp sl
times 510-($-$$) db 0
dw 0AA55h

And I need to make it interrupt free because of the cli instruction when switching to 64 bit mode. I hope that I can make it to be compatible with any resolution but I need to output a pixel for now. I hope someone knows how to do it, because I didn't find anything is this topic.

I tried to switch the mov bx, 103h to other things, but it just made it worse. And I can't even run it in 64 bit mode because of the mov es, ax.

1

There are 1 best solutions below

8
On BEST ANSWER

First I strongly recommend to read this:

The idea behind pixel rendering is to compute address where pixel lies in VRAM and copy the color or index at that address (using segment where the VRAM is located usually A000h for video and B800h for text modes).

address = (x + y*x_resolution) * bytes_per_pixel

However normally we can access only single segment of VRAM so wee need also to select which one it is (page) so:

page = address / 65536
offs = address % 65536

now you switch in page (if not already) and copy the pixel color (1/2/4 bytes) at that address for example by using stosb/w/d. Now I am not sure if pixel can be at 2 pages at once (the code bellow does not handle that) so if true you should handle that too (however as x resolution for standard video modes is always multiple of 4 I do not think its possible).

Looks like you really a rookie so here is small simple (ugly and slooooow) example (MS-DOS com executable using VESA BIOS in NASM) of rendering pixels in 800x600x32bit mode 115h... just inspect the function pixel , it expects 800x600x32bit video mode and ax,bx as x,y and ecx as 32bit color:

Firs main source file:

[BITS 16]
[ORG 100h]

[SEGMENT .text]

start:  pusha
    mov ax,115h ; init 800x600 32bit
    call    vesamod

    mov al,0    ; set page to 0
    mov [cs:page],al
    call    vesapag

mainl0: mov ax,10
    mov bx,10
    mov ecx,003F7FFFh
l0: call    pixel
    inc ax
    inc bx
    cmp ax,110
    jnz l0

    mov ax,256  ; stop on any key hit
    int 16h
    jz  mainl0

    mov ax,3    ; return to 80x25 text mode
    int 10h
    popa
    ret

error:  mov ax,3
    int 10h
    popa
    popa
    ret

pixel:  pusha           ; ax=x, bx=y, ecx = color

    mov di,ax       ; eax = ( 800*y + x ) * 4
    mov eax,800
    and ebx,0FFFFh
    mul ebx
    mov bx,di
    add eax,ebx
    shl eax,2

    mov di,ax       ; di = eax % FFFFh (offset)
    mov ax,0A000h   ; es = A000h
    mov es,ax

    shr eax,16      ; ax = eax / FFFFh (page)
    cmp al,[cs:page]
    jz  .pixel0     ; change page if needed
    mov [cs:page],al
    call    vesapag

.pixel0:mov eax,ecx     ; eax = color
    stosd           ; render pixel
    popa
    ret

page:   db  0

%include 'vesa.lib'

and the helper vesa.lib:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;VESA librrary ver: 1.0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;vesamod    set VESA videomode ax
;vesapag    al=page  switch vesa video page window A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Vesa: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
vesamod:pusha               ;set VESA videomode ax
    mov     bx,ax
    mov     ax,4f02h
    int     16
    lea     si,[cs:.err]
    or      ah,ah
    jnz     near error
    popa
    ret
.err:   db  'VESA mode set error.',0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
vesapag:pusha               ;al=page  switch vesa video page window A
    mov     dl,al
    sub     dh,dh
    sub     bx,bx
    mov     ax,4f05h    ; window A
    int     16
    lea     si,[cs:.err]    ; error msg
    or      ah,ah
    jnz     near error
    popa
    ret
.err:   db  'VESA page switch error.',0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; End. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

note that I did not code in asm in ages and have no mod to tweak this in DOS-BOX too much so its ugly and non optimized.

This renders blue diagonal line using function pixel which means the layout of color is:

ecx = 00RRGGBBh

there are many pusha/popa and I am using slow computation using mul to improve performance you should have array where you store the starting address and page of each scan line precomputed once (after changing video mode) and then just access it using y. Also the actual page variable could be moved directly into vesapag function but I was not in the mood to edit 2 files as I am really rusty in MS-DOS and asm now and DOS BOX is conflicting key shortcuts with my editors not to mention VC editors stopped working for god knows what reason (took me a lot more time to workaround that than code the example itself)...

Also if you want to use 32/64 bit code you will have to use some kind of extender to have access to VESA BIOS (or any BIOS) functions or their replacement. Have never done such thing but people used DOS4GW for this back in the day...

Also in 32/64 bit mode you can use LFB (linear frame buffer) and forget about page switching completely (improving speed a lot more).

If you want to have this working for any resolution then you should change the hardcoded 800 to real resolution you use. It can be obtained from VESA BIOS (along with starting segment) just disect this:

It obtains all available VESA video modes along with information about them and once you chose one from the list it renders a control image so you see the difference between 8/15/16/32 bit modes...