C++ 使用ifstream时OpenGL版本过低
我正在为2D roguelike编写引擎的一些元素。我在一个我希望能够打开的地方。(我手动操作,因为我喜欢了解这些东西。)因此我创建了一个C++ 使用ifstream时OpenGL版本过低,c++,opengl,C++,Opengl,我正在为2D roguelike编写引擎的一些元素。我在一个我希望能够打开的地方。(我手动操作,因为我喜欢了解这些东西。)因此我创建了一个PngLoader类,并开始用它做一些基本的事情,比如。。。打开文件。出于某种原因,这会破坏OpenGLGLFunctionFinder类,该类除了手动之外,还执行类似于GLEW的操作 当OpenGL版本过低时,GLFF基本上会使程序崩溃;这是预期的行为。(可能是一个未设置的函数指针上的segfault。我可以通过使其更优雅地崩溃来“修复”这个问题,但谁在乎呢
PngLoader
类,并开始用它做一些基本的事情,比如。。。打开文件。出于某种原因,这会破坏OpenGLGLFunctionFinder
类,该类除了手动之外,还执行类似于GLEW的操作
当OpenGL版本过低时,GLFF基本上会使程序崩溃;这是预期的行为。(可能是一个未设置的函数指针上的segfault。我可以通过使其更优雅地崩溃来“修复”这个问题,但谁在乎呢?)GLFF通常工作得相当好,因为我的图形卡运行OpenGL 4.3左右,但几天前当驱动程序切换到集成图形驱动程序(仅适用于OpenGL 1.1版)时,我确实让它崩溃了。这是通过更改图形仪表板中的某些设置修复的
因此,当我写这样的东西时,我今天突然想到的问题出现了:
class ifcontainerclass {
std::ifstream fs;
};
/* other code */
int WINAPI WinMain(/* ... */) {
GLFunctionFinder ff;
ff.interrogateWindows();
ifcontainerclass ifcc;
/* GL code and main loop */
return 0;
}
。。。OpenGL上下文在版本1.1上卡住了。如果我将ifstream
更改为fstream
,我会得到预期的更高版本上下文,问题就会消失
我还在测试中发现,如果我注释掉GL代码和主循环
区域,问题再次消失。“版本过低”检查是在GLFunctionFinder::interrogateWindows()
中完成的,而不是在以后的GL代码中完成的,因此仍在检查这些条件。(经过一些测试,我发现注释掉MSG
结构是问题得以解决的原因。)
我目前的看法是,编译器正在做一些魔术,导致Windows/Intel/NVidia在以下情况下只发出OpenGL 1.1上下文/连接到错误的驱动程序。。。我真的不知道什么时候。这个问题似乎很武断
我可能会考虑去掉我出于懒惰而使用的globalHDC
和globalHGLRC
,因为我认为问题与如何初始化有关/编译器如何安排初始化这些东西,把他们从全球范围内拉出来,我就能更有效地检查和控制这个过程。我在GLFunctionFinder
中使用了一个static void*GlobalAddr=this
文件范围的指针,在虚拟窗口的WndProc
中将其转换为GLFunctionFinder
,并将HDC
和HGLRC
作为GLFunctionFinder
的成员变量,可通过指针访问。我可能会在我的主窗口中尝试类似的东西;不管怎样,我一直需要清理全球范围的东西。我可以做的另一件事是在调试器中运行每个版本,并查看它的差异,尽管我不愿意这样做,因为调试在我的IDE中没有正确设置,我也不希望修复它
我想我可以同时使用fstream
而不是ifstream
,但我不喜欢不理解这么奇怪的问题,因为它暗示了某种不稳定性,在我有10k行代码任意停止运行之前,我应该意识到这一点,并且只能通过改变其他地方看起来完全不相关的东西来修复
问题:
- 到底发生了什么事?这里的核心问题是什么
- 为什么将
更改为ifstream
可以解决问题fstream
- 为什么注释掉
struct可以解决这个问题MSG
NvOptimusEnablement=0x00000001
未修复该问题
PPS:MingW4.9.2在Qt中(作为一个IDE,没有Qt库)使用CMake
编辑:在确定将-ggdb
传递给g++时Qt的调试器工作后,我仔细检查了代码,发现GLFunctionFinder
中的PIXELFORMATDESCRIPTOR
没有被分配;我将属性分配给某个随机临时变量而不是成员变量,而ChoosePixelFormat
使用的是成员变量。由于您获得的上下文取决于您指定的像素类型,因此我实际上是在从Windows请求不确定的设备上下文。编译的细节决定了在PIXELFORMATDESCRIPTOR
中放入了哪些随机垃圾,而声明ifstream
而不是fstream
会在该区域放入错误的随机垃圾
通过在this->pfd\uu=pfd的效果上添加一些东西,问题得到了解决定义临时pfd
后,将code>转换为GLFunctionFinder
的构造函数
编辑2:为了满足我对“off-topic”标志含义的理解,我将提供一个核心问题的最小示例:
main.cpp:
#include <windows.h>
#include <sstream>
#include <GL/gl.h>
HDC h_dc;
HGLRC h_context;
LRESULT CALLBACK MainWndProc(_In_ HWND h_wnd,
_In_ UINT u_msg,
_In_ WPARAM w_param,
_In_ LPARAM l_param) {
switch(u_msg) {
case WM_CREATE: {
PIXELFORMATDESCRIPTOR pfd; // <-- This was the error source, (pfd not set to an
// accelerated format, but only sometimes)
// except in my code it was harder to see than
// this.
h_dc = GetDC(h_wnd);
int pfint = ChoosePixelFormat(h_dc, &pfd);
SetPixelFormat(h_dc, pfint, &pfd);
h_context = wglCreateContext(h_dc);
wglMakeCurrent(h_dc, h_context);
const unsigned char * version_string =
static_cast<const unsigned char *>(glGetString(GL_VERSION));
if(version_string[0] == '1' || version_string[0] == '2') {
std::stringstream ss;
ss << "OpenGL version (" << version_string << ") is too low";
MessageBox(NULL, ss.str().c_str(), "Error", MB_OK | MB_ICONERROR);
}
break;
}
case WM_DESTROY:
PostQuitMessage(EXIT_SUCCESS);
break;
default:
return DefWindowProc(h_wnd, u_msg, w_param, l_param);
}
return 1;
}
int WINAPI WinMain( HINSTANCE h_inst,
HINSTANCE h_previnst,
LPSTR cmd_str_in,
int cmd_show_opt) {
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_OWNDC;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = h_inst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "MAINWIN";
wc.hIconSm = NULL;
RegisterClassEx(&wc);
HWND h_wnd = CreateWindowEx(0,
"MAINWIN",
"MCVE Program",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
640,
480,
NULL,
NULL,
h_inst,
NULL);
return EXIT_SUCCESS;
}
如果有人跳到最后,问题就解决了,但我不知道该如何表示。因此,我实际看到的是由于默认初始化结构而导致的未定义行为的影响,其中包含的值未初始化:
class GLFunctionFinder {
PIXELFORMATDESCRIPTOR pfdarr_;
/* other code */
GLFunctionFinder();
setupContext();
/* other code */
}
GLFunctionFinder::GLFunctionFinder() {
/* other code */
PIXELFORMATDESCRIPTOR pfd = { /* things */ };
// Missing: pfdarr_ = pfd;
// pfdarr_ never gets set
}
GLFunctionFinder::setupContext() {
// Undefined behavior:
int px_format_default = ChoosePixelFormat(this->h_cd, &(this->pfdarr_));
/* other code */
}
这就给了ChoosePixelFormat
任何垃圾都在pfdarr\uu
中。当我最初写这篇文章时,它的表现似乎没有问题,因为垃圾数据“看起来”像是一种加速像素格式类型,ChoosePixelFormat
会给我一种int格式,它产生了我所追求的OpenGL上下文。它这样保持了一段时间,因为它一直在工作
从fstream
切换到ifstream
改变了编译器布局/优化程序的一些细节,而pfdarr\uu
中的垃圾数据更改为“看起来像”一种未加速的格式。这导致获取错误的cont
class GLFunctionFinder {
PIXELFORMATDESCRIPTOR pfdarr_;
/* other code */
GLFunctionFinder();
setupContext();
/* other code */
}
GLFunctionFinder::GLFunctionFinder() {
/* other code */
PIXELFORMATDESCRIPTOR pfd = { /* things */ };
// Missing: pfdarr_ = pfd;
// pfdarr_ never gets set
}
GLFunctionFinder::setupContext() {
// Undefined behavior:
int px_format_default = ChoosePixelFormat(this->h_cd, &(this->pfdarr_));
/* other code */
}