begin process at 2012 02 09 06:54:19
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

OpenGL

 > LIMITER NOMBRE FPS [OPENGL & QUERYPERFORMANCE & DEVCPP]

LIMITER NOMBRE FPS [OPENGL & QUERYPERFORMANCE & DEVCPP]


 Information sur la source

Note :
8 / 10 - par 1 personne
8,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :OpenGL Niveau :Initié Date de création :07/09/2004 Date de mise à jour :16/09/2004 21:49:55 Vu / téléchargé :8 206 / 502

Auteur : BeLZeL

Ecrire un message privé
Site perso
Commentaire sur cette source (31)
Ajouter un commentaire et/ou une note

 Description

Cliquez pour voir la capture en taille normale
Dans la plupart des jeux, il est possible de limiter le nombre d'images par seconde (FPS, frames per second) que peut afficher un jeu.

Il est souvent inutile de gaspiller du temps machine pour afficher jusqu'à 3000 FPS avec des cartes graphiques dernier cri (aaaaaahhh !). L'oeil n'en percoit qu'une centaine au maximum.

Ce programme :
* calcule le nombre de FPS.
* limite le nombre de FPS selon votre choix.
* déplace les objets selon la méthode du TimeStep (déplacement en fonction du temps).
* toutes les valeurs des variables sont affichées en temps réel (toutes les 1s).

Comment faire ?

