禁用 DWM 会导致 OpenGL 窗口中的前端缓冲区损坏

DWM being disabled causes front-buffer corruption in OpenGL window

本文关键字:前端 缓冲区 损坏 窗口 OpenGL DWM 禁用      更新时间:2023-10-16

我的 SDL2 + OpenGL GUI 应用程序遇到了一些奇怪的图形损坏。现在,如果我没有使用适当的术语来描述这种情况,我深表歉意。似乎前端缓冲区正在失效,并且在缓冲区中绘制了其他应用程序?

重要说明:此损坏仅在 Windows XP 中或在 Windows 7 中使用 Windows Basic 主题时发生。

可以通过以下几种方式重现损坏:

  1. 通过移动窗口。似乎前端缓冲区被其前面或后面的其他应用程序的图像损坏了。
  2. 如果后面有一个应用程序,它偶尔会闪烁到前端缓冲区中。
  3. 我可以在 opengl 应用程序上方的 Chrome 中加载一个谷歌网页,关闭 chrome 进程,然后移动 opengl 应用程序,我会看到谷歌主页覆盖了整个窗口内部。
  4. 通过在 OpenGL 窗口上移动另一个应用程序。

似乎当我移动其他窗口时,我也看到了损坏,即使它们不与 opengl 窗口重叠,只要我已经尝试了上面发布的其中一个。

inline int UI::RenderingThread()
{
   UI::Window::Instance().RenderingThreadEnter();
   while( UI::Window::Instance().RenderingThreadActive() )
   {
      unsigned int ticks = SDL_GetTicks();
      UI::Window::Instance().RenderingThreadUpdate();
      UI::Window::Instance().RenderingThreadRender();
      ticks = SDL_GetTicks() - ticks;
      if( ticks < 33 )
      {
         SDL_Delay( 33 - ticks );
      }
   }
   UI::Window::Instance().RenderingThreadExit();
   return 0;
}

正如您可能猜到的那样,我正在使用多线程,并且我的渲染在单独的线程中。在RenderingThreadRender()函数中,我仅在内容发生变化或请求重绘时才重绘。

case SDL_WINDOWEVENT:
   switch( sdl_event.window.event )
   {
      default:
         UI::Window::Instance().Redraw();
         break;
   }

这样做是为了允许所有SDL_WINDOWEVENT事件重新绘制,希望其中一个事件能够解决问题。不幸的是,这并没有解决问题。

我犹豫是否要以 30 或 60 fps 的速度不断重绘我的应用程序,因为我注意到这样做,其他应用程序在移动它们时会很慢。

初始化:

SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); 
this->window = SDL_CreateWindow( this->caption.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                                 UI::WindowSize::Instance().GetWindowWidth(), UI::WindowSize::Instance().GetWindowHeight(),
                                 SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE );
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glViewport(0, 0, UI::WindowSize::Instance().GetWindowWidth(), UI::WindowSize::Instance().GetWindowHeight());
// Set the OpenGL view
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( 0, UI::WindowSize::Instance().GetWindowWidth(), UI::WindowSize::Instance().GetWindowHeight(), 0, -1, 1 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glDisable( GL_DITHER );

渲染:

if( this->redraw )
{
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glLoadIdentity();
     // a few DrawArrays
     SDL_GL_SwapWindow( this->window ); 
}

有没有人知道可能导致此问题的原因以及如何解决它?

编辑:更多的研究向我指出了以下两个问题:

https://superuser.com/questions/316738/what-happens-with-the-off-screen-front-buffers-in-windows-7-when-dwm-is-disabled

C++ OpenGL 窗口仅跟踪背景

但是,这并不能解决我的问题,因为我已经在使用双缓冲。

我已经找到了解决问题的方法。任何人都不太可能遇到与我相同的问题,但您永远不知道。本质上,以前正在创建一个大小等于或大于我的应用程序的 C# 窗口。此窗口是隐藏的,但是由于XP具有全局帧缓冲而不是合成,因此存在导致损坏的冲突。

总而言之,如果您遇到类似的问题,请确保没有其他上下文。