it's me again. And my new question is: how to implement double buffering to prevent screen from blinking when it is being re-drawn? I've tried this:
bseg segment
backbuff db BUFFER_SIZE dup (?)
bseg ends
.data
BUFFER_SIZE equ 64000
.code
(...)
;we need to clear buffer first
mov ax, bseg
mov es,ax
mov di, offset backbuff
xor al,al
mov cx,BUFFER_SIZE
rep stosb
(...)
;and now we are writting in buffer. Mode 13h.
;some functions...
(...)
;then,we need to write buffer on screen
mov ax,bseg
mov ds,ax
xor di,di
mov si, offset backbuff
mov cx, BUFFER_SIZE
rep movsb
(...)
but it is very slow :(
maybe i'm wrong, but
BUFFER_SIZE equ 64000
bseg segment
backbuff db BUFFER_SIZE dup (?)
bseg ends
might be better
EQUates do not have to be in a segment
they are assembler constants
also, you could use .DATA? to open a bss segment
i just woke up, so i can't read the code yet :lol:
Half your cx value, then use stosw and movsw -- double-speed! :greenclp:
(or stosd/movsd for 4x, if available)
Quote from: dedndave on June 29, 2014, 10:08:30 PM
also, you could use .DATA? to open a bss segment
depends on what's this :biggrin:
i thought only "segment" to be enough....
QuoteHalf your cx value, then use stosw and movsw -- double-speed!
thank you, now it's done!
i cant just get what's wrong: my program draws new frame much slower than it responds to keyboard buttons pressed. This looks like some lags...
Quote from: ghjjkl on June 29, 2014, 11:46:16 PM
Quote from: dedndave on June 29, 2014, 10:08:30 PM
also, you could use .DATA? to open a bss segment
depends on what's this
i thought only "segment" to be enough....
Hi,
.DATA? is the new fangled simplified segment directive. It is
supposed to be easier to use than the older SEGMENT directive.
They both end up doing something similar. You are using "bseg
segment" to create a specific segment named bseg. Dave uses
.DATA? to reserve space in a default segment named _BSS. You
end up using what you like and understand.
SEGMENT requires you to use an ENDS to limit the segment size
and scope. .DATA? lets you skip that onerous step (if you follow
its rules of course).
Cheers,
Steve N.
well - he's already using .DATA and .CODE :biggrin:
here's an "empty" program template for a Small model EXE with 4K stack...
.MODEL Small
.STACK 4096
.DOSSEG
.386
OPTION CaseMap:None
;####################################################################################
.DATA
;************************************************************************************
.DATA?
;####################################################################################
.CODE
;************************************************************************************
_main PROC FAR
mov dx,@data
mov ds,dx
mov ax,4C00h
int 21h
_main ENDP
;####################################################################################
END _main
I suspect that your speed problems are due to your OS/execution-environment.
The "blinking" is commonly called "flickering" or "tearing". To eliminate it, the screen update, whether done by drawing directly to the display buffer or by copying the contents of a back buffer to the display buffer, must be synchronized with the screen refresh and must be completed within 1-2 refresh periods, depending on various details. At 60Hz, for example, the refresh period would be ~16.6ms, a fairly long time for even a slow system.
For a DOS app, and assuming VGA color, bit 3 of the Input Status #1 Register at I/O port 3DAh indicates when the display is in vertical retrace. For the common case where the screen update is faster than the screen refresh, to synchronize with the screen refresh you should synchronize with the start of vertical retrace. To do this reliably you read the port value in a double loop, waiting for bit 3 to be clear, then waiting for it to be set.
A demo:
;-----------------------------------------------------------------
; Spacebar to toggle sync, Escape to exit, any other key to loop.
;-----------------------------------------------------------------
.model small
.386
.stack
.data
f_sync dw 0
.fardata black
buff0 db 64000 dup(0)
.fardata white
buff1 db 64000 dup(7)
.code
sync proc
mov dx, 3dah
@@:
in al, dx
test al, 1000b
jnz @B
@@:
in al, dx
test al, 1000b
jz @B
ret
sync endp
.startup
mov eax, 13h
int 10h
push 0a000h
pop es
L0:
test f_sync, 1
jz @F
call sync
@@:
mov ecx, 64000/4
xor esi, esi
xor edi, edi
push ds
push seg buff0
pop ds
rep movsd
pop ds
xor ah, ah
int 16h
cmp ah, 1
je L1
cmp ah, 39h
jne @F
xor f_sync, 1
@@:
test f_sync, 1
jz @F
call sync
@@:
mov ecx, 64000/4
xor esi, esi
xor edi, edi
push ds
push seg buff1
pop ds
rep movsd
pop ds
xor ah, ah
int 16h
cmp ah, 1
je L1
cmp ah, 39h
jne @F
xor f_sync, 1
@@:
jmp L0
L1:
.exit
end
MichaelW,
Thank you! I finally got what was an error. I've set sync period too long. So my program worked not fast enough inspite any cpu clock i set in dosbox :biggrin:
back in the days of DOS, we used to write a little speed test to run at initialization
we'd try to estimate how much text could be sent to the display in each refresh period :P
the easy way was to make it work on a 4.77 MHz XT - lol
Dave,
Assuming you had an EGA/VGA adapter, for the text modes the easy way around the problem was to take advantage of the multiple display pages available. You would use an invisible page as a back buffer, and when you finished writing to the page you would make it the visible page. For every adapter that I tested the page switch was fast and, at least effectively, synced with vertical retrace.
it wasn't so bad on EGA/VGA cards
i think a lot of them had synchronous updating or whatever
i seem to recall that TTL and Hercules adapters/monitors were also pretty good in this respect
it was the CGA cards that were the problem
and, probably really bad if you used a composite monitor
windows probably doesn't use the bios code on the video adapter for INT 10h
hell - i don't even know if modern cards have their own video bios - lol
Quote from: dedndave on July 02, 2014, 05:54:48 AM
it wasn't so bad on EGA/VGA cards
i think a lot of them had synchronous updating or whatever
i seem to recall that TTL and Hercules adapters/monitors were also pretty good in this respect
it was the CGA cards that were the problem
and, probably really bad if you used a composite monitor
Yeah, the single port (V?)RAM on the CGA cards was horrible. Can't write during a display read or it would generate snow. There was just enough time (on the 4.77mhz 8088s) during the horizontal retrace to poke one character onto the display (if you did it right, I seem to recall that ROM used a mov, but if you did that from RAM it would still snow due to latency. I believe the RAM version required an xchg?). I can't recall how many characters one could write during the vertical retrace. A couple hundred or so? MDA and EGA on up didn't have that issue, you could write to video RAM at the same time the display controller was reading. Also, EGA added really nice page flipping support. The flip interrupt was rarely used, normally was just done programmatically, but I always thought that was a cool feature.
Seems hard to believe that so little work could be done during the retrace, but even serial comm was tough back then. At max speed of the UART, you had a whopping 410 clock cycles to deal with each incoming byte! On an 8088 with a typical 4 cycle per instruction in the core and the small prefetch queue, AND the 8 bit bottleneck of a memory path... Most apps topped out at 56,700 bps on a 4.77mhz box (unless it was an 8086 or the equivalent NEC V-series with the 16 bit data bus and longer prefetch queue) and required 10mhz to max out the UART! Dropped bytes were not uncommon if you had any kind of TSRs loaded... :-)
but why does keyboard work so slow? If i move some image using my keyboard it moves much slower than if i move picture indirectly, by changing its position in draw cycle.
Quote from: ghjjkl on July 03, 2014, 03:31:20 AM
but why does keyboard work so slow? If i move some image using my keyboard it moves much slower than if i move picture indirectly, by changing its position in draw cycle.
The keyboard has what is known as a "typematic" rate and delay that can be controlled in the BIOS setup, or with Interrupt 16h Function 3. Basically, when you hold a key down for longer than the typematic delay, the keyboard controller starts automatically repeating the key at the typematic rate. The repetition is known as key "rollover". If I recall correctly the default delay is 0.5 seconds, the default rate something like 10 repeats per second, and the maximum rate 30 repeats per second. I posted some code here (http://www.masmforum.com/board/index.php?topic=13604.msg106677#msg106677) that avoids the delay, and allows you control the effective repetition rate by inserting a millisecond-resolution delay in your run loop.
i had no idea about these "features"...
i'm afraid my bad english interferes me to say more than "thank you a lot again" :biggrin:
won't some dos functions work after timer is reprogrammed?
i think the keyboard uses a different timer
on the original IBM PC, there were 3 programmable counter/timers
Quote from: ghjjkl on July 03, 2014, 10:21:17 PM
won't some dos functions work after timer is reprogrammed?
If you are referring to my code reprogramming system timer 0, my Interrupt 8 handler is coded so the previous Interrupt 8 handler gets called at close to the normal rate, so any BIOS or DOS timer based on Interrupt 8 will function normally.