Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Simplification de Window::isOpen()  (Lu 4158 fois)

0 Membres et 1 Invité sur ce sujet

Cmdu76

  • Full Member
  • ***
  • Messages: 194
    • Voir le profil
Simplification de Window::isOpen()
« le: Août 13, 2013, 12:57:16 am »
Bonjour à tous !

Je suis en train de travailler sur un petit projet ici : http://fr.sfml-dev.org/forums/index.php?topic=12617.0

Et je viens de réfléchir à comment simplifier au maximum ma fonction main (j'ai sûrement pas encore uploadé ma dernière version)

Donc premièrement je suis venu repenser l'ordre d'affichage "traditionel" qui est :
window.clear()
window.draw(...)
window.display()

Je me suis dit que finalement, vu que la boucle se lit "vite", que le code du haut et celui-ci revenait au même :
window.draw(...)
window.display()
window.clear()

J'ai fait des tests, aucuns problèmes :)

Maintenant c'est la que j'ai poussé à la simplification "extrême", j'ai ajouté les fonctions display() et clear() dans la fonction isOpen() comme ceci :

bool Application::isOpen()
{
    bool running = mWindow.isOpen();
    display();
    clear();
    return running;
}

//Dans mon projet, je travaille sur une classe Application qui comporte une RenderWindow et ses méthodes (que je peux donc modifer)

et donc après ça je peux dessiner tranquillement dans ma boucle isOpen() sans me soucier des display et clear :)

Bon voilà c'est pas grand chose mais finalement quand on compte le nombre de fois qu'on écrit ces fonctions :)

Ensuite j'ai essayé de voir les avantages de "l'ancienne" méthode, finalement le seul inconvénient c'est le fait que clear peut prendre un paramètre... Mais en fait, il suffit d'ajouter la couleur du clear en paramètre à isOpen() ;)

Voilà, je pense que cette petite chose peut être simplifiée :)




Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Simplification de Window::isOpen()
« Réponse #1 le: Août 13, 2013, 08:02:17 am »
Juste pour la petite histoire, l'ordre optimal serait même celui-ci :

display()
...
update()
...
clear()
draw()

Ce qui revient au bon vieux

update()
...
clear()
draw()
display()

... car lors de l'appel à display(), le GPU se "met en route" et exécute tout le boulot qui a potentiellement été mis en attente par les appels précédents à draw(). Donc après display(), si le CPU attaque directement par une instruction graphique, il va devoir attendre que le GPU ait terminé et donc bloquer à ne rien faire. Alors que si le CPU s'occupe de choses qui n'impliquent pas le GPU pendant ce temps, les deux peuvent  tourner en parallèle, d'où un gain de temps.

Bien sûr c'est pertinent pour de grosses applications graphiques avec plein de calculs GPU et CPU ; là on s'en fiche un peu ;)

Sinon, pour en revenir à ta proposition, c'est une très mauvaise idée.

Premièrement, isOpen() indique l'état de la fenêtre, elle n'est pas censée faire quelque chose de manière cachée. Ce serait mentir à l'utilisateur, et quand on ment à l'utilisateur on peut être sûr qu'il va coder des bêtises à son insu.

Ensuite isOpen() peut être appelée n'importe quand, le fait que ce soit la condition de la boucle principale et que ce ne soit appelé nulle part ailleurs, c'est juste le cas simple. Qu'est-ce qui empêche d'appeler isOpen() pour vérifier si al fenêtre est ouverte ailleurs ? Qu'est-ce qui empêche d'utiliser un booléen et de ne jamais l'appeler ? Pense aux programmes complexes, avec plusieurs threads, etc.

Et puis enfin il faut laisser la flexibilité à l'utilisateur. Ce schéma n'est pas figé, il y a des gens qui utiliseront ces trois fonctions très différemment.

Quand à un isOpen(sf::Color::Black)... sans déconner ? :P
Laurent Gomila - SFML developer

Cmdu76

  • Full Member
  • ***
  • Messages: 194
    • Voir le profil
Re : Simplification de Window::isOpen()
« Réponse #2 le: Août 13, 2013, 12:34:06 pm »
Très bon arguments, je m'incline :)

Le premier est le moins percutant mais je comprends que pour une lib de cette qualité ce n'est pas possible.

J'avoue ne pas du tout avoir pensé au second...

Et le troisième je savais que ça n'avait pas de sens mais c'était plus pour le côté "pratique" xD

Pourquoi ne pas ajouter alors une fonction isRunning() qui ferait ça, du coup 1-On ne ment pas car elle est prévue pour, 2-Bah du coup elle est prévue pour donc les gens peuvent utiliser isOpen() quand même pour leurs tests, 3-Tant pis pour la couleur en argument ou une couleur par défaut

Je te laisse jeter un coup d'oeil à mon code où justement j'utilise cette technique, même si comme tu me le dis avec l'exemple du CPU/GPU, ici c'est une petite application et que pour les grosses cela ne fonctionne pas terriblement bien...

#include <SFML/Graphics.hpp>
#include "include/Application.h"

