Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assembly x86 video mode

I'm trying to create some basic drawing routines in assembly (NASM). Looking at the x86 BIOS interrupt table, I've found the 10h interrupt that offers some video manipulation services.

Using it, I've managed to come up with a routine to draw a square, configuring the interrupt call to Write a Graphics Pixel (AH = 0Ch).

The square is being drawn correctly but takes too long, I can see it being filled. BTW, I'm running my code on QEMU.

I've assumed the screen was being refreshed faster than the instructions were executed. After some research, I didn't find any helpful content. The main possible solutions were to adjust vertical sync and write directly to the video memory.

Considering that I'm using video mode 12h (640x480 - 16 colors), my questions are:

1 - Writing directly to the video memory is faster than calling an interruption?

2 - How the bytes are organized in the video memory space? Each pixel occupies a byte (starting at address 0xa000)?

3 - How can I write to the video memory? Simply write each pixel color sequentially?

4 - In general, when a display is refreshing the screen, it just reads directly from the video memory from time to time?

like image 755
Mateus Avatar asked May 04 '14 01:05

Mateus


1 Answers


1) Writing directly to the video memory is much faster.

2) For graphic video modes with only 16 colors(4 bit) we have to use a port access (to 3CEh Pixel-Mask-Register) and additional a dummy read at the target location for to set one pixel to the framebuffer. It is not so simple to explain the way. But i can give you an example of my pixel set routine for my ET4000 graphic card using videomodes with 16 colors:

PIXEL:    pusha
          add    bp, XMIN
          add    bx, YMIN
          mov    cx, bp              ; Screen-Offset
          shr    cx, 3
          mov    ax, PS              ; Pixel of a line
          mul    bx                  ;    * Y
          add    ax, cx              ;        + (X/8)
          mov    di, ax              ;                = address
          cmp   BYTE PTR[FLAG_2], 5  ; SVGA ?
          jb  VGA
          mov    al, dl              ; Bank switch ET4000
          shl    al, 4               ; for SVGA: 1024x768 and 1280x1024
          add    al, dl              ; overflow 64K border
          mov    dx, 3CDh            ; Port address for bank switching ET4000
          out    dx, al
VGA:      inc    cx                  ; calculate Pixel
          shl    cx, 3
          sub    cx, bp
          dec    cx
          mov    ah, 1               ; 2 ^ (((X/8) + 1) * 8 - X) - 1
          shl    ah, cl              ;                      = Pixel pos.
          mov    dx, 3CEh            ; Pixel-Mask-Register
          mov    al, 8
          out    dx, ax
          mov    al, fs:[di]         ; Dummy-READ (get the address)
EBENE:    mov   BYTE PTR fs:[di], 1  ; set Pixel
          popa
          ret

But video modes with 8,15/16,24/32 bit color are more easy to use without a port access. Example with 8 bit colors it is simple to calculate the address of a pixel. Pixel address= (Y_coordinate * horizontal resolution) + X_coordinate

With 8 bit color each address represent one pixel on the screen. But additional we have a color palette(lookup table) for to determine the red, green and blue parts for each color number. Only for video modes with 15/16 and 24/32 colors the color is fully encoded in the pixel-address with two bytes, or three bytes for the color.

3) Yes, for video modes with 8,15/16,24/32 bit color it is easy to fill the screen with colors.

4) We do not need to tell the graphic card for refreshing the screen content. But we can check the status register of port 3DAh if the cathode ray is at the end on the screen, for to minimize a flickering effect and a tearing of the screen content.

In the first time i also try to use videomode with 4 bit color, but it is not so simple to use like other graphic modes with more colors. Today with my Radeon 7950 card i prefer to use the native resolution of my 28" widescreen monitor in 19202x1200 with 32 bit color using the linear framebuffer located somewhere in the fourth gigabyte. For to switch into this resolution i use the VBE-Bios and the modetable of modenumbers that comes within the VBE-bios. The documentation for that can be found in the vbe3.pdf from vesa.org(costfree but need register/login) in the public section of there page.

like image 115
Dirk Wolfgang Glomp Avatar answered Sep 28 '22 04:09

Dirk Wolfgang Glomp