能否在不销毁窗口与OpenGL上下文的情况下切换全屏模式?
无需销毁窗口切换GLFW全屏/窗口模式的解决方案
嘿,我完全懂你现在的困扰——销毁重建窗口的方式不仅繁琐,还会因为OpenGL上下文丢失导致GPU资源失效,这就是你切换后引擎关键部分停止绘制的核心原因!其实GLFW早就提供了直接切换窗口显示模式的API,完全不用销毁窗口和上下文,用glfwSetWindowMonitor就能轻松搞定。
核心思路
glfwSetWindowMonitor允许你在不重建窗口的前提下,切换窗口的显示监视器(全屏时绑定主显示器,窗口模式时解绑),同时保留原有的OpenGL上下文,所有GPU资源(着色器、纹理、缓冲等)都不会丢失,也就不用重新初始化那些_shader、_skybox了。
修改后的实现代码
首先,你需要在类中额外保存窗口模式下的位置和尺寸(避免切换回窗口时位置错乱):
// 在TMooseEngine类中添加成员变量 int _windowedX, _windowedY; int _windowedWidth, _windowedHeight;
然后重写toggleFullscreen函数:
void TMooseEngine::toggleFullscreen() { _fullscreen = !_fullscreen; // 获取当前窗口的监视器(全屏时会返回主显示器,窗口模式返回NULL) GLFWmonitor* currentMonitor = glfwGetWindowMonitor(window); if (_fullscreen) { // 切换到全屏模式:先保存当前窗口的位置和尺寸 glfwGetWindowPos(window, &_windowedX, &_windowedY); glfwGetWindowSize(window, &_windowedWidth, &_windowedHeight); // 获取主显示器的视频模式(用原生分辨率做全屏) const GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); // 切换到全屏:绑定主显示器,使用视频模式的分辨率和位置(0,0) glfwSetWindowMonitor(window, glfwGetPrimaryMonitor(), 0, 0, mode->width, mode->height, mode->refreshRate); } else { // 切换回窗口模式:解绑监视器,恢复之前保存的窗口位置和尺寸 glfwSetWindowMonitor(window, NULL, _windowedX, _windowedY, _windowedWidth, _windowedHeight, GLFW_DONT_CARE); } // 更新视口,适配新的窗口尺寸 int width, height; glfwGetFramebufferSize(window, &width, &height); glViewport(0, 0, width, height); // 注意:这里不需要销毁和重建_shader、_skybox等资源! // 因为OpenGL上下文没有丢失,所有GPU资源都还在 }
为什么原来的方法会失效?
你之前的实现销毁了窗口,这会直接导致OpenGL上下文被销毁——所有在GPU上创建的资源(着色器程序、纹理、顶点缓冲、天空盒数据等)都会被释放。虽然你重建了_shader和_skybox,但像注释掉的_particulas这类资源没有重建,其他隐藏的GPU资源也可能没处理,最终导致绘制流程中断。
额外提示
- 切换全屏后一定要用
glfwGetFramebufferSize获取真实的帧缓冲尺寸(因为窗口尺寸和帧缓冲尺寸可能不一致,比如高DPI屏幕),再更新glViewport - 如果需要自定义全屏分辨率,不用视频模式的尺寸,直接传入你想要的宽高即可,但建议匹配显示器的支持分辨率
内容的提问来源于stack exchange,提问作者Manu
相关产品推荐
相关产品推荐

