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:
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:
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:
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 ?