Framerate für Spiel einstellen
Framerate für Spiel einstellen
Nachdem ich es eingesehen habe dass es sinnlos ist
ein Spiel anhand des Soundkartenpuffers zu timen,
das gäbe dann vielleicht sowas wie 20fps und wäre
dann sehr ruckelig, brauche ich Alternativen.
Lieb wäre mir dennoch eine feste Framerate, z.B. 50 fps
Vielleicht den Timer umlenken?
Hätte da noch jemand Empfehlungen?
ein Spiel anhand des Soundkartenpuffers zu timen,
das gäbe dann vielleicht sowas wie 20fps und wäre
dann sehr ruckelig, brauche ich Alternativen.
Lieb wäre mir dennoch eine feste Framerate, z.B. 50 fps
Vielleicht den Timer umlenken?
Hätte da noch jemand Empfehlungen?
mov ax, 13h
int 10h
while vorne_frei do vor;
int 10h
while vorne_frei do vor;
Re: Framerate für Spiel einstellen
Ja, ich habe eine: Lenk den Timer um.
Re: Framerate für Spiel einstellen
zatzen hat geschrieben:Nachdem ich es eingesehen habe dass es sinnlos ist
ein Spiel anhand des Soundkartenpuffers zu timen,
das gäbe dann vielleicht sowas wie 20fps und wäre
dann sehr ruckelig, brauche ich Alternativen.
Lieb wäre mir dennoch eine feste Framerate, z.B. 50 fps
Vielleicht den Timer umlenken?
Hätte da noch jemand Empfehlungen?
Bei Mods (4chn) müßte es eigentlich gehen. Die Ticks werden ja im Standardfall (125 bpm) ja alle 0,02 sec aufgerufen, was 50 Hz entspricht.
Im Regelfall machen die meisten das Timing aber immer über den Timer. Daneben kann man noch das Timing an den Vertical Retrace der VGA orientieren, was im Regelfall je nach Videomode 60 oder70 Hz ergibt. Drittens kann man das Timing noch über Int $15 machen und sich nach einer gewählten Zeit an millisekunden ein Flag setzen lassen. Daneben gibt es bestimmt noch ein paar andere Timing-Methoden. Das Timing mittels Timer ist aber wohl das gängiste und flexibelste.
Re: Framerate für Spiel einstellen
Hi,
das beste ist du liest den Performance-Counter aus. Dann kannst du auch keine Bewegungen abhaengig der vergangenen Zeit berechnen. Das einzig blöde ist dass es den Performance-Counter erst seit dem ur-Pentium gibt. Welche CPU haste denn drin?
TomCat
das beste ist du liest den Performance-Counter aus. Dann kannst du auch keine Bewegungen abhaengig der vergangenen Zeit berechnen. Das einzig blöde ist dass es den Performance-Counter erst seit dem ur-Pentium gibt. Welche CPU haste denn drin?
TomCat
Re: Framerate für Spiel einstellen
Würde ich auf keinen Fall empfehlen.
Erstens limitiert man das Spiel dann zu sehr auf die spezielle Hardware (beim PC kein No-Go) und macht sich vor allem davon abhängig.
Man will ja selbst bestimmen, wie schnell das Spiel läuft, bzw wieviele "Steps" pro Sekunde das Spiel macht - selbst wenn man weniger Framerate bei der Grafikausgabe hat.
Das Problem, was heutzutage leider oft vorkommt, ist, daß unterhalb von bestimmter Systemleistung einfach nur kackenfrech gesagt wird: Geht nicht - anstatt den Benutzer entscheiden zu lassen, ob er mit eingeschränkten Features trotzdem spielen will...
Aber OK, ich schweife ab.
Erstens limitiert man das Spiel dann zu sehr auf die spezielle Hardware (beim PC kein No-Go) und macht sich vor allem davon abhängig.
Man will ja selbst bestimmen, wie schnell das Spiel läuft, bzw wieviele "Steps" pro Sekunde das Spiel macht - selbst wenn man weniger Framerate bei der Grafikausgabe hat.
Das Problem, was heutzutage leider oft vorkommt, ist, daß unterhalb von bestimmter Systemleistung einfach nur kackenfrech gesagt wird: Geht nicht - anstatt den Benutzer entscheiden zu lassen, ob er mit eingeschränkten Features trotzdem spielen will...
Aber OK, ich schweife ab.
Re: Framerate für Spiel einstellen
Wie geht denn das mit dem Performance-Counter. Da ich nur auf 386sx und 486sx programmiere, hat das für mich keine praktische Relevanz. Aber ein kurzes source-Beispiel würde mich schon interessieren oder ein Link auf irgendeine Erklärung hierzu. Beim Googeln habe ich jetzt nämlich nichts gefunden.TomCat hat geschrieben:Hi,
das beste ist du liest den Performance-Counter aus. Dann kannst du auch keine Bewegungen abhaengig der vergangenen Zeit berechnen. Das einzig blöde ist dass es den Performance-Counter erst seit dem ur-Pentium gibt. Welche CPU haste denn drin?
TomCat
Re: Framerate für Spiel einstellen
Damit der Cursorbalken in einem Auswahlmenü beim Drücken der Bewegungstasten und bei unterschiedlich schnellen CPUs nahezu in der gleichen Bewegungsgeschwindigkeit sich bewegt habe ich eine kleines Programm(SPEED.EXE) geschrieben, welches eine Schleife mit 64 NOP-Befehlen eine Sekunde lang durchläuft und danach die Anzahl der Durchläufe in eine Datei(SPEED.tic) schreibt und dessen Anzahl dann als Verzögerungsfaktor verwendet wird. So konnte ich es verhindern das sich der Cursorbalken ggf. zu schnell bewegen läßt und die Menüpunkte sich dann nicht mehr sinnvoll auswählen lassen. Die Verzögerung habe ich damals auf einem 80386DX mit 40mhz eingestellt und das Menü läßt sich auch noch mit meinen Core2quad mit 2800mhz benutzen.
Die erzeugte Datei mit dem Namen "SPEED.tic" ist 4 Byte gross(little endian) und kann von jedem Programm eingeladen und als goben Anhaltspunkt für die Ausführungsgeschwindigkeit verwendet werden.
http://www.alice-dsl.net/freecracmaps/Tool/MENU.ZIP
Dirk
Die erzeugte Datei mit dem Namen "SPEED.tic" ist 4 Byte gross(little endian) und kann von jedem Programm eingeladen und als goben Anhaltspunkt für die Ausführungsgeschwindigkeit verwendet werden.
Code: Alles auswählen
.386P
.387
.CODE
org 100h
Cpu86 = 0 ; Wert als Index in der Takt-Tabelle
Cpu286 = 4
Cpu386 = 8
Cpu486 = 12
Cpu586 = 16
START: mov ax, @DATA
mov ds, ax ; DS auf Daten-Bereich
call GETCPU ; Prozessor-Analyse: AX=CPU
call GETSPEED ; Zählschleife
call FILE ; create a new file
;-------------------------------------
mov ah, 4Ch ; Dos-Rücksprung, Programm-Ende
int 21h
;────────────────────────────────────────────────────────────────────────────
; U N T E R - R O U T I N E N
;────────────────────────────────────────────────────────────────────────────
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
GETCPU: mov ax, Cpu86
xor bx, bx
push bx ; Null auf Stack
popf ; Null in Flagregister
pushf
pop bx ; zurück nach bx
and bh, 0F0h
cmp bh, 0F0h ; wenn gleich, dann 8086
je short CPUOK
;-------------------------------------
mov ax, Cpu286
push 7000h ; dasselbe mit 7000h
popf
pushf
pop bx
and bh, 70h
jz short CPUOK
;-------------------------------------
mov ax, Cpu386
mov edx, esp
and esp, 0FFFCh ; durch vier teilbare Adr.
pushfd
pop ebx
mov ecx, ebx
btc ebx, 18 ; Bit 18 umdrehen
push ebx
popfd
pushfd
pop ebx
push ecx ; alte Flaggen zurück
popfd
mov esp, edx ; Stack zurück
cmp ecx, ebx ; wenn gleich dann 386
jz short CPUOK
;-------------------------------------
mov ax, Cpu486
btc ecx, 21
push ecx
popfd
pushfd
pop ebx
cmp ebx, ecx ; wenn ungleich, dann 486
jnz short CPUOK
;-------------------------------------
mov ax, Cpu586 ; sonst Pentium
;----------------------------------------------------------------------------
CPUOK: mov bp, ax
ret ; AX=Cpu
;────────────────────────────────────────────────────────────────────────────
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
GETSPEED: cli ; Interrupt's verbieten
xor ax, ax
mov es, ax ; ES auf Seg.: 0
;-------------------------------------
mov di, es:[20h] ; Vector von INT 8 retten (Offset)
mov si, es:[22h] ; (Segment)
;-------------------------------------
mov es:[20h], OFFSET NEUVEC ; Interrupt-Vector von INT 8
mov es:[22h], cs ; auf neue Routine legen
;-------------------------------------
mov al, 36h ; RUNDE auf 18,2 Hertz (Standart)
out 43h, al
xor al, al
out 40h, al ; low
out 40h, al ; high
;-------------------------------------
cmp bp, 8 ; 32-Bit-CPU ?
jb short M16
jmp M32
;---------------------------------------------------------------------------
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
M16: mov bp, 1 ; Aktiv-Flag = IRQ-Ende wenn 0
xor cx, cx ; Zähler low
xor dx, dx ; Zähler high
sti ; neuen Interrupt 8 starten
;-------------------------------------
S1: and bp, bp ; Auf IRQ-Ende warten
jnz S1
mov bp, 1 ; Für's Zählen IRQ Aktiv-Flag setzen
;-------------------------------------
S2: inc cx ; Hauptzählschleife
jnz short S3
inc dx
;-------------------------------------
S3: nop ; 64 Nop's
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
;-------------------------------------
and bp, bp ; auf Timer-IRQ-Ende abfragen
jnz S2 ; weiter, wenn Timer-IRQ noch aktiv
;-------------------------------
mov RUNDE, cx ; Zähler low retten
mov RUNDE+2, dx ; Zähler high retten
;---------------------------------------------------------------------------
ANALYS: cli ; Interrupts verbieten
mov es:[20h], di ; alten Interrupt-Vector
mov es:[22h], si ; von INT 8 wiederherstellen
sti ; Interrupts erlauben
ret
;────────────────────────────────────────────────────────────────────────────
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
M32: mov bp, 1 ; Aktiv-Flag = IRQ-Ende wenn 0
xor ecx, ecx ; Zähler
sti ; neuen Interrupt 8 starten
;-------------------------------------
S4: and bp, bp ; Auf IRQ-Ende warten
jnz S4
;-------------------------------------
mov bp, 1 ; Für's Zählen IRQ Aktiv-Flag setzen
;-------------------------------------
S5: inc ecx ; Hauptzählschleife
nop ; 64 Nop's
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
;-------------------------------------
and bp, bp ; auf Timer-IRQ-Ende abfragen
jnz S5 ; weiter, wenn Timer-IRQ noch aktiv
;---------------------------------------------------------------------------
mov DWORD PTR[RUNDE], ecx ; Zähler retten
jmp ANALYS
;────────────────────────────────────────────────────────────────────────────
; neue I R Q - R o u t i n e für INT 8
;────────────────────────────────────────────────────────────────────────────
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
NEUVEC: mov al, 20h ; neue IRQ-Routine für INT 8
dec bp ; Aktiv-Flag löschen
out 20h, al ; =EOI
iret
;────────────────────────────────────────────────────────────────────────────
org START + ((($-START)/16)*16) + 16
;---------------------------------------------------------------------------
FILE: mov dx, OFFSET SPEEDNAM
xor cx, cx
mov ah, 3Ch ; Datei erstellen
int 21h
mov bx, ax
;---------------------------------------
mov dx, OFFSET RUNDE
mov cx, 4
mov ah, 40h ; Datei beschreiben
int 21h
;---------------------------------------
mov ah, 3Eh ; Datei schließen
int 21h
ret
;────────────────────────────────────────────────────────────────────────────
; D A T E N - B E R E I C H
;────────────────────────────────────────────────────────────────────────────
org START + ((($-START)/64)*64) + 64
;---------------------------------------------------------------------------
.DATA
org 0
;---------------------------------------------------------------------------
RUNDE DW 0, 0 ; Anzahl der Schleifen-Durchläufe
SPEEDNAM DB "SPEED.tic", 0
;────────────────────────────────────────────────────────────────────────────
.STACK 20h
end
Dirk
Re: Framerate für Spiel einstellen
wobo hat geschrieben:Wie geht denn das mit dem Performance-Counter. Da ich nur auf 386sx und 486sx programmiere, hat das für mich keine praktische Relevanz. Aber ein kurzes source-Beispiel würde mich schon interessieren oder ein Link auf irgendeine Erklärung hierzu. Beim Googeln habe ich jetzt nämlich nichts gefunden.TomCat hat geschrieben:Hi,
das beste ist du liest den Performance-Counter aus. Dann kannst du auch keine Bewegungen abhaengig der vergangenen Zeit berechnen. Das einzig blöde ist dass es den Performance-Counter erst seit dem ur-Pentium gibt. Welche CPU haste denn drin?
TomCat
der ASM-Befehl lautet:
rdtsc
und liefert den Inhalt des Performance-Counters in EDX:EAX als 64-Bit Zahl sozusagen zurück. Er zählt mit der Taktfrequenz der CPU hoch. Allerdings wie ich schaon sagte gibts den erst seit dem Ur-Pentium und nicht bei 486er oder noch tiefer.
Also um auch in 286er 386 exakte zeiten zu messen und komfortabel benutzen zu koennen gibts ne andere sehr gute Methode.
Re: Framerate für Spiel einstellen
Ich habe in Xpyderz irgendwann einen Workaround eingebaut. Normalerweise stelle ich ja den Ticker auf die gewünschte Frequenz und er tickt dann fröhlich vor sich hin. Problem ist, daß zB unter WinNT4 und Win2000 (also NT-Linie, betrifft aber NICHT WinXP, da haben sie es wohl gefixt) der Ticker nachträglich wieder irgendwie umgeändert... was weiß ich.
Daher messe ich die Durchläufe pro Sekunde, indem ich die BIOS-Uhr benutze. D.h. ich warte, bis die Sekunde umschaltet, dann zähle ich die Tickerdurchläufe, bis die nächste Sekunde umschaltet.
Und daraufhin passe ich den Tickerwert neu an, damit am Ende das richtige Ergebnis herauskommt.
Ich weiß, das ist totaler Voodoo, aber es funktioniert.
Und eigentlich hätte ich es nicht machen müssen, da Xpyderz ein DOS-Spiel ist und wenn es unter anderen OS nicht richtig funktioniert, ist es eigentlich nicht meine Schuld. Aber ich hatte es zufällig mal auf den besagten Windowsen getestet und es hat mich eben gestört, daß es nicht richtig funktionierte. Tschuldigung, daß ich so oft dieses dämliche Spiel erwähne, aber ich schätze eben, daß auch andere von meinen Erfahrungen profitieren können - so wie ich es von den Erfahrungen anderer ebenfalls tue.
Daher messe ich die Durchläufe pro Sekunde, indem ich die BIOS-Uhr benutze. D.h. ich warte, bis die Sekunde umschaltet, dann zähle ich die Tickerdurchläufe, bis die nächste Sekunde umschaltet.
Und daraufhin passe ich den Tickerwert neu an, damit am Ende das richtige Ergebnis herauskommt.
Ich weiß, das ist totaler Voodoo, aber es funktioniert.
Und eigentlich hätte ich es nicht machen müssen, da Xpyderz ein DOS-Spiel ist und wenn es unter anderen OS nicht richtig funktioniert, ist es eigentlich nicht meine Schuld. Aber ich hatte es zufällig mal auf den besagten Windowsen getestet und es hat mich eben gestört, daß es nicht richtig funktionierte. Tschuldigung, daß ich so oft dieses dämliche Spiel erwähne, aber ich schätze eben, daß auch andere von meinen Erfahrungen profitieren können - so wie ich es von den Erfahrungen anderer ebenfalls tue.
Re: Framerate für Spiel einstellen
Dazu habe ich nun auch ein kleines Beispiel von Ralph Bauer gefunden:TomCat hat geschrieben:der ASM-Befehl lautet:
rdtsc
und liefert den Inhalt des Performance-Counters in EDX:EAX als 64-Bit Zahl sozusagen zurück. Er zählt mit der Taktfrequenz der CPU hoch. Allerdings wie ich schaon sagte gibts den erst seit dem Ur-Pentium und nicht bei 486er oder noch tiefer.
Also um auch in 286er 386 exakte zeiten zu messen und komfortabel benutzen zu koennen gibts ne andere sehr gute Methode.
http://dcla.rkhb.de/rdtsc.html
Weitere Hinweise:
http://en.wikipedia.org/wiki/Time_Stamp_Counter
Neben dem TSC gibt es nun auch noch den Power Management Timer (PMTIMER) und den High Precision Event Timer(HPET) und auch (locale) Advanced Programmable Interrupt Controller(APIC).Starting with the Pentium Pro, Intel processors have supported out-of-order execution, where instructions are not necessarily performed in the order they appear in the executable. This can cause RDTSC to be executed later than expected, producing a misleading cycle count.[3] This problem can be solved by executing a serializing instruction, such as CPUID, to force every preceding instruction to complete before allowing the program to continue, or by using the RDTSCP instruction, which is a serializing variant of the RDTSC instruction (starting from Core i7[4] and starting from AMD Athlon 64 X2 CPUs with AM2 Socket (Windsor & Brisbane)).
Dirk
Re: Framerate für Spiel einstellen
Naja, wie gesagt - für so etwas Simples wie ein Spiel/Programm vernünftig zu timen würde ich nicht gleich einen Pentium als Mindestvoraussetzung ansetzen. Aber das ist natürlich nur, was ich machen bzw nicht machen würde - das wird natürlich jeder für sich selbst entscheiden.