PB gestion du temps windows et décharge CPU.

Signaler
Messages postés
2
Date d'inscription
samedi 17 septembre 2005
Statut
Membre
Dernière intervention
6 mars 2010
-
Messages postés
2
Date d'inscription
samedi 17 septembre 2005
Statut
Membre
Dernière intervention
6 mars 2010
-
Bonjour tout le monde.

Voila je présente mon code.

Je cherche a éffectuer une décharge processeur au sein d'une application windows pour afficher des graphismes openGL.

Il s'agit plus ou moins de limiter le nombre de rendus opengl pour avoir par exemple 60 images/secondes.

J'utilise donc une constante référence de temps time_per_frame 1/60 sec environ 16 ms.
Elle correspond au temps idéal pour afficher une image, cela veut dire qu'on ne veut afficher qu'une seule image toute les 16 ms.

Pour mesurer ma boucle d'affichage, j'ai créer une fonction qui mesure à chaque passage le temps écoulé : get_time();
(cela renvoi une mesure de quelques millisecondes)
Cette fonction ne pose pas de problème, je suis pret à vous la montrer si besoin est.


Ensuite, dans ma boucle d'affichage, aprés chaque rendu, je mesure le temps écoulé.
(il s'agit du temps écoulé à chaque passage renvoyé par get_time)
Ce temps est appelé running_time.(unsigned int)


Je test ce temps pour voir si j'ai effectué moins de temps "running_time" qu'il ne faut pour une image "time_per_frame".

Si cela est le cas alors je fait perdre un delay à ma boucle: la différence de temps qu'il me reste pour attenidre "time_per_frame".


Bon ce n'est pas facile à éxpliquer, tout ceci est bien sur très inspiré du siteduzéro sur le tutorial opengl 3D partie2.

Voici a quoi ressemble ma boucle :


void loop()
{

#define 		FPS 		60
static 	unsigned int 	time_per_frame 	= (unsigned int)static_cast( (1000/FPS)  + 0.5);
static 	unsigned int 	running_time 	= 0;		
static 	DWORD 		delay 		= 0;


static 	unsigned int 	refresh_times 	= 0;
static 	bool 		is_first_time 	= true;

// initialistion effectué qu'au premier passage
init_opengl();


// animations pour une rotation 3D d'un plan
angle += 0.2;

// rendu opengl				
draw();

// lecture framerate
framerate(running_time+delay);


// mesure du temps écoulé a chaque passage, la première fois running_time = 0;	
running_time = get_time();



// décharge CPU

if (running_time < time_per_frame)
{	
delay = time_per_frame - running_time;
Sleep(delay);
}
else
{ 	delay = 0;}




// lecture des temps dans une statusbar windows
refresh_times += running_time;

if (refresh_times > 800 || is_first_time)
{
send_statusbar_var(statusbar->debug,"time_per_frame = ",time_per_frame," ms");

send_statusbar_var(statusbar->refresh,"cycle = ",running_time," ms");
send_statusbar_var(statusbar->delay,"delay = ",delay," ms");

send_statusbar_var(statusbar->time,"add = ",running_time+delay," ms");

refresh_times = 0;
is_first_time = false;
}




}


Voila, ce code à l'air de fonctionner, mais apparement j'ai le cas "aléatoire" ou (running_time > time_per_frame).
Cela veut dire que en une boucle j'ai mis plus de 16ms à afficher un rendu openGL.
Dans ce cas je ne perd pas de temps et je réaffiche tout de suite (delay = 0).

Seulement sur mon ordinateur, j'ai des périodes ou cela se produit assez longtemps (au démarrage de l'ordinateur j'ai l'impression).
j'ai envie de dire que mon ordinateur est plombé.

Mais ce qui est plus étonnant, c'est que au bout d'un certain temps cela disparait, puis réapparait, sans explications.
Je tient à préciser que ce phénomène ne se produit pas en SDL, et que mon code fonctionne parfaitement en SDL.
(comme sur le site du zéro en fait)

Cela fait 2 semaines que je remet en cause mon programme, et je me pose des questions.

J'ai conscience que la fonction sleep(millisecondes); n'est pas précise, mais il me semble que ceci est rattrapé par une nouvelle mesure du temps avec mon get_time ?