* Le principal soucis pour calculer le nombre d'images par seconde est de réussir à trouver des fonctions de timing très précises. Les fonctions classiques sont trop imprécises (de l'ordre de 1 à 10 ms). C'est une précision insuffisante lorsqu'on désire afficher plus de 100 FPS (ca nous fait une image toutes les 10ms ou moins). Les seules fonctions intéressantes sont QueryPerformanceFrequency et QueryPerformanceCounter (qui existent bien sur tous les processeurs, quoi qu'en dise la MSDN, qui doit dater un peu). Leur seul inconvénient est de ne pas donner directement le temps, il faut au préalable diviser le nombre de cycle par la fréquence du nombre de cycles par seconde. Il y a donc un coût en temps supplémentaire pour les divisions et également un coût en mémoire pour stocker les résultats en seconde dans des variables de type double.

* Le nombre de cycles est un résultat beaucoup plus précis que le millième de seconde. Un cycle correspond environ (sur mon PC, Barton 3200+) à 270 nano secondes.

* Pour calculer le nombre de frames par seconde (FPS), nous allons comptabiliser toutes les frames affichées (temps.nbFrames). Ensuite, toutes les secondes, on affiche le résultat et on remet le compteur à 0. Le résultat est assez précis.

* Pour limiter le nombre de FPS, il faut 2 variables. Il faut comptabiliser le nombre de cycles maintenant (temps.cSuiv) et le nombre de cycles pour la prochaine frame (temps.cSuiv). Dès que temps.cNow > temps.cSuiv, on dessine une nouvelle image et on augmente temps.cSuiv. Si on veut beaucoup de FPS, on ajoutera un peu de cycles à temps.cSuiv, ou inversement.

* Pour animer un objet, on n'incrémentera pas son déplacement de manière statique à chaque image (pos++). On utilisera le temps qu'il s'est écoulé entre deux frames (pos += temps.cSuiv - temps.cPrec) pour savoir où l'objet sera placé.

* Concernant l'affichage OpenGL, la fonction glutSwapBuffers() permet un affichage en double buffering. Il faut uniquement l'utiliser lorsqu'on est sur le point d'afficher une nouvelle image (temps.cNow > temps.cSuiv). La fonction glutPostRedisplay() permet de redemander l'affichage d'une nouvelle image, il faut toujours utiliser cette fonction à la fin de l'affichage, que la frame précédente soit affichée ou non.

Source

  • [code]
  • //------------------------------------------------------------------------------
  • // Structures
  • //------------------------------------------------------------------------------
  • // Gestion du temps : toutes les variables ne sont pas indispensables
  • struct TEMPS
  • {
  • // Par rapport au démarrage de Windows
  • LONGLONG cBase; // Nombre de cycles depuis le démarrage de Windows, trouvé au démarrage de l'application
  • LONGLONG cPrec; // Nombre de cycles depuis le démarrage de Windows, trouvé lors du dernier rendu
  • LONGLONG cNow; // Nombre de cycles depuis le démarrage de Windows, trouvé actuellement
  • LONGLONG cSuiv; // Nombre de cycles depuis le démarrage de Windows, qu'on doit atteindre pour le prochain rendu
  • // Par rapport au démarrage de l'application
  • LONGLONG cBegin; // Nombre de cycles écoulés uniquement depuis le démarrage de l'application
  • LONGLONG allFrames; // Nombre de frames depuis le démarrage de l'application
  • LONGLONG allFramesPrec; // Nombre de frames depuis le démarrage de l'application
  • LONGLONG cUneSeconde; // On attend une seconde pour comptabiliser le nombre de frames
  • long int ns; // Nombre de nano secondes depuis le démarrage de l'application
  • // Par rapport aux conversions temps <=> cycle
  • LONGLONG frequence; // Nombre de cycles par seconde (de l'ordre de 3 millions avec un Barton 3200+)
  • double tpsPerC; // Temps en seconde entre deux cycles
  • // Par rapport aux frames
  • LONGLONG cPerFrame; // Nombre de cycles qui doivent s'écouler entre deux frames (pour la limitation)
  • LONGLONG cEcoule; // Nombre de cycles écoulés entre deux frames (pour le TimeStep)
  • double ecoule; // Temps en secondes entre deux frames (pour le TimeStep)
  • LONGLONG nbFrames; // Nombre de frames affichées (remis à 0 toutes les secondes)
  • double fps; // Nombre de frames par seconde (mis à jour toutes les secondes via nbFrames)
  • };
  • struct TEMPS temps;
  • [/code]
[code]
//------------------------------------------------------------------------------
// Structures
//------------------------------------------------------------------------------


    // Gestion du temps : toutes les variables ne sont pas indispensables
    struct TEMPS
    {
        // Par rapport au démarrage de Windows
        LONGLONG cBase;             // Nombre de cycles depuis le démarrage de Windows, trouvé au démarrage de l'application
        LONGLONG cPrec;             // Nombre de cycles depuis le démarrage de Windows, trouvé lors du dernier rendu
        LONGLONG cNow;              // Nombre de cycles depuis le démarrage de Windows, trouvé actuellement
        LONGLONG cSuiv;             // Nombre de cycles depuis le démarrage de Windows, qu'on doit atteindre pour le prochain rendu
        
        // Par rapport au démarrage de l'application
        LONGLONG cBegin;            // Nombre de cycles écoulés uniquement depuis le démarrage de l'application
        LONGLONG allFrames;         // Nombre de frames depuis le démarrage de l'application
        LONGLONG allFramesPrec;     // Nombre de frames depuis le démarrage de l'application
        LONGLONG cUneSeconde;       // On attend une seconde pour comptabiliser le nombre de frames
        long int ns;                // Nombre de nano secondes depuis le démarrage de l'application

        // Par rapport aux conversions temps <=> cycle
        LONGLONG frequence;         // Nombre de cycles par seconde (de l'ordre de 3 millions avec un Barton 3200+)
        double   tpsPerC;           // Temps en seconde entre deux cycles
        
        // Par rapport aux frames
        LONGLONG cPerFrame;         // Nombre de cycles qui doivent s'écouler entre deux frames (pour la limitation)
        LONGLONG cEcoule;           // Nombre de cycles écoulés entre deux frames (pour le TimeStep)
        double   ecoule;            // Temps en secondes entre deux frames (pour le TimeStep)
        LONGLONG nbFrames;          // Nombre de frames affichées (remis à 0 toutes les secondes)
        double   fps;               // Nombre de frames par seconde (mis à jour toutes les secondes via nbFrames)
    };
    struct TEMPS temps;
[/code]

 Conclusion

Utiliser les touches '-' et '+' pour changer le framerate.
Si vous avez une autre méthode : laissez moi un message.

Vous pouvez comparer les résultats inscrits dans la barre du titre de la fenêtre OpenGL avec des programmes tels que FRAPS (qui affichent le nombre de FPS). Ils sont identiques normalement.

Enjoy,
BeLZeL

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !
  • main.cTélécharger ce fichier [Réservé aux membres club]Voir ce fichier18 798 octets
  • Projet1.devTélécharger ce fichier [Réservé aux membres club]931 octets
  • Projet1.exeTélécharger ce fichier [Réservé aux membres club]114 836 octets
  • Projet1.icoTélécharger ce fichier [Réservé aux membres club]Voir ce fichier2 238 octets

Télécharger le zip


 Historique

07 septembre 2004 22:21:02 :
Suppression de l'exe dans le zip ;-p
16 septembre 2004 21:49:56 :
Ce n'est plus du tout le même programme. Implémentation d'une nouvelle gestion du timing avec QueryPerformanceCounter et QueryPerformanceFrequency

 Sources du même auteur

Source avec Zip Source avec une capture VORTEX [OPENGL DEVCPP]
Source avec Zip Source avec une capture MODÈLE 3D TEXTURÉ [OPENGL & ASE & RAW & DEVCPP]
Source avec Zip [HOOK CLAVIER] FICHIER TEXTE AVEC GESTION DES DEAD KEYS [DEV...
Source avec Zip Source avec une capture LOAD TGA / OPENGL [DEV-C++ 4.9.5.0]
Source avec Zip Source avec une capture LOAD JPG / OPENGL [DEV-C++ 4.9.5.0]

 Sources de la même categorie

Source avec Zip Source avec une capture AFFICHER DES COURBES DE BEZIER par shorzy
Source avec Zip Source avec une capture BASE/MOTEUR 3D EN QT/OPENGL (COMPLET ET FONCTIONNEL!) POUR U... par envi33
Source avec Zip Source avec une capture CLASSE AVEC OPENGL - OBJETS 3D ET ANIMATIONS par rasta63
Source avec Zip Source avec une capture LETTRES 3D AVEC OPENGL ET QT par opossum_farceur
Source avec Zip CUBE 3D GLUT32 VC++ ET DEVC++ par bobby03

Commentaires et avis

Commentaire de Kirua le 07/09/2004 22:46:50

Je n'ai pas lu le code, mais si j'ai bien compris l'explication, sur un ordinateur rapide, si tu limites à 30FPS et que l'ordi est capable d'en faire 60, il va faire 30 images pdt 0.5s, et puis plus rien pdt 0.5s? j'imagine que ce n'est pas ça. ça marche comment (en fait? :p).

sinon, moi je fais comme ça:

const int DELAI = 30; //délai min en ms entre deux frames
clock_t tpsfps = 0; //temps mesuré lors du dernier affichage, clock_t est une structure de <ctime>, cf une référence sur internet

dans la main loop:

while(clock() - clkfps < DELAI); //ne fait rien jusqu'à ce que minimum DELAI ms soient passées depuis la dernière frame;
clkfps = clock(); //temps de cette frame-ci
GestionClavier(); //gère... le clavier, oui, merci :p
DessinerEcran(); //appelle toutes les méthodes de dessin...


je dois reconnaître que c'est une sorte de timer plutôt rudimentaire... ça marche très bien pour un jeu style RPG (tiens tiens), mais pour une simulation physique (souvent le cas ds les jeux d'ailleurs) qui demandent de pvr dessiner avec des temps différents, et d'ailleurs de ne pas faire des déplacements égaux à chaque frame, mais des déplacements dépendant du temps depuis la dernière frame, ce système est pourri jusqu'à l'os ;)

Commentaire de djl le 07/09/2004 23:26:49

dois y avoir plus simple, si tu es en  double frame buffer tu swap seulement quand tu es dans les delais, c'est plus coherent (pas de pause)

Commentaire de BeLZeL le 07/09/2004 23:27:49

Si la machine est puissante, l'affichage sera limité par un nombre précis, comme tu l'as dit.

A chaque appel à la fonction Draw (qui dessine avec OpenGL), il y a le nombre d'images qui s'incrémente et le temps qui est mis à jour. Normal.

Je me suis basé sur une moyenne du nombre de FPS :
images (affichées depuis le lancement) / temps en seconde (écoulé depuis le lancement)

Si la moyenne est inférieur à MAX_FPS, on peut afficher de nouvelles images (et incrémenté le nombre d'images et on fait une MAJ du temps).

Si la moyenne est supérieur (ou égal) à MAX_FPS, on n'affiche rien (on fait juste une MAJ du temps). Si bien qu'à un moment donné (un moment très court), la moyenne redeviendra inférieure, obligatoirement.

On passe des miliers de fois (pour ne pas dire des dizaines de milliers de fois) dans la fonction Draw, mais on affiche qu'un nombre précis d'image. Le programme ne bloque pas, c'est à dire qu'on peut toujours faire quelque chose pendant qu'on affiche rien (il faudrait rajouter un else dans Draw()). Je ne crois pas que ca doit être pareil pour ta boucle while (qui devrait être bloquante), mais c'est vrai que ca semble plus simple :) Je me suis peut-être compliqué la vie, ce ne sera pas la première fois ;)

