SDL_GL_SwapBuffers() 间歇性缓慢

SDL_GL_SwapBuffers() is intermittently slow

本文关键字:缓慢 GL SwapBuffers SDL      更新时间:2023-10-16

我有一个sdl/opengl游戏,我正在开发一个有趣的游戏。我的平均 fps 不错,但移动真的很不稳定,因为 SDL_GL_SwapBuffers() 会随机花费很长时间来处理。加载纹理并将其写入缓冲区后,有时需要 100 毫秒以上!我剪掉了很多代码,试图弄清楚这是否是我做错了什么,但我没有太多的运气。当我运行这个裸露的程序时,它有时仍然会阻塞长达 70 毫秒。

主要:

// 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: %sn", SDL_GetError());
    }
    // begin video class
    VideoEngine videoEngine;
    // BEGIN MAIN LOOP
    bool done = false;
    while (!done)
    {
        int loopStart = SDL_GetTicks();
        printf("STARTING SWAP BUFFER : %dn", SDL_GetTicks() - loopStart);
        SDL_GL_SwapBuffers();

        int total = SDL_GetTicks() - loopStart;
        if (total > 6)
            printf("END LOOP  : %d ------------------------------------------------------------>n", total);
        else
             printf("END LOOP  : %dn", total);
    }
    // END MAIN LOOP
    return 0;
}

我的"视频引擎"构造函数:

    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: %sn", 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! %sn", gluErrorString( error ) );
        }
    return;
}

我开始认为我可能有硬件问题?不过,我从来没有遇到过这个问题。

SDL 确实使用 SwapIntervalEXT 扩展名,因此您可以确保缓冲区交换尽可能快(禁用 VSYNC)。此外,缓冲区交换不是一个简单的操作,OpenGL 需要将后台缓冲区的内容复制到前端缓冲区,以备glReadPixels()。可以使用 WGL_ARB_pixel_format 来控制此行为,使用 WGL_SWAP_EXCHANGE_ARB(您可以在规范中阅读所有这些内容;现在我不确定是否有 Linux 的替代方案)。

最重要的是,还有窗口系统。这实际上会造成很多麻烦。另外,如果生成一些错误...

如果您在小型移动 GPU 上运行,则此行为可能没问题。

SDL_GL_SwapBuffers()只包含对glxSwapBuffers()/wglSwapBuffers()的调用,因此没有时间在那里花费。