vesa lfb - how to avoid flickering
vesa lfb - how to avoid flickering
as the topic says...
is there any way to avoid flickering on vesa 2.0 using a linear framebuffer.
maybe something like double buffering ( painting to offscreen memory and flipping onscreen/offscreen memory)?
is there any way to avoid flickering on vesa 2.0 using a linear framebuffer.
maybe something like double buffering ( painting to offscreen memory and flipping onscreen/offscreen memory)?
- AndrewAPrice
- Member
- Posts: 2309
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: vesa lfb - how to avoid flickering
Their could be some sort of double buffering built in, but I'm no VESA expert. Until I found such a feature I would allocate a memory, do all my drawing in that buffer, and then to update what's on the screen I'd copy straight from my buffer to the frame buffer. That's essentially double buffering.ezome wrote:as the topic says...
is there any way to avoid flickering on vesa 2.0 using a linear framebuffer.
maybe something like double buffering ( painting to offscreen memory and flipping onscreen/offscreen memory)?
But I've read "VBE 3.0 has support for triple buffering" somewhere which makes me wonder if VBE 1/2 has in-built double buffering functions. This would save memory since you may not need to allocate more memory. I don't know.
My OS is Perception.
Re: vesa lfb - how to avoid flickering
i thought about that but the problem is to find the right moment to copyMessiahAndrw wrote:I would allocate a memory, do all my drawing in that buffer, and then to update what's on the screen I'd copy straight from my buffer to the frame buffer. That's essentially double buffering.
if you copy your buffer while the old buffer is drawn to the screen you end up with half old/half new image on the screen
so in this case i would need some sort of sync
- AndrewAPrice
- Member
- Posts: 2309
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Do the copying inside your flip() (or similar) function, which you call after you have finished updating everything on the screen.
My OS is Perception.
You can test for Verticle Retrace, something like this:
But i have found it make no differance for vesa or as it's for VGA, it does not work for vesa, but by double buffering, you will get rid of the flickering.
Code: Select all
FullVertWait:
mov dx,3dah
Vr:
in al,dx
test al,8
jnz Vr ;wait until Verticle Retrace starts
Nvr:
IN al,dx
test al,8
jz Nvr ;wait until Verticle Retrace Ends
ret
i don't got a flip functionMessiahAndrw wrote:Do the copying inside your flip() (or similar)
function, which you call after you have finished updating everything on
the screen.
i just draw my stuff to the framebuffer and at some point i don't
know the graphic card updates the screen
what is Verticle Retrace?Dex wrote:You can test for Verticle Retrace, something like this:But i have found it make no differance for vesa or as it's for VGA,Code: Select all
FullVertWait: mov dx,3dah Vr: in al,dx test al,8 jnz Vr ;wait until Verticle Retrace starts Nvr: IN al,dx test al,8 jz Nvr ;wait until Verticle Retrace Ends ret
it does not work for vesa, but by double buffering, you will get rid
of the flickering.
however to implement double buffering i would need the know the
moment after an update is finished and be able to tell vesa which
memory address to use as framebuffer for the next update.
or am i missing something?
-
- 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:
Basically, all your functions that draw stuff draw to a RAM-based framebuffer (NOT the vesa one). Then, once you need them displayed, you call flip, which copies the RAM-based framebuffer into the vesa framebuffer - for example:
Code: Select all
// assume 0xE0000000 is the VESA lfb
// double buffer
char* dbuff;
void init_vesa()
{
// .... do your vesa mode switch .... //
// create a second buffer big enough
dbuff = (char*) malloc( 640 * 480 * 8 ); // 32-bit
}
void draw_things()
{
circle( 1, 2, 4 );
square( 5, 6, 2 );
rect( 9, 10, 11, 12 );
}
void flip()
{
// faster ways to do this, but for example purposes
// you get the idea
memcpy( (char*) 0xE0000000, dbuff, 640 * 480 * 8 );
}
void main()
{
while( 1 )
{
draw_things();
flip();
}
}
By using the flip method I've shown above, you should be able to stop the flickering problem.however to implement double buffering i would need the know the
moment after an update is finished and be able to tell vesa which
memory address to use as framebuffer for the next update.
When your VGA programing you call the function i posted than on return, you move you buffer to screen.
But i am not sure if this still works for vesa.
I have done alot of vesa programing, but have alway used a buffer in ram, than when i have finish updating buffer i write it to screen.
Now with vesa, if your using 32BPP, you need to test the BPP as some cards use 24bits and others use 32bits.
Now if you use double buffering as above, you will get no flicker or tearing, even without doing Verticle Retrace ( http://www.computerhope.com/jargon/v/vertretr.htm ).
Also note, that if you are coding a Gui, its best to update mouse pointer direct to screen, i have found it best that way anyway.
But i am not sure if this still works for vesa.
I have done alot of vesa programing, but have alway used a buffer in ram, than when i have finish updating buffer i write it to screen.
Now with vesa, if your using 32BPP, you need to test the BPP as some cards use 24bits and others use 32bits.
Now if you use double buffering as above, you will get no flicker or tearing, even without doing Verticle Retrace ( http://www.computerhope.com/jargon/v/vertretr.htm ).
Also note, that if you are coding a Gui, its best to update mouse pointer direct to screen, i have found it best that way anyway.
ok ill try thatDex wrote:When your VGA programing you call the function i posted than on return, you move you buffer to screen.
But i am not sure if this still works for vesa.
however i guess i don't understand how the graphic card uses the lfb to update the screen because in my understanding even if i use memcpy i could change the buffer while the graphic card is updating the screen.
is there any article about that?
i would also like an article about vga programming including compatibility issues.
currently i fixed my os on 800x600x24 VBE2 because it seems to be available on most systems and i'm more interested in os internals than in gui anyway
thanks ez
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Basically, the video card is a piece of memory and a GPU. The memory is shared between the GPU and the rest of the system - both can read and write to it at about the same time. Part of the GPU is responsible for generating the video output - it reads in bytes from video memory, converts them to colors, and put those on the output, then reads a new set of bytes and repeats the process. In essence, the video card can be trying to read from memory when you are writing to it, the effects are noticeable after only a few pixels. When doublebuffering, you copy the buffer in one piece. the video card will only change once from old to new data (if your code is uninterrupted). Tearing is reduced because there is only one scanline where the bottom and top half (original and new) do not match up.ezome wrote:however i guess i don't understand how the graphic card uses the lfb to update the screen because in my understanding even if i use memcpy i could change the buffer while the graphic card is updating the screen.
VGA Hardware on the wiki, and there's an book called Graphics Programming Black Book which contains useful information on the subject (free download as pdf, google).i would also like an article about vga programming including compatibility issues.
ok let me explain how i understood what you saidCombuster wrote: Basically, the video card is a piece of memory and a GPU. The memory is shared between the GPU and the rest of the system - both can read and write to it at about the same time. Part of the GPU is responsible for generating the video output - it reads in bytes from video memory, converts them to colors, and put those on the output, then reads a new set of bytes and repeats the process. In essence, the video card can be trying to read from memory when you are writing to it, the effects are noticeable after only a few pixels. When doublebuffering, you copy the buffer in one piece. the video card will only change once from old to new data (if your code is uninterrupted). Tearing is reduced because there is only one scanline where the bottom and top half (original and new) do not match up.
we got the cpu, ram, videomemory and the gpu
do you mean ram or video memory when you talk about memory?
when you say shared between gpu and the rest of the system do you
mean some block of memory in ram is shared between gpu and cpu?
if thats true than how is memory transfered to the gpu?
does the gpu paint data from ram or from video memory?
if the gpu paints from video memory does it copy the lfb in one piece or
in little chunks to video memory?
yeah alot of questions i know. maybe i'm stupid
![Wink :wink:](./images/smilies/icon_wink.gif)
but i just hate coding such stuff as long as i don't understand whats
going on
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Video memory is a form of ram, only located on the card rather than on the motherboard. When programming VBE modes, the other differences are neglegible.ezome wrote:we got the cpu, ram, videomemory and the gpu do you mean ram or video memory when you talk about memory?
Yes. In most cases, its the video ram, but IIRC intel chipsets share system ram.when you say shared between gpu and the rest of the system do you mean some block of memory in ram is shared between gpu and cpu?
Like any other multiprocessor system. both the CPU and GPU want access to the memory, and the chipset of the video card will arrange things so they both get what they want.if thats true than how is memory transfered to the gpu?
See the notes above.does the gpu paint data from ram or from video memory?
The LFB is video memory.if the gpu paints from video memory does it copy the lfb in one piece or in little chunks to video memory?
Compliments for the attitude.but i just hate coding such stuff as long as i don't understand whats
going on
A diagram:
Code: Select all
CPU
|
============ system bus
| |
RAM PCI controller
|
============= PCI bus
| |
other +--- | ---+
devices | ===== |
| | | | <- video card
| GPU RAM |
+- | -----+
|
Monitor
The GPU can read and write to memory just as good (usually, its better at it) as the processor can - and it can just as well access everything it is (indirectly) connected to. Normally it won't stick his nose out of his box, but if you tell him to, it will talk to the monitor, and if you know how, it will even read from system memory even though that is quite a bit away (that process is called DMA).
When in VESA mode, the GPU just reads bits from the memory, and forwards them to the monitor. That means for every frame, the contents of memory is sent to the display.
Since the CPU has also access to the same bit of RAM, the CPU might change the contents of it during one of the GPU's cycles. The GPU doesn't bother, but from the user's perspective it seems as if you see parts of several screens. Tearing results when one of those screens is a intermediate of the drawing process, i.e. it is not the screen you previously drew, nor is it the screen that you want the user to see next time around. By keeping those intermediates out of the area where the GPU finds its data for the screen, you can eliminate tearing. Many alternatives are available, including double-buffering, triple-buffering, page-flipping and using the vertical retrace interval. Double buffering is the easiest - you simply keep a copy of the screen somewhere the user can't see it, then copy it to the video card's visible area once its in a state ready for the user to view. That way intermediates are only present in non-visible memory and can not contribute to tearing effects.
The other three methods are more advanced, but require special support from the video card. With a VGA, you have all options at your disposal.
thanks great explanation
so if i get it right...
let's assume i got a pci graphic card with seperate video memory
and i'm using vbe
in this case when writing to the address provided as lfb i think i'm writing
to system memory but actually i'm writing to video memory on the pci card
ok now i got a last question
lets assume we loaded 2 bitmaps to system memory
the first bitmap is located at void* bmp1
the second bitmap is located at void* bmp2
and the lfb is located at void* lfb
so bmp1 and bmp2 point to different locations in system memory and lfb
points to video memory
now what happens if we do this:
-copy bmp1 to lfb
-do something till one half of bmp1 is displayed
-copy bmp2 to lfb
don't we end up with bmp1 on the top half of the screen and bmp2 on the
bottom half of the screen for one single frame?
on the next frame of course only bmp2 would be displayed.
something like this Verticle Retrace Dex mentioned before just for VBE
if so how do we make sure that on frame1 bmp1 is dislayed completely
and on frame2 bmp2 is displayed completely
so if i get it right...
let's assume i got a pci graphic card with seperate video memory
and i'm using vbe
in this case when writing to the address provided as lfb i think i'm writing
to system memory but actually i'm writing to video memory on the pci card
ok now i got a last question
lets assume we loaded 2 bitmaps to system memory
the first bitmap is located at void* bmp1
the second bitmap is located at void* bmp2
and the lfb is located at void* lfb
so bmp1 and bmp2 point to different locations in system memory and lfb
points to video memory
now what happens if we do this:
-copy bmp1 to lfb
-do something till one half of bmp1 is displayed
-copy bmp2 to lfb
don't we end up with bmp1 on the top half of the screen and bmp2 on the
bottom half of the screen for one single frame?
on the next frame of course only bmp2 would be displayed.
something like this Verticle Retrace Dex mentioned before just for VBE
if so how do we make sure that on frame1 bmp1 is dislayed completely
and on frame2 bmp2 is displayed completely
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
You got the idea
VBE can tell you if the video card supports the VGA register set, after which you can use some VGA knowledge to detect the retrace. If it isn't, triple buffering may be available that will allow you to a page flip during the vertical retrace. If both are unavailable, VBE can not help you.
![Very Happy :D](./images/smilies/icon_biggrin.gif)
The Vertical Retrace is the period when the GPU does not send data to the screen, other than that it just finished one. If you wait for the Vertical Retrace before doing some operations, you know you can change the contents of video memory for a short time without anyone seeing it. Under normal circumstances, it is enough to copy the buffers over. However, to detect the Vertical Synchronization Pulse (which indicates the Vertical Retrace period) is a hardware-specific thing.something like this Verticle Retrace Dex mentioned before just for VBE
if so how do we make sure that on frame1 bmp1 is dislayed completely
and on frame2 bmp2 is displayed completely
VBE can tell you if the video card supports the VGA register set, after which you can use some VGA knowledge to detect the retrace. If it isn't, triple buffering may be available that will allow you to a page flip during the vertical retrace. If both are unavailable, VBE can not help you.
I would just like to add one thing to the info so far posted, I in the old days programming VGA always used V retrace, before writing buffer to screen to avoid tear out.
But i have found with vesa that if you write use double buffering and write the back buffer to screen, you never get tear out,even without V-retrace, why i do not know.
So all you need to do is call something like this:
And you will get no flicking.
NOTE: The above code is unoptimised and hardcoded for one res, also the vesa buffer has been written to acording to the BPP.
Also you can test V-retrace by useing it as a simple timer in your code, example:
Works for none critical time, 60 = 1 second.
But i have found with vesa that if you write use double buffering and write the back buffer to screen, you never get tear out,even without V-retrace, why i do not know.
So all you need to do is call something like this:
Code: Select all
;----------------------------------------------------;
; BuffToScreen. ;Puts whats in the buffer to screen ;
;----------------------------------------------------;
BuffToScreen:
pushad
push es
mov ax,linear_sel
mov es,ax
mov esi,[VesaBuffer] ; Main Ram
mov edi,[ModeInfo_PhysBasePtr] ; Graphic card Ram
mov ecx,640*480
cmp [ModeInfo_BitsPerPixel],24 ; You must test this
jne @f
mov ecx,0x38400
@@:
cld
cli
rep movsd
sti
pop es
popad
ret
NOTE: The above code is unoptimised and hardcoded for one res, also the vesa buffer has been written to acording to the BPP.
Also you can test V-retrace by useing it as a simple timer in your code, example:
Works for none critical time, 60 = 1 second.
Code: Select all
BITS 16
ORG 100h
SECTION .text
START:
xor ah,ah
int 16h
mov word[count],0
ddf:
call FullVertWait
cmp word [count],60
jne ddf
;Do some thing in here
xor ah, ah
int 16h
mov ax, 04c00h
int 21h
;**************************
FullVertWait:
MOV DX,3DAh
Vr:
IN AL,DX
TEST AL,8
JNZ Vr ;wait until Verticle Retrace starts
Nvr:
IN AL,DX
TEST AL,8
JZ Nvr ;wait until Verticle Retrace Ends
ADD word[count],1
RET
;**************************
SECTION .data
count dw 0