Commentaire de Kirua le 08/09/2004 07:46:22

en fait, ts les deux vous effectuez un nombre maximum de fois les fct de gestion clavier et du jeu (physique...) mais vous ne dessinez pas tjs les nouvelles infos. c'est mieux, j'imagine.

au fait, ac ta méthode belzel, tu devrais pê remettre le compteur initial (celui du début du jeu) à clock() (tps actuel) de tps à autre, genre toutes les 5s, pour éviter que le temps de chargement du début du jeu n'aient de répercussions sur la moyenne pdt tte la partie.

Commentaire de NoRabbit le 08/09/2004 18:04:22

une autre méthode consiste à calculer les différents changements / opérations en fonction du temps écoulé entre chaque itération de la boucle.
Imaginons un cube qui se déplace de 5 à chaque itération. Le temps écoulé est de 12 ms.
Pour éviter que ce cube se déplace plus rapidement sur une machine plus puissante (FPS plus élevé), il suffit de calculer son déplacement en fonction des 12 ms (bien entendu ces 12 ms peuvent changer à chaque itération de la boucle)
Ce qui nous fait --> cube.x = cube.x + 5 * Var_TpsEcoule (= temps écoulé...)
Le cube se déplace à la même vitesse sur n'importe quelle machine et il n'est plus nécessaire de limiter la fréquence d'affichage qui peut parfois (souvent) créer des problèmes lors de la synchronisation des évènements comme pour dans un jeu en réseau par exemple...