Auriez des suggestions à me faire ?
J'ai supposé aussi que les messages windows peuvent etre source des décalages dans le temps.
(si c'est le cas je remesure le temps écoulé à chaque fois)

Je vous montre des screens shoots.

Fonctionnement idéal:


Default constaté:


Merci de m'éclairer.

le raton laveur <+"=

2 réponses

Messages postés
3874
Date d'inscription
mardi 8 mars 2005
Statut
Modérateur
Dernière intervention
7 novembre 2014
14
Bienvenue,

Plutôt que de passer en paramètre de Sleep le temps à attendre, tu peux faire une boucle sur un Sleep(1), et à chaque tour de boucle, tu vérifie que tu ne dois pas sortir de la boucle. Il faut s'attendre qu'un Sleep(1) dure 3 ou 4 millisecondes, voire une douzaine en fonction de ce qui tourne en même temps sur le PC...

Généralement, dans les jeux, on tourne le plus vite possible, pour consommer 100% de CPU (Quoiqu'on se maintient rarement à 100% à cause d'accès disques qui mettent le processeur en attente). Ou alors on passe en synchronisation verticale. Il ne sert en effet (presque !) à rien de générer des frames qui ne seront pas affichées...

Dernière solution, faire une boucle qui fait le rendu le plus rapidement possible, mais inclure un Sleep(1) dedans. Cela permet d'avoir un boucle rapide tout en ne consommant que très peu de CPU.

Et quoiqu'il arrive, à chaque rendu, on se base sur le temps écoulé depuis le dernier rendu pour faire les modifs liées au temps.
Messages postés
2
Date d'inscription
samedi 17 septembre 2005
Statut
Membre
Dernière intervention
6 mars 2010

Merci pour la bienvenue,

Sa fait un moment que je m'éssaye en amateur à la programmation.

C'est pourquoi je prend mon temps et ce site m'a beaucoup aidé. (même si je ne vennait pas spécialement sur les forums)


tu peux faire une boucle sur un Sleep(1), et à chaque tour de boucle, tu vérifie que tu ne dois pas sortir de la boucle.


Oui bien sur une boucle sur un sleep(1);
A vrai dire j'y avait pensé ,je l'ai même mesuré (sa mettait bien 5 ms), et je me suis dis qu'une imprécision de ce coté n'était pas dérangeante.
Cependant je vais quand même tester.
Je montrerait mes résultats et mon code !


Généralement, dans les jeux, on tourne le plus vite possible, pour consommer 100% de CPU


Je ne savait pas, je penser simplement que l'idéal était de tourner à "100%" seulement pour tout ce qui est entrées utilisateurs (manette de jeux par exemple).
Biensur c'est une pensé idéal, cela ne doit pas être possible dans une simple boucle.

Il ne sert en effet (presque !) à rien de générer des frames qui ne seront pas affichées...


Je suis tout a fait d'accord, c'est ce que je veut faire.

Et quoiqu'il arrive, à chaque rendu, on se base sur le temps écoulé depuis le dernier rendu pour faire les modifs liées au temps.


Par contre dans mon cas, j'ai basé la vitesse des animations sur le nombre d'images affichées.

C'est peut être un peu exotique, mais je ne voulait pas d'animations qui se "calent sur le temps":
J'aimerait utiliser une fonction pause, qui une fois terminé ne recalcule pas mon angle de rotation par rapport au temps écoulé (contrairement à ce qui est fait dans le tuto du siteduzero)
En fait le calcul de mon angle se fait si il y a un nouveau passage.

Peut être est-ce une mauvaise méthode, mais vu que je regularise le temps (enfin sa marche pas encore) pour chaque image, mes animations sont quand même synchronisées sur mon temps.

Ou alors on passe en synchronisation verticale.


Ca c'est une bonne idée, je me demande si cette synchronisation est facile à obtenir.
Je croit avoir lu quelque part des codes qui testait si l'option était possible et qui avait 2 modes de rendus (avec et sans).
Je vais m'en informer un peu plus.

Merci de cette réponse.

Je promet de montrer mes résultats dès que possible.
Ca peut toujours servir à d'autres personnes!

le raton laveur <+"=