640x480x16 double buffer

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
codemastersnake
Member
Member
Posts: 148
Joined: Sun Nov 07, 2004 12:00 am
Contact:

Re: 640x480x16 double buffer

Post by codemastersnake »

I would really suggest the double buffering technique that was used back in good ol' dayz when DOS games existed....

It's pretty quick and was used professionally...

I think following algo could work as well:

1) create a buffer in main memory
2) create a pointer to video memory
3) update all the things in buffer not directly to video memory
4) install a timer that updates screen by using data from buffer after a specific interval
5) the timer IRQ should manage retrace and all the hardware related problems...

I guess I just discovered a way ;) well maybe I'll use it in my OS's next release...

What do you all have to say about this psuedo code?
User avatar
Combuster
Member
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:

Re: 640x480x16 double buffer

Post by Combuster »

Let's just call that software triple-buffering from the start :D
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
pcmattman
Member
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:

Re: 640x480x16 double buffer

Post by pcmattman »

For even faster implementation you could use dirty rectangles, which are basically regions of that in-RAM buffer that need to be copied to video RAM. So, rather than copying the entire buffer, you only copy regions that have been updated since the last redraw.

Although, you might want to actually get a GUI working first before you worry about things like that, otherwise you'll not know whether the reason your screen is going blank is the dirty rectangles implementation or something wrong in your GUI code.
User avatar
i586coder
Member
Member
Posts: 143
Joined: Sat Sep 20, 2008 6:43 am

Re: 640x480x16 double buffer

Post by i586coder »

Hi guy's :D

I studied your comment well and
developed this programe,...,i need your reply
note: use Turob C++ 3.1 compiler with large memory model

Code: Select all

#define buffer_base 0x50000000L //my buffer segment
#define size 38400              //bytes

enum type0x12{save=1,load};
typedef unsigned char far fbyte;

void screen0x12(type0x12 rw){
     for(int i=0; i<3; i++){//Cycle through 4 bit plane of EGA/VGA.
	 if(rw==load){//load buffer
	    outp(0x3c4,2);//index the map register.
	    outp(0x3c5,(int)pow(2.0,(float)i));//Bit plane to reference.
	    //Load each segment into its corresponding bit plane.
	    _fmemcpy((fbyte)0xA0000000L,(void far*)(buffer_base+(i*0x10000000L)),size);
	 }
	 else{//save to buffer
	    outp(0x3ce,4);//Select Read Map Select Register.
	    outp(0x3cf,i);//Select the bit plane to save.
	    _fmemcpy((void far*)(buffer_base+(i*0x10000000L)),(fbyte)0xA0000000L,size);
	 }
     }
}
Distance doesn't make you any smaller,
but it does make you part of a larger picture.
ru2aqare
Member
Member
Posts: 342
Joined: Fri Jul 11, 2008 5:15 am
Location: Hungary

Re: 640x480x16 double buffer

Post by ru2aqare »

I have no idea what this program does, however I would like to highlight some points concerning the code.

First,

Code: Select all

void screen0x12(type0x12 rw)
{
     for(int i=0; i<3; i++){//Cycle through 4 bit plane of EGA/VGA.
If you have four bit planes, it should be

Code: Select all

     for(int i=0; i<4; i++){//Cycle through 4 bit plane of EGA/VGA.
My other point is

Code: Select all

	    outp(0x3c4,2);//index the map register.
	    outp(0x3c5,(int)pow(2.0,(float)i));//Bit plane to reference.
Using a bit shift is much faster, especially under Turbo C or Turbo Pascal, which uses emulation for floating-point instructions.

Code: Select all

	    outp(0x3c4,2);//index the map register.
	    outp(0x3c5, 1 << i);//Bit plane to reference.
Besides,

Code: Select all

	    //Load each segment into its corresponding bit plane.
	    _fmemcpy((fbyte)0xA0000000L,(void far*)(buffer_base+(i*0x10000000L)),size);
If you are in real mode, you need to use segmented addressing. If I remember correctly, you have to use a MK_FP macro, or something similar.

Code: Select all

	    _fmemcpy((fbyte) MK_FP(0xA000, 0), (void far*)MK_FP(buffer_seg, buffer_offset),size);
Pushing a long value (32-bit in real mode) down the stack may work, because it is interpreted as segment:offset by the function called, however it may break anytime you change the address.
User avatar
i586coder
Member
Member
Posts: 143
Joined: Sat Sep 20, 2008 6:43 am

Re: 640x480x16 double buffer

Post by i586coder »

This code is an attempt to make BSAVE BLOAD like QBASIC instruction
in addition to use memory instead of disk :!:
Distance doesn't make you any smaller,
but it does make you part of a larger picture.
User avatar
i586coder
Member
Member
Posts: 143
Joined: Sat Sep 20, 2008 6:43 am

Re: 640x480x16 double buffer

Post by i586coder »

anyway i need some things to kill flicker in screen mode 0x12.

I think this screen mode or VESA mode isn't look like famous screen 0x13 #-o
Distance doesn't make you any smaller,
but it does make you part of a larger picture.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: 640x480x16 double buffer

Post by Brendan »

Hi,
AhmadTayseerDajani wrote:anyway i need some things to kill flicker in screen mode 0x12.
Before you blit the buffer to display memory, you could wait for vertical retrace to start. Note: "vertical retrace" is the time it takes the video card's signal to go from the bottom right corner of the screen to the top left corner of the screen; where the video isn't using video display memory (and where you can change video display memory without worrying about half a frame being displayed, or sheering effects, or flicker).

The code goes something like this:

Code: Select all

        mov dx, 0x03DA         ;dl = VGA misc register #1
.l1:    in al, dl              ;al = value from VGA misc register #1
        test al, 8             ;Is the "retrace not in progress" bit set?
        jnz .l1                ; yes, wait until the retrace isn't in progress

.l2:    in al, dl              ;al = value from VGA misc register #1
        test al, 8             ;Is the "retrace not in progress" bit set?
        jnz .l2                ; no, wait until the retrace is in progress
There's 2 problems here:
  • It can waste a lot of CPU time. The retrace would happen 60 times per second for standard 640 * 480 VGA mode, so you could waste up to 16.66 ms of CPU time while you're waiting for the retrace to start, which adds up to millions of cycles for modern computers.
  • The blit may be too slow to update all 4 planes before the retrace ends (especially on old/slow computers). In this case you'd get flicker even though you are waiting for retrace to start.
To avoid the first problem you could try using a vertical retrace IRQ, but that's non-standard (not supported most of the time). However, it is possible to use some other timer to emulate a vertical retrace IRQ. For example, you'd wait for the vertical retrace to start (like above), then program the PIT chip to generate an IRQ in about 10 ms time. When the PIT IRQ occurs you'd wait for retrace to start again (but it'd only take about 2 ms because you've been running other code for 10 ms), reprogram the PIT again, etc. You can also dynamically adjust the PIT timer's delay to reduce the time spent polling as much as possible (just be careful of "IRQ jitter").

To avoid the second problem (and to reduce the time spend in the vertical retrace IRQ handler, if used) it's possible to use page flipping. The idea is that you use two areas in video display memory - an "active" area that the video card is displaying and a "work" area that you can modify without worrying much about (because it isn't being displayed). When you're ready to display the next frame it's already in display memory, and all you do is reprogram the VGA's "Start Address High Register" and "Start Address Low Register" so that the "work" area becomes the "active" area and the "active" area becomes the "work" area. This method requires more video display memory, but all modern video cards will have enough video display memory anyway. Another option would be to use dirty rectangles or some other way to avoid updating parts of video display memory that didn't change since last time.

You could also combine all of the above. For example, you draw data into your buffer in RAM (while keeping track of which areas were modified), and when you're ready you blit areas that did change from your buffer in RAM to the "work" buffer in video display memory, and then your (real or emulated) vertical retrace IRQ does a "page flip" during the next vertical retrace to make the new frame visible.

Of course all of this may be overkill - the extra complexity may or may not be worth the hassle...


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
i586coder
Member
Member
Posts: 143
Joined: Sat Sep 20, 2008 6:43 am

Re: 640x480x16 double buffer

Post by i586coder »

while(1){
cout<<"Thank you very much Brendan for worthy information"<<endl;
}
Distance doesn't make you any smaller,
but it does make you part of a larger picture.
Post Reply