int main()
{
    Application app;

    BoutonText bouton = app.newBoutonText(app.getTexture("gui.png"),sf::IntRect(0,0,396,35),sf::IntRect(0,35,396,35),sf::IntRect(0,70,396,35),sf::Vector2f(0,0),4,10,"Clique pour centrer",23,app.getFont("cloister.ttf"),sf::Color(255,255,255));
    BoutonImage boutonI = app.newBoutonImage(app.getTexture("gui.png"),sf::IntRect(0,0,396,35),sf::IntRect(0,35,396,35),sf::IntRect(0,70,396,35),sf::Vector2f(50,50),4,10,app.getTexture("gui.png"),sf::IntRect(0,70,180,10));

    while (app.isOpen()) //Application::isOpen inclut les fonctions display, clear et drawGui
    {
        while (app.pollEvent()) //Application::pollEvent inclut la gestion de la fermeture de la fenêtre mais ça c'est encore autre chose et je comprends que tu ne veuilles pas
        {
            if (CmEvent::clicLeft(app.getEvent()) && bouton.isHover(app.getWindowPtr()))
            {
                bouton.centerText("Bim! Centré!");
            }
            if (CmEvent::clicLeft(app.getEvent()) && boutonI.isHover(app.getWindowPtr()))
            {
                boutonI.centerImage();
            }
        }
    }
    return 0;
}
« Modifié: Août 13, 2013, 12:42:15 pm par Cmdu76 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Simplification de Window::isOpen()
« Réponse #3 le: Août 13, 2013, 12:52:40 pm »
Citer
Pourquoi ne pas ajouter alors une fonction isRunning() qui ferait ça
Si, on continue à mentir à l'utilisateur. Un nom acceptable ne sous-entendrait pas qu'on ne fait que récupérer un état, et expliciterait le fait qu'on rafraîchit la fenêtre.

Là c'est même encore pire : on introduit un nouvel état pour le moins flou (c'est quoi une fenêtre qui "tourne" ?), je n'appelle pas ça une simplification de l'API.

A la limite, tu m'aurais proposé un while (window.display()), ça m'aurait moins choqué.

Bref on va en rester là, hein ;)
Laurent Gomila - SFML developer

Cmdu76

  • Full Member
  • ***
  • Messages: 194
    • Voir le profil
Re : Simplification de Window::isOpen()
« Réponse #4 le: Août 13, 2013, 01:47:02 pm »
Rien à redire, en fait tu as raison :)

Lynix

  • Sr. Member
  • ****
  • Messages: 403
    • Voir le profil
Re : Re : Simplification de Window::isOpen()
« Réponse #5 le: Août 15, 2013, 02:39:09 am »
Juste pour la petite histoire, l'ordre optimal serait même celui-ci :

display()
...
update()
...
clear()
draw()

Ce qui revient au bon vieux

update()
...
clear()
draw()
display()

... car lors de l'appel à display(), le GPU se "met en route" et exécute tout le boulot qui a potentiellement été mis en attente par les appels précédents à draw(). Donc après display(), si le CPU attaque directement par une instruction graphique, il va devoir attendre que le GPU ait terminé et donc bloquer à ne rien faire. Alors que si le CPU s'occupe de choses qui n'impliquent pas le GPU pendant ce temps, les deux peuvent  tourner en parallèle, d'où un gain de temps.

Sauf que l'appel à "display" entraîne un glFinish implicite, bloquant par nature.
Et de toute façon, c'est déjà parallélisé, le GPU tourne en même temps que le CPU lui donne des instructions, l'idéal serait alors de faire les gros calculs CPU après le draw() :)

Bon en revanche ça introduit une frame de latence pour le joueur, ce qui peut avoir son importance selon le type de jeu.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Simplification de Window::isOpen()
« Réponse #6 le: Août 15, 2013, 09:13:57 am »
Citer
Sauf que l'appel à "display" entraîne un glFinish implicite, bloquant par nature.
Il me semble que c'est plutôt un glFlush, non bloquant donc.

Citer
Et de toute façon, c'est déjà parallélisé, le GPU tourne en même temps que le CPU lui donne des instructions, l'idéal serait alors de faire les gros calculs CPU après le draw()
Sauf que le GPU accumule les commandes et ne les exécute que lorsqu'il est vraiment obligé (glFlush, glGet, ...). Donc typiquement il ne va pas se passer grand chose pendant les appels à draw(), et tout le rendu sera fait après display() ; c'est donc le meilleur moment pour faire quelque chose d'autre avec le CPU.

Bon, mes connaissances du pipeline de rendu sont un peu rouillées, alors c'est pas du 100% ce que je dis là ;D
Laurent Gomila - SFML developer

Lynix

  • Sr. Member
  • ****
  • Messages: 403
    • Voir le profil
Re : Simplification de Window::isOpen()
« Réponse #7 le: Août 15, 2013, 12:44:17 pm »
J'ai eu l'occasion de faire un benchmark fait par une dizaine de personnes récemment : http://www.siteduzero.com/forum/sujet/moteur-de-jeu-nazara-engine-69732?page=20#message-84597382

On retrouve souvent ceci, lorsque l'instancing est activé, et que le CPU doit faire moins de choses que le GPU, window.Display (SwapBuffers) prend alors bien plus de temps (25ms par exemple, si ça ce n'est pas du bloquant ^^), alors que si l'instancing est désactivé, le Swap est presque immédiat (200us).

J'en ai déduit que le GPU n'attend pas, et se lance immédiatement dans l'exécution des commandes, avec l'instancing, le CPU a terminé avant le GPU et se met donc à l'attendre. Sans instancing, le CPU passe plus de temps sur les commandes, suffisamment pour que le GPU ait le temps de les terminer avant que le CPU ne passe à SwapBuffers, qui n'effectue dès lors qu'un swap, sans devoir attendre la carte graphique.

De plus, si je ne dis pas de bêtises, les moteurs 3D sont basés sur cette exécution simultanée (Rien que les query sont basées sur ce principe).
« Modifié: Août 15, 2013, 01:52:13 pm par Lynix »