2012-10-17 19 views
6

Mam grę sdl/opengl, nad którą pracuję dla zabawy. Dostaję przyzwoite fps, ale ruch jest naprawdę niepewny, ponieważ SDL_GL_SwapBuffers() będzie losowo wymagać długiego czasu do przetworzenia. Z teksturami załadowanymi i zapisanymi do bufora czasami zajmie to ponad 100ms! Wytraciłem dużo kodu, żeby spróbować dowiedzieć się, czy to było coś, co zrobiłem źle, ale nie miałem szczęścia. Kiedy uruchomię ten program bez kości, będzie on blokował czasami nawet do 70 ms.SDL_GL_SwapBuffers() jest sporadycznie powolny

główne:

// 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; 
} 

Mój "VideoEngine" konstruktor:

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; 
} 

Zaczynam myśleć ewentualnie mam problem sprzętowy? Jednak nigdy nie miałem takiego problemu z grą.

+0

Czy masz włączoną opcję vsync? – Tim

+0

Nie Nie sądzę, po przeczytaniu tego - http: //stackoverflow.com/questions/589064/how-to-enable-vertical-sync-in-opengl Myślę, że to, co może się dziać nazywa się SwapBuffers () bez podania czasu na przetworzenie może spowodować zawieszenie lub zapętlenie. Zrobię więcej czytania i zobaczę, czy nie mogę znaleźć czegoś, co by to poparło. – Alden

+2

[Toss] (http://www.msarnoff.org/sdb/) a 'SDL_Delay (1)' po zamianie buforów, zobacz, co robi z twoimi czasami ramek. – genpfault

Odpowiedz

2

SDL korzysta z rozszerzenia SwapIntervalEXT, dzięki czemu można się upewnić, że wymiany buforów są tak szybkie, jak to możliwe (wyłączone VSYNC). Ponadto wymiana bufora nie jest prostą operacją, OpenGL musi kopiować zawartość buforów zwrotnych do buforów przednich dla przypadku, który ma być glReadPixels(). To zachowanie można kontrolować za pomocą WGL_ARB_pixel_format, używając WGL_SWAP_EXCHANGE_ARB (możesz przeczytać o tym wszystkim w specyfikacji, teraz nie jestem pewien, czy istnieje alternatywa dla Linuksa).

A na dodatek istnieje system okien. To naprawdę może powodować wiele problemów. Ponadto, jeśli niektóre błędy są generowane ...

To zachowanie jest prawdopodobnie dobre, jeśli używasz małego mobilnego procesora graficznego.

SDL_GL_SwapBuffers() zawiera tylko połączenie z glxSwapBuffers()/wglSwapBuffers(), więc nie ma tam czasu.

+3

Wymienione bufory "swap" właśnie dlatego, że żadna rozsądna implementacja faktycznie nie wykonuje kopii. –

+0

@BenVoigt Cóż, najwyraźniej WGL robi - przeczytaj dokumentację powiązaną z '' WGL_SWAP_EXCHANGE_ARB'' (http://oss.sgi.com/projects/ogl-sample/registry/ARB/wgl_pixel_format.txt) (nie kwestionuję twojego komentarza ale o zdrowiu psychicznym). Powodem tego jest możliwość odczytania zawartości bufora nawet po zamianie (nie wiem, dlaczego ktoś chciał to zrobić), i to jest domyślne zachowanie. Włączając 'WGL_SWAP_EXCHANGE_ARB', potwierdzasz, że rozumiesz, że po zamianie, bufory się zamieniają i nie możesz już dostać się do twoich danych. –

+0

Czy jesteś pewien, że nie musisz jawnie żądać posiadania prawidłowych danych w buforze? Ten parametr 'WGL_SWAP_METHOD_ARB' ma trzy opcje i nie wyjaśnia, który jest domyślny. –