IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

OpenGL Discussion :

Optimisation d'OpenGL sous Linux


Sujet :

OpenGL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 28
    Par défaut Optimisation d'OpenGL sous Linux
    Bonjour,

    Je cherche à développer un space shooter 2D en combinant à la fois SDL et OpenGL.

    Mon code fonctionne sous Windows et Linux mais là où j'arrive à un pic de consommation de 20% du CPU chez Microsoft, je suis systématiquement à 50% sur mon Ubuntu (le moniteur système ne distinguant pas les deux coeurs), 100% d'un processeur, sur l'Ubuntu d'un ami, chez qui le jeu fonctionne très mal (j'ai vérifié que ses drivers Nvidia étaient bien installés).

    Comment donc puis-je optimiser ce code pour qu'il fonctionne aussi bien sous Linux que sous Windows?

    Je me suis inspiré de ce tutoriel pour la structure de mon moteur.

    Les fonctions principales employant OpenGL dans mon code, sont les suivantes :

    - pour la classe principale "Engine" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    void CEngine::Init()
    {
    	// Register SDL_Quit to be called at exit; makes sure things are cleaned up when we quit.
    	atexit( SDL_Quit );
     
    	// Initialize SDL's subsystems - in this case, only video.
    	if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    	{
    		fprintf( stderr, "Unable to init SDL: %s\n", SDL_GetError() );
    		exit( 1 );
    	}
     
    	// Attempt to create a window with the specified height and width.
    	SetSize( m_iWidth, m_iHeight );
     
    	//Double tampon
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
     
    	//Couleur de nettoyage
    	glClearColor(1.0,1.0,1.0,0.0);
     
    	//Remettre a zero la matrice de projection
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
     
        // Mettre les matrices en place pour une vue orthogonale
        gluOrtho2D(0, m_iWidth, m_iHeight,0);
     
    	// If we fail, return error.
    	if ( m_pScreen == NULL )
    	{
    		fprintf( stderr, "Unable to set up video: %s\n", SDL_GetError() );
    		exit( 1 );
    	}
     
    	AdditionalInit();
    }
     
    /** The main loop. **/
    void CEngine::Start()
    {
    	m_lLastTick = SDL_GetTicks();
    	m_bQuit = false;
     
    	// Main loop: loop forever.
    	while ( !m_bQuit )
    	{
    		// Handle mouse and keyboard input
    		HandleInput();
     
    		if ( m_bMinimized ) {
    			// Release some system resources if the app. is minimized.
    			#if _WIN32
                WaitMessage(); // pause the application until focus in regained
                #endif
     
    		} else {
    			// Do some thinking
    			DoThink();
     
    			// Render stuff
    			DoRender();
    		}
    	}
     
    	End();
    }
     
    /** Handles the rendering and FPS calculations. **/
    void CEngine::DoRender()
    {
    	++m_iFPSCounter;
    	m_iFPSLimit += m_iFPSTickCounter;
     
    	if ( m_iFPSTickCounter >= 1000 )
    	{
    		m_iCurrentFPS = m_iFPSCounter;
    		m_iFPSCounter = 0;
    		m_iFPSTickCounter = 0;
    	}
     
        if (m_iFPSLimit < 1000/30)
            return;
     
        m_iFPSLimit = 0;
     
    	// Lock surface if needed
    	if ( SDL_MUSTLOCK( m_pScreen ) )
    		if ( SDL_LockSurface( m_pScreen ) < 0 )
    			return;
     
    	// Effacer le tampon des couleurs
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glClearDepth(0.0f);
     
    	glLoadIdentity();
     
    	Render( GetSurface() );
     
    	// Unlock if needed
    	if ( SDL_MUSTLOCK( m_pScreen ) )
    		SDL_UnlockSurface( m_pScreen );
     
    	// Tell SDL to update the whole gScreen
    	//SDL_Flip( m_pScreen );
    	glFlush();
        SDL_GL_SwapBuffers();
    }
    Et pour sa sous-classe "CMyEngine":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    void CMyEngine::Render( SDL_Surface* pDestSurface )
    {
    	// Display slick graphics on screen
     
    	//Modifie la projection
    	glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
     
    	//Retrouve la vision orthogonale
    	gluOrtho2D(vis.x,vis.x + vis.w,vis.y + vis.h,vis.y);
     
    	//Modifie les textures
    	glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
     
    	//On applique le monde sur l'écran
    	world.affiche();
     
    	//On met en place le test alpha
    	glEnable(GL_ALPHA_TEST);
    	//On dessine en fonction de la valeur alpha
    	glAlphaFunc(GL_GREATER,0.5f);
     
    	//Affiche les obstacles
    	int i;
    	for (i = 0;i<(int)obstacles.size();i++)
    	{
    		obstacles[i]->affiche();
    	}
     
    	//On applique les persos sur l'ecran
    	for (i = 0;i<(int)tabperso.size();i++)
    	{
    		tabperso[i]->affiche();
    	}
     
    	//On applique les tirs
    	for (i = 0;i<(int)tabtirs.size();i++)
    	{
    		tabtirs[i]->affiche();
    	}
     
    	//On desactive le test sur la valeur alpha
    	glDisable(GL_ALPHA_TEST);
    }
    J'ajoute le code d'affichage de la classe "Sprite":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    void Sprite::affiche()
    {
    	GLfloat xt0 = (GLfloat)((float)_clip.x/(float)_rect.w);
    	GLfloat xt1 = (GLfloat)(((float)_clip.x+(float)_clip.w)/(float)_rect.w);
    	GLfloat yt0 = (GLfloat)((float)_clip.y/(float)_rect.h);
    	GLfloat yt1 = (GLfloat)(((float)_clip.y+(float)_clip.h)/(float)_rect.h);
     
    	glEnable(GL_TEXTURE_2D);
    	glBindTexture(GL_TEXTURE_2D, _texture->textu);
     
    	//glColor4f(0.0,0.0,0.0,0.5);
    	glBegin(GL_QUADS);
    		glTexCoord2f(xt0,yt0);
    		glVertex3f((GLfloat)_rect.x,(GLfloat)_rect.y,0);					// En haut a gauche
    		glTexCoord2f(xt1,yt0);
    		glVertex3f((GLfloat)_rect.x+_clip.w,(GLfloat)_rect.y,0);			// En haut a droite
    		glTexCoord2f(xt1,yt1);
    		glVertex3f((GLfloat)_rect.x+_clip.w,(GLfloat)_rect.y+_clip.h,0);	// En bas a droite
    		glTexCoord2f(xt0,yt1);
    		glVertex3f((GLfloat)_rect.x,(GLfloat)_rect.y+_clip.h,0);			// En bas a gauche
    	glEnd();
    	glDisable(GL_TEXTURE_2D);
    }
    Ouf ! Voilà tout !

    Je pressens que la réponse doit être une évidence pour les spécialistes mais qu'elle reste invisible pour un débutant comme moi.

    Edit : Serait-il plus efficace de calculer à chaque cycle, pixel par pixel l'image que je veux afficher et de créer ou modifier une seule et même texture pour tout l'écran plutôt que d'afficher une texture par objet comme je le fais actuellement ?

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 35
    Par défaut
    Edit : Serait-il plus efficace de calculer à chaque cycle, pixel par pixel l'image que je veux afficher et de créer ou modifier une seule et même texture pour tout l'écran plutôt que d'afficher une texture par objet comme je le fais actuellement ?
    Non, ce que tu fais est bien, ça exploite les capacités d'affichage de la carte graphique. Modifier une texture comme ça serait aussi lent qu'inadapté.

    En ce que concerne ton problème de charge processeur, je pense que tu devrais dejà revoir ton implémentation du limiteur de fps...
    J'ai l'impression que tant que le moment d'afficher la frame n'est pas venu, tu tournes dans la boucle principale, pas étonnant que tu te retrouves avec une charge processeur trop élevée !!

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 28
    Par défaut
    Merci beaucoup.

    Je vais travailler à partir de là, notamment à l'aide de ce tutoriel, puis je posterai ma réponse définitive en fonction du résultat.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 35
    Par défaut
    Visiblement il y a un souci dans ce tutoriel...

    Le problème vient de ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
    {
         //On attend...
    }
    Si on boucle en attendant, ça fera tourner le processeur à fond pour rien pendant ce temps.
    Il faudrait faire quelque chose avec un sleep, pour que le processus passe la main:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     SDL_Delay(1000/FRAMES_PER_SECOND - fps.get_ticks())
    ça marchera bien mieux !

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 28
    Par défaut
    Merci pour ce second message. Je m'apprêtais à écrire que je voyais pas d'améliorations.
    J'essaie la fonction "delay" et je réponds.

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 28
    Par défaut
    Excellent : j'ai une consommation de 1% au plus sous Linux maintenant.
    Le problème est donc réglé.

    J'ai donc modifié la fonction principale comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    /** The main loop. **/
    void CEngine::Start()
    {
    	m_lLastTick = SDL_GetTicks();
    	m_bQuit = false;
     
    	// Main loop: loop forever.
    	while ( !m_bQuit )
    	{
    		// Handle mouse and keyboard input
    		HandleInput();
     
    		if ( m_bMinimized ) {
    			// Release some system resources if the app. is minimized.
    			#if _WIN32
                WaitMessage(); // pause the application until focus in regained
                #endif
     
    		} else {
     
    			// Do some thinking
    			DoThink();
     
    			// Render stuff
    			DoRender();
     
    			//Attends la fin de la frame
    			SDL_Delay(1000/30 - (SDL_GetTicks() - m_lLastTick));
    		}
    	}
     
    	End();
    }
    Merci beaucoup pour votre aide.

    Eric 'Henn' Niubo

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Free Pascal] Optimisation de write sous Linux
    Par PyNub dans le forum Free Pascal
    Réponses: 4
    Dernier message: 26/05/2014, 20h00
  2. OpenGL sous linux avec wayland ?
    Par kripteks dans le forum OpenGL
    Réponses: 8
    Dernier message: 15/11/2013, 09h49
  3. Utilisation d'OpenGL sous Linux
    Par dragonjoker59 dans le forum wxWidgets
    Réponses: 4
    Dernier message: 01/04/2011, 08h57
  4. Réponses: 1
    Dernier message: 17/04/2009, 19h22
  5. Mettre à jours les dev d'OpenGL sous Linux
    Par Yno dans le forum OpenGL
    Réponses: 6
    Dernier message: 06/11/2006, 09h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo