2012-10-17 10 views
6

Ho un gioco sdl/opengl su cui sto lavorando per divertirmi. Ottengo un discreto fps in media, ma il movimento è davvero instabile perché SDL_GL_SwapBuffers() richiede una quantità enorme di tempo per l'elaborazione. Con le trame caricate e scritte nel buffer a volte ci vorranno più di 100ms! Ho tagliato molto del mio codice per cercare di capire se fosse qualcosa che ho sbagliato, ma non ho avuto molta fortuna. Quando eseguo questo programma bare bones, continuerà a bloccare fino a 70ms a volte.SDL_GL_SwapBuffers() è lento a intermittenza

principale:

// Don't forget to link to opengl32, glu32, SDL_image.lib 

// includes 
#include <stdio.h> 

// SDL 
#include <cstdlib> 
#include <SDL/SDL.h> 

// Video 
#include "videoengine.h" 

int main(int argc, char *argv[]) 
{ 
    // begin SDL 
    if (SDL_Init(SDL_INIT_VIDEO) != 0) 
    { 
     printf("Unable to initialize SDL: %s\n", SDL_GetError()); 
    } 

    // begin video class 
    VideoEngine videoEngine; 

    // BEGIN MAIN LOOP 
    bool done = false; 
    while (!done) 
    { 
     int loopStart = SDL_GetTicks(); 

     printf("STARTING SWAP BUFFER : %d\n", SDL_GetTicks() - loopStart); 
     SDL_GL_SwapBuffers(); 


     int total = SDL_GetTicks() - loopStart; 
     if (total > 6) 
      printf("END LOOP : %d ------------------------------------------------------------>\n", total); 
     else 
      printf("END LOOP : %d\n", total); 

    } 
    // END MAIN LOOP 

    return 0; 
} 

mio "VideoEngine" costruttore:

VideoEngine::VideoEngine() 
{ 
    UNIT = 16; 
    SCREEN_X = 320; 
    SCREEN_Y = 240; 
    SCALE = 1; 


    // Begin Initalization 

     SDL_Surface *screen; 

     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); // [!] SDL_GL_SetAttributes must be done BEFORE SDL_SetVideoMode 

     screen = SDL_SetVideoMode(SCALE*SCREEN_X, SCALE*SCREEN_Y, 16, SDL_OPENGL); // Set screen to the window with opengl 
     if (!screen) // make sure the window was created 
     { 
      printf("Unable to set video mode: %s\n", SDL_GetError()); 
     } 

     // set opengl state 
     opengl_init(); 

    // End Initalization 

} 

void VideoEngine::opengl_init() 
{ 
    // Set the OpenGL state after creating the context with SDL_SetVideoMode 

     //glClearColor(0, 0, 0, 0);        // sets screen buffer to black 
     //glClearDepth(1.0f);          // Tells OpenGL what value to reset the depth buffer when it is cleared 
     glViewport(0, 0, SCALE*SCREEN_X, SCALE*SCREEN_Y);  // sets the viewport to the default resolution (SCREEN_X x SCREEN_Y) multiplied by SCALE. (x,y,w,h) 
     glMatrixMode(GL_PROJECTION);       // Applies subsequent matrix operations to the projection matrix stack. 
     glLoadIdentity();          // Replaces the current matrix with the identity matrix 
     glOrtho(0, SCALE*SCREEN_X, SCALE*SCREEN_Y, 0, -1, 1); //describes a transformation that produces a parallel projection 
     glMatrixMode(GL_MODELVIEW);       // Applies subsequent matrix operations to the projection matrix stack. 
     glEnable(GL_TEXTURE_2D);        // Need this to display a texture 
     glLoadIdentity();          // Replaces the current matrix with the identity matrix 
     glEnable(GL_BLEND);          // Enable blending for transparency 
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  // Specifies pixel arithmetic 
     //glDisable(GL_LIGHTING);        // Disable lighting 
     //glDisable(GL_DITHER);         // Disable dithering 
     //glDisable(GL_DEPTH_TEST);        // Disable depth testing 

     //Check for error 
     GLenum error = glGetError(); 
     if(error != GL_NO_ERROR) 
     { 
     printf("Error initializing OpenGL! %s\n", gluErrorString(error)); 
     } 

    return; 
} 

sto iniziando a pensare che forse ho un problema hardware? Non ho mai avuto questo problema con un gioco.

+0

Avete attivato il vsync? – Tim

+0

No, non credo dopo aver letto questo -http: //stackoverflow.com/questions/589064/how-to-enable-vertical-sync-in-opengl Penso che quello che potrebbe succedere sia chiamare SwapBuffers () senza dargli tempo per l'elaborazione potrebbe causare il blocco o il loop. Farò ancora un po 'di lettura e vedrò se non riesco a trovare qualcosa che lo supporti. – Alden

+2

[Toss] (http://www.msarnoff.org/sdb/) a 'SDL_Delay (1)' dopo lo swap del buffer, vedere cosa fa ai tempi del frame. – genpfault

risposta

2

SDL utilizza l'estensione SwapIntervalEXT in modo da assicurarsi che gli scambi di buffer siano il più veloci possibile (VSYNC disabilitato). Inoltre, il buffer swap non è una semplice operazione, OpenGL deve copiare il contenuto dei buffer posteriori sui buffer anteriori per il caso che si desidera glReadPixels(). Questo comportamento può essere controllato usando WGL_ARB_pixel_format, usando WGL_SWAP_EXCHANGE_ARB (si può leggere su tutte queste cose nelle specifiche, ora non sono sicuro se c'è un'alternativa a quello per Linux).

E poi, oltre a tutto questo, c'è il sistema di finestre. Questo può effettivamente causare molti problemi. Inoltre, se vengono generati degli errori ...

Questo comportamento è probabilmente ok se stai usando una piccola GPU mobile.

SDL_GL_SwapBuffers() contiene solo una chiamata a glxSwapBuffers()/wglSwapBuffers() quindi non c'è tempo trascorso lì.

+3

Si chiama buffer "swap" proprio perché nessuna implementazione sana di fatto esegue una copia. –

+0

@BenVoigt Bene, a quanto pare WGL - leggi [documenti correlati a '' WGL_SWAP_EXCHANGE_ARB'] (http://oss.sgi.com/projects/ogl-sample/registry/ARB/wgl_pixel_format.txt) (Non sto contestando il tuo commento a proposito di sanità mentale, però). La ragione di questo è di essere in grado di leggere il contenuto del buffer anche dopo lo swap (non so perché qualcuno volesse farlo), e questo è il comportamento predefinito. Abilitando 'WGL_SWAP_EXCHANGE_ARB' riconosci che comprendi che dopo lo swap, i buffer si scambiano e non puoi più accedere ai tuoi dati. –

+0

Sei sicuro di non dover richiedere esplicitamente di avere dati validi nel buffer? Quel parametro 'WGL_SWAP_METHOD_ARB' ha tre opzioni, e non chiarisce quale è l'impostazione predefinita. –