Voilà, c'est la méthode que j'utilise pour le moment.
Elle est parfois plus problèmatique dans certaines situations, mais elle permet une utilisation plus souple, complète...

Commentaire de Kirua le 08/09/2004 18:25:29

c'est exactement ce que j'ai dit juste avant.

"...une simulation physique (souvent le cas ds les jeux d'ailleurs) qui demandent de pvr dessiner avec des temps différents, et d'ailleurs de ne pas faire des déplacements égaux à chaque frame, mais des déplacements dépendant du temps depuis la dernière frame..."

Commentaire de NoRabbit le 08/09/2004 18:29:53

... ;) sorry, j'ai pas tout lu...

Commentaire de NoRabbit le 08/09/2004 18:32:30

...je ne comprends pas, faut que tu m'expliques pourquoi tu cherches à limiter le nombre de fps...
c'est vraiment la dernière chose à faire...

Commentaire de Kirua le 08/09/2004 18:50:21

pas pour un RPG en 2D non temps-réel: j'évite de devoir faire des calculs en fonction du temps (et par la même de devoir passer le temps en paramètre de toutes les fonctions!), tout en gardant une vitesse constante sur tous les ordinateurs et en répartissant les frames de façon équilibrée (c'est pas 33 et puis plus rien jusqu'à la fin de la seconde, c'est 33 tout au long de la seconde).

En fait, cette méthode est mauvaise EN GENERAL, mais dans ce cas précis, elle est la plus adéquate (je pense).

Commentaire de Funto66 le 08/09/2004 19:13:09

Perso j'utilise la même méthode que NoRabbit, en général avec SDL_GetTicks().
T'as un exemple ici : http://perso.wanadoo.fr/funto/BaseCode2.rar
et un autre là : http://perso.wanadoo.fr/funto/BaseCode.zip

Commentaire de BeLZeL le 08/09/2004 22:55:51

Concernant le temps écoulé entre deux frames. C'est effectivement une très bonne méthode. Le problème, c'est que sur ma machine, le temps écoulé (pour afficher un cube simple) est parfois inférieur à 1 ms (j'ai plus de 1500 FPS avec ce programme). Je n'ai donc pas assez de précision pour utiliser le temps écoulé entre deux frames.

Commentaire de djl le 09/09/2004 11:01:35

NoRabbit  > limiter les fps, je peux au moins t'assurer que ce n'est surement pas pour assurer la meme vitesse quelque soit la machine (en principe on synchronise avec le temps)

la limitationde framerate est par exemple utilisé dans doom3 pour reduire les inegalité en mode multijoueurs

Commentaire de NoRabbit le 09/09/2004 11:35:13

djl : peux tu donner un exemple ? j'aimerais mieux comprendre.

tkx

Commentaire de djl le 09/09/2004 11:42:40

ca depends comment la synchro est gerer, mais dans certains jeux (notament q3 ou les fps pouvais alller tres tres haut) le comportement du physique a tendance a changer, typiquement dans q3 a partir de 120 - 130  fps la jouablité change et c'etait penalisant pour  ceux qui etait dans les 60 -80, je sais pas a quoi c'etait du (synchro pas  parfaite ?) mais n'empeche que dans doom3 carmach a decider de limiter les fps en multi joueur

c'est le seul exemple que je connaisse mais il doit y en avoir d'autres

Commentaire de BeLZeL le 09/09/2004 12:33:04

Concernant Q3A, en fait la physique changeait selon le nombre de FPS. Si tu avais un FrameRate bloqué à 125 FPS, tu pouvais sauter à 66 unités de haut, alors que sinon, tu ne pouvais pas sauter plus de 63 unités voir moins.

Ca autorisait quelques tricks sympatiques, notamment pour choper la mégavie d'en bas dans la Q3DM13.

Sinon des jeux récent comme NFSU bloque le FrameRate selon des paliers. Impossible de dépasser les 60 FPS, et si ca rame trop, on passe à 30. Probablement parce que le jeu à été développé avant sur console.

Commentaire de djl le 09/09/2004 13:03:17

dans le fichier BASEQ3/q3config.cfg, la ligne
seta com_maxfps

permet de fixer le framerate max

Commentaire de Funto66 le 09/09/2004 18:44:08

"Le problème, c'est que sur ma machine, le temps écoulé (pour afficher un cube simple) est parfois inférieur à 1 ms (j'ai plus de 1500 FPS avec ce programme). Je n'ai donc pas assez de précision pour utiliser le temps écoulé entre deux frames."
!!!
Ouah ! Ben là alors on doit faire comment? parce que c'est pénalisant ça, si on veut trouver un système "universel"...
Je pensais pas que le système qui consistait à faire les calculs en fonciton du temps écoulé avait ce défaut-là :(

En fait peut-être que le mieux serait de limiter les FPS ET de faire les calculs selon le temps écoulé? Comme ça, avec la limite des FPS à un nombre assez élevé, tu peux profiter de la puissance de ta machine tout en n'ayant pas de pb avec le timer non?

Commentaire de djl le 09/09/2004 18:52:49

mais  peut etre aussi que dans les  jeu on syncrhonise a partir de la frequence / nombre de cycle pour garder un precision absolue

Commentaire de Funto66 le 09/09/2004 18:58:24

Hmm j'en doute quand même, imagine déjà pour récupérer le nombre de cycles du fias comment?
Et puis aussi avec le multitasking, plusieurs applications à la fois, qui bouffent chacunes des cycles CPU, tu peux pas calculer uniquement par rapport à ton prog...

Enfin qui sait si c'est possible...mais si ça l'est ça m'étonnerait que ça soit portable dans tous les cas ^^

Commentaire de djl le 09/09/2004 19:02:56

ca se fais a base d'appels systeme, et oui peux savoir le cout en cycle de cetraine instructions

je crois meme que c'est frequent de mesurer la vitesse des instructions avec cette technique, doit y avoir un source de brunews la dessus

Commentaire de CRAzy-flaSH le 11/09/2004 14:43:00

Je crois que les fonctions qui permettent d'être plus précises au niveau du temps sont les suivantes :

QueryPerformanceCounter()
QueryPerformanceFrequency()

Je ne sais pas du tout ce qu'il en est de leur portabilité mais je crois savoir qu'elles sont plus gourmantes que des fonctions de temps plus traditionnelles.

Le mieux est sûrement de limiter le nombre maximum de fps pour ne pas arriver dans des temps trop petits et donc trop imprécis puis d'utiliser des fonctions traditionnelles...

Mais si quelqu'un s'y connait mieux sur ce qu'il est conseillé de faire, ça m'intéresse également ;)

Commentaire de BruNews le 11/09/2004 15:12:52 administrateur CS

QueryPerformanceCounter()
QueryPerformanceFrequency()
sont effectivement les mesures les plus fiables sur Windows. Elles consomment egalement moins de cycles que les fonctions classiques de la CRT qui sous Windows finissent dans tous les cas par les appeler.

Commentaire de BeLZeL le 11/09/2004 15:51:58

Oki doki.

Je vais voir comment implémenter ces fonctions.

Commentaire de BeLZeL le 16/09/2004 21:51:37

Voilà, j'ai fait une update du prog et il fonctionne à merveille. Merci pour vos conseils.

BeLZeL

Commentaire de BeLZeL le 30/09/2005 22:03:45

Je cherche un équivalent des fonctions QueryPerformanceCounter QueryPerformanceFrequency, sous Linux ...

Commentaire de JMGR le 11/12/2005 16:10:47

Bin tu peux utiliser GLFW, qui remplace Glut et qui a une fonction glfwGetTime() qui donne un timestamp en secondes (donc de type "double") avec une précision qui dépends de la plateforme. Mais bon sur un pc pas trop vieux on (en général) une précision de l'ordre de la nanoseconde.

Commentaire de BeLZeL le 11/12/2005 17:46:21

J'achète ;)

Comme quoi, on en apprend tous les jours.
Je ne connaissais pas, merci :)
J'espère que j'arriverai à faire marcher la souris sous Linux avec ce framework ...

Commentaire de JMGR le 11/12/2005 19:07:17

De rien ^^

Le seul défaut de cette librairie c'est de ne pas être très connue, mais elle le mériterait...

Commentaire de Kirua le 11/12/2005 21:22:39

Je confirme, GLFW a été la réponse à la majorité de mes soucis en matière de fenêtre OpenGL. Elle est même équipée d'un support de thread portables, d'un loader de TGA et de toute la gestion clavier / souris / joystick. A découvrir absolument ;)

Commentaire de Funto66 le 17/12/2005 11:42:37

Juste un bémol, chez moi en tous cas, GLFW n'a pas voulu reconnaître mon joystick, alors que SDL si...(NB : je parle sous Linux, la version Win32 fonctionnait).

Mais sinon c'est mon framework préféré :)

Commentaire de Kirua le 17/12/2005 14:02:46

Tiens donc, celui qui nous a tous convertis à GLFW est encore vivant :)

 Ajouter un commentaire




Nos sponsors


Sondage...

CalendriCode

Février 2012
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
272829    

Consulter la suite du CalendriCode

Photothèque

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 2,527 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales