Page 2 of 2

Re: 640x480x16 double buffer

Posted: Tue Sep 23, 2008 1:17 pm
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?

Re: 640x480x16 double buffer

Posted: Tue Sep 23, 2008 3:41 pm
by Combuster
Let's just call that software triple-buffering from the start :D

Re: 640x480x16 double buffer

Posted: Tue Sep 23, 2008 4:43 pm
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.

Re: 640x480x16 double buffer

Posted: Thu Sep 25, 2008 7:55 am
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);
	 }
     }
}

Re: 640x480x16 double buffer

Posted: Thu Sep 25, 2008 8:17 am
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.

Re: 640x480x16 double buffer

Posted: Thu Sep 25, 2008 8:42 am
by i586coder
This code is an attempt to make BSAVE BLOAD like QBASIC instruction
in addition to use memory instead of disk :!:

Re: 640x480x16 double buffer

Posted: Thu Sep 25, 2008 8:51 am
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

Re: 640x480x16 double buffer

Posted: Thu Sep 25, 2008 10:35 am
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

Re: 640x480x16 double buffer

Posted: Thu Sep 25, 2008 11:30 am
by i586coder
while(1){
cout<<"Thank you very much Brendan for worthy information"<<endl;
}