Page 1 of 1

Plot pixel at Linear Frame Buffer

Posted: Fri Aug 16, 2013 1:47 pm
by Elja98
Hello all,

This is my first post in this forum. I'm creating an operating system and I'm pretty successful until now. I'm using VESA and want to plot a pixel. I can find examples for doing it in C, but the problem is I'm still using assembly. How to plot a pixel in assembly? I'm using mode 117h (1024 x 768 16bit color). I already found the address of the linear frame buffer. I hope somebody can help.

Thanks in advance.

Re: Plot pixel at Linear Frame Buffer

Posted: Fri Aug 16, 2013 2:21 pm
by Brendan
Hi,
Elja98 wrote:This is my first post in this forum. I'm creating an operating system and I'm pretty successful until now. I'm using VESA and want to plot a pixel. I can find examples for doing it in C, but the problem is I'm still using assembly. How to plot a pixel in assembly? I'm using mode 117h (1024 x 768 16bit color). I already found the address of the linear frame buffer. I hope somebody can help.
Find the offset in the LFB for the start of the line, using "Y * bytes_per_line". For example (assuming EAX contains the Y co-ord):

Code: Select all

    mul dword [bytes_per_line]      ;edx:eax = y * bytes_per_line
Then multiply the X co-ord by the bytes per pixel (2) to find the offset of the pixel on the line; then add it to your "offset for the start of the line". For example (assuming EBX contains the X co-ord):

Code: Select all

    lea edx,[ebx*2+eax]             ;edx = y * bytes_per_line + x * bytes_per_pixel
Then add the address of the LFB. Hopefully you're using paging to map it at a fixed address, so the above instruction can be "lea edx,[ebx*2+eax+LFB_address]". Otherwise you need a whole new instruction for it:

Code: Select all

    add edx,[LFB_address]           ;edx = LFB_address + y * bytes_per_line + x * bytes_per_pixel
Once you've got the right address calculated, store the colour at the address. For example (assuming CX contains the colour):

Code: Select all

    mov [edx],cx
Of course hopefully you're using paging and can combine this with the "lea edx,[ebx*2+eax+LFB_address]", and do "mov [ebx*2+eax+LFB_address],cx" instead.

Basically, if your LFB isn't at a fixed address you might get something like this:

Code: Select all

;Input:
;   eax = Y co-ord
;   ebx = X co-ord
;   cx = colour
;
;Output
;   none
;
;Trashed
;  edx, eax

plotPixel:
    mul dword [bytes_per_line]      ;edx:eax = y * bytes_per_line
    lea edx,[ebx*2+eax]             ;edx = y * bytes_per_line + x * bytes_per_pixel
    add edx,[LFB_address]           ;edx = LFB_address + y * bytes_per_line + x * bytes_per_pixel
    mov [edx],cx                    ;Set the pixel's colour
    ret
And if your LFB is at a fixed address you might get something like this:

Code: Select all

;Input:
;   eax = Y co-ord
;   ebx = X co-ord
;   cx = colour
;
;Output
;   none
;
;Trashed
;  edx, eax

plotPixel:
    mul dword [bytes_per_line]      ;edx:eax = y * bytes_per_line
    mov [ebx*2+eax+LFB_address],cx  ;Set the pixel's colour
    ret
Now; in both cases the code is relatively small, so the call/ret will add significant overhead. For this reason it'd be better to implement it as a macro.


Cheers,

Brendan

Re: Plot pixel at Linear Frame Buffer

Posted: Fri Aug 16, 2013 3:27 pm
by Elja98
Thanks for your quick reply Brendan! Such an easy answer for something I worked days on :oops: Thanks for your help

Re: Plot pixel at Linear Frame Buffer

Posted: Sat Aug 17, 2013 2:17 am
by Elja98
I tested your code but unfortunately it doesn't work. Is there something that I have to do with the GDT? Or anything I have to setup to make your code work. Here's my code for now:

My 16 bits code:

Code: Select all

mov	ax, 4F02h			;Set video mode
mov	bx, 117h				;1024 x 768 16 bpp
or	bx, 4000h			;Use Linear Frame Buffer
int	10h

mov	ax, 4F01h			;Get mode information
mov	cx, 117h				;Of mode 117h
mov	di, buffer		
int	10h
	
mov	ax, WORD [buffer+2Ah]	;Get location of Linear Frame Buffer
mov	WORD [loc_lfb], ax		;Save it
mov	ax, WORD [buffer+32h]	;Get Bytes Per Scanline
mov	WORD [BPS], ax		;Save it
After that I enter 32 bits mode and use this:

Code: Select all

mov	eax, 1				;X = 1, Y = 1
mov	ebx, 1
mov	cx, 0000011111100000b		;Color = green

PlotPixel:
mul	WORD [BPS]			;eax = Y * BytesPerScanline
lea	edx, [ebx*2+eax]			;edx = X * 2 + Y * BytesPerScanline
add	edx, [loc_lfb]			;edx = (X * 2 + Y * BytesPerScanline) + LFB (0xE000 bochs)
mov	[edx], cx				;Plot it
Again, Thanks in advance

Re: Plot pixel at Linear Frame Buffer

Posted: Sat Aug 17, 2013 2:47 am
by jnc100
Isn't the LFB at offset 0x28 within the structure? And 4 bytes long?

Regards,
John.

Re: Plot pixel at Linear Frame Buffer

Posted: Sat Aug 17, 2013 2:54 am
by Elja98
Yes, but first I did some tests with Bochs to print the dword at 28h. I got 0x0000E000 so I just decided to ignore the first byte and just use 0xE000.

Re: Plot pixel at Linear Frame Buffer

Posted: Sat Aug 17, 2013 3:31 am
by Combuster
Your print function is wrong. The correct answer is 0xE0000000 (stored as 00 00 00 E0), not 0x0000E000 (which would be 00 E0 00 00 in memory)

Also ignoring one byte is not the same as ignoring two bytes. This business is very, very sensitive to details and I would recommend that you grow some appreciation for that. Tiny mistakes like these will tend to haunt you through your entire OS if left unchecked.

Re: Plot pixel at Linear Frame Buffer

Posted: Sat Aug 17, 2013 3:57 am
by Elja98
I'm feeling like a complete idiot right now. I always forget to swap bytes and words when I read hex. I work days on it and after that I find out I have to swap them. But thanks sir!

I changed my code and it works perfect:

Code: Select all

16 bits:
mov	ax, WORD [buffer+28h]
mov	WORD [loc_lfb], ax
mov	ax, WORD [buffer+2Ah]
mov	WORD [loc_lfb+2], ax

32 bits:
PlotPixel:
mul	WORD [BPS]
lea	edx, [ebx*2+eax]
add	edx, [loc_lfb]
mov	[edx], cx

loc_lfb dd 0
Thanks to everybody that helped me :D

Re: Plot pixel at Linear Frame Buffer

Posted: Wed Aug 21, 2013 8:54 pm
by h0bby1
normally you'd rather plot on a backbuffer in memory and then copying the backbuffer on the vesa framebuffer memory, it avoid flickering or out of sync display, the method is the same than explained above but done to a memory buffer, and with vesa you can also have the backbuffer in video memory if you change the access window with a vesa interupt, you can store your pixel in some part of the video memory that is not displayed, and then swap the start address of display memory to display it and then draw the new pixels in the area that is not displayed, i don't remember all the details of doing that, but it's not very good to draw directly to the display framebuffer, with the vesa memory window change, you can have a backbuffer without the need to copy a backbuffer to video memory