使用 OpenGL 正确关闭 SDL

Posted

技术标签:

【中文标题】使用 OpenGL 正确关闭 SDL【英文标题】:Proper shutdown for SDL with OpenGL 【发布时间】:2013-10-12 03:57:37 【问题描述】:

我以最小的方式使用 SDL 1.2 在 C++ 中创建跨平台 OpenGL 上下文(在 Win7 64 位上)。我还使用 glew 让我的上下文支持 OpenGL 4.2(我的驱动程序支持)。

运行时一切正常,但我最近注意到在调用 SDL_Quit 时关闭时发生随机崩溃。

SDL (1.2) 与 OpenGL 启动和关闭的正确顺序是什么?

这是我目前所做的:

int MyObj::Initialize(int width, int height, bool vsync, bool fullscreen)

  if(SDL_Init( SDL_INIT_EVERYTHING ) < 0) 
  
    printf("SDL_Init failed: %s\n", SDL_GetError());
    return 0;
  

  SDL_GL_SetAttribute(SDL_GL_RED_SIZE,          8);
  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,        8);
  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,         8);
  SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE,        8);

  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,        24);
  SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,          8);
  SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE,           24);

  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS,  0);
  SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL,  vsync ? 1 : 0);

  if((m_SurfDisplay = SDL_SetVideoMode(width, height, 24, 
                                       SDL_HWSURFACE | 
                                       SDL_GL_DOUBLEBUFFER | 
                                       (fullscreen ? SDL_FULLSCREEN : 0) |
                                       SDL_OPENGL)) == NULL)
  
    printf("SDL_SetVideoMode failed: %s\n", SDL_GetError());
    return 0;
  

  GLenum err = glewInit();
  if (GLEW_OK != err) 
    return 0;

  m_Running = true;
  return 1;


int MyObj::Shutdown()
   
  SDL_FreeSurface(m_SurfDisplay);
  SDL_Quit();

  return 1;

在 init 和 shutdown 调用之间,我创建了许多 GL 资源(例如纹理、VBO、VAO、着色器等)并在每一帧渲染我的场景,在每一帧的末尾都有一个 SDL_GL_SwapBuffers()(漂亮典型的)。像这样:

int MyObject::Run()

  SDL_Event Event;

  while(m_Running) 
  
    while(SDL_PollEvent(&Event))
     OnEvent(&Event);  //this eventually causes m_Running to be set to false on "esc"

    ProcessFrame();
    SDL_SwapBuffers();
  
  return 1;

在 ~MyObject 中调用 MyObject::Shutdown()。最近 SDL_Quit 使应用程序崩溃的地方。在我的渲染循环返回相同的效果之后,我还尝试在析构函数之外调用 Shutdown。

我不做的一件事(我认为我不需要做)是在调用 Shutdown 之前为我分配的所有 GL 资源调用 glDelete* 函数(我认为它们会通过销毁我假设在 SDL_FreeSurface 或 SDL_Quit() 期间发生的上下文。我当然在包装对象的 dtors 中调用 glDelete* 函数,最终被 ~MyObject 的故事调用,因为包装对象是其他对象的一部分属于 MyObject 成员的对象。

作为一项实验,我尝试强制所有适当的 glDelete* 调用在 Shutdown() 之前发生,而我的崩溃似乎从未发生。有趣的是,一周前我不需要这样做,根据 GIT,实际上没有任何改变(尽管可能是错误的)。

真的有必要在使用 SDL 调用 MyObject::Shutdown 之前确保释放所有 GL 资源吗?看起来我可能做错了什么?

【问题讨论】:

【参考方案1】:
m_SurfDisplay = SDL_SetVideoMode(...)
...
SDL_FreeSurface(m_SurfDisplay);
                ^^^^^^^^^^^^^ naughty naughty!

SDL_SetVideoMode():

返回的表面由 SDL_Quit 释放,不能由调用者释放

【讨论】:

嗯,这似乎可以解决几次运行问题,但现在我似乎仍然在 SDL_Quit 上随机崩溃。我认为调用堆栈来自 nvoglv64.dll,我假设它是 OpenGL 驱动程序的一部分。如果我销毁所有 GL 资源(我的测试应用比我的实际应用更容易完成),我似乎不会崩溃。 奇怪的是,在我之前的 10k 左右运行中从未发生过崩溃。从那以后有一个视频驱动程序更新,但我尝试回到原来的驱动程序,但我仍然遇到问题。

以上是关于使用 OpenGL 正确关闭 SDL的主要内容,如果未能解决你的问题,请参考以下文章

SDL OpenGL 纹理显示问题

SDL2 (C++) 并非所有 .png 图像都能正确呈现

为什么我的2D OpenGL纹理无法正确加载? [关闭]

使用 SDL_CreateWindow 时出现 SDL OpenGL 分段错误

OpenGL 茶壶无法正确绘制。我究竟做错了啥? [关闭]

SDL OpenGL 窗口无响应,透明