Winapi OpenGL调用损坏的内存
当我调用GLGETINGERV或任何其他opengl函数,并在gdb中单步执行它时,到达它时,gdb将跳过几行,然后在代码中继续单步执行 下面是加载opengl和windows的代码。它是在第一个opengl调用GLGetInterserv之前运行的唯一代码Winapi OpenGL调用损坏的内存,winapi,opengl-3,Winapi,Opengl 3,当我调用GLGETINGERV或任何其他opengl函数,并在gdb中单步执行它时,到达它时,gdb将跳过几行,然后在代码中继续单步执行 下面是加载opengl和windows的代码。它是在第一个opengl调用GLGetInterserv之前运行的唯一代码 HWND window; HDC dev_context; HGLRC rend_context; //Creating the Window char const *name = "Opengl Test"; HINST
HWND window;
HDC dev_context;
HGLRC rend_context;
//Creating the Window
char const *name = "Opengl Test";
HINSTANCE inst = (HINSTANCE)GetModuleHandle(0);
WNDCLASS windowClass;
DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
windowClass.lpfnWndProc = (WNDPROC) WndProcedure;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = inst;
windowClass.hIcon = LoadIcon(NULL, IDI_WINLOGO);
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = NULL;
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = name;
RegisterClass(&windowClass);
window = CreateWindowEx(dwExStyle, name, name, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 0, 0, NULL, NULL, inst, NULL);
//Context
dev_context = GetDC( window );
std::cout << dev_context << std::endl;
//Get pixel format
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
int nPixelFormat = ChoosePixelFormat(dev_context, &pfd);
SetPixelFormat( dev_context, nPixelFormat, &pfd );
HGLRC temp_rend_context = wglCreateContext( dev_context );
wglMakeCurrent( dev_context, temp_rend_context );
HGLRC (WINAPI *wglCreateContextAttribsARB) (HDC hDC, HGLRC hShareContext, const int *attribList) = (HGLRC (WINAPI *) (HDC hDC, HGLRC hShareContext, const int *attribList)) gl3wGetProcAddress("wglCreateContextAttribsARB");
const int attribs[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 0, WGL_CONTEXT_FLAGS_ARB, /*WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB*/0, 0};
rend_context = wglCreateContextAttribsARB(dev_context, 0, attribs);
wglMakeCurrent(0,0);
wglDeleteContext(temp_rend_context);
wglMakeCurrent(dev_context, rend_context);
gl3wInit();
int glVersion[2] = {-1, -1};
glGetIntegerv(GL_MAJOR_VERSION, &glVersion[0]); //First gl call
glGetIntegerv(GL_MINOR_VERSION, &glVersion[1]);
我正在使用gl3w库加载opengl函数。听起来调用约定或参数列表不匹配,或者两者都不匹配,这会损坏堆栈,导致调用返回地址出错 仔细检查编译时使用的opengl.h文件是否与调用的opengl.dll版本匹配。仔细检查是否为.h文件定义并启用了Windows所需的任何条件定义。WinAPI调用中调用约定的规范是STDCALL。如果在.h文件中没有看到gl函数的调用约定,请怀疑 我隐约记得STDCALL和cdecl调用约定以相同的顺序(从右到左)将参数推送到堆栈上,但在调用后谁负责调整堆栈指针方面有所不同。我相信STDCALL期望被调用方弹出堆栈,而使用cdecl,调用方在调用返回后恢复堆栈指针
这意味着,如果调用者正在进行cdecl调用,但被调用者实际上是STDCALL,那么参数将使其进入调用中,但返回时所有的麻烦都会消失。根据不匹配的运行方式,堆栈指针要么根本不会调整,要么会过度调整(调整两次) 下面是我用来创建GL上下文和使用GL3功能的代码。 现在我知道这是C#但你明白了。没有理由创建两个GL上下文来使用OpenGL3。。。除非我完全听不懂你说的话
void Init(IntPtr handle, bool fullscreen, bool vSync)
{
this.handle = handle;
#if WINDOWS
//Get DC
dc = WGL.GetDC(handle);
WGL.SwapBuffers(dc);
//Set BackBuffer format
WGL.PIXELFORMATDESCRIPTOR pfd = new WGL.PIXELFORMATDESCRIPTOR();
WGL.ZeroPixelDescriptor(ref pfd);
pfd.nVersion = 1;
pfd.dwFlags = WGL.PFD_DRAW_TO_WINDOW | WGL.PFD_SUPPORT_OPENGL | WGL.PFD_DOUBLEBUFFER;
pfd.iPixelType = (byte)WGL.PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cAlphaBits = 8;
pfd.cDepthBits = 16;
pfd.iLayerType = (byte)WGL.PFD_MAIN_PLANE;
unsafe{pfd.nSize = (ushort)sizeof(WGL.PIXELFORMATDESCRIPTOR);}
int pixelFormatIndex = WGL.ChoosePixelFormat(dc, ref pfd);
if (pixelFormatIndex == 0) Debug.ThrowError("Video", "ChoosePixelFormat failed");
if (WGL.SetPixelFormat(dc, pixelFormatIndex, ref pfd) == 0) Debug.ThrowError("Video", "Failed to set PixelFormat");
ctx = WGL.CreateContext(dc);
if (ctx == IntPtr.Zero) Debug.ThrowError("Video", "Failed to create GL context");
if (WGL.MakeCurrent(dc, ctx) == 0) Debug.ThrowError("Video", "Failed to make GL context current");
WGL.Init();//<< load 'wglSwapIntervalEXT'
WGL.SwapInterval(vSync ? 1 : 0);
}
您有什么证据表明OpenGL调用正在破坏内存?当进入gdb时,在到达第一个glGetIntegerv后,它将继续向下并在程序中的稍后点停止。另外,当我在类函数内调用glCreateShader时,gdb向下跳过并崩溃,报告此指针指向0x1。为什么要创建和删除上下文。。。对我来说似乎是kina hoky。@zezba9000创建的第一个上下文(用于opengl 2.1)只是为了能够使用wglCreateContextAttribsARB,它创建了一个3.0+的上下文。我正在使用生成的gl3w.h进行编译,它使用gl3.h,直接从Khronos网站下载。好的,然后,再次检查是否正确设置了定义,以在声明的函数上获得适当的调用约定。STDCALL最有可能。您还可以使用您最喜欢的调试器的反汇编视图深入研究asm代码,以确认堆栈指针在这些调用中被屏蔽,再深入一点,您应该能够了解实际函数/被调用方的调用约定是什么,以及"cdecl",;这两个函数在gdb中具有相同的行为。同样,在gdb中,对glGetIntegerv的调用显示为:mov,movl,movl,call,sub,mov,movl,movl,call,sub+1。我在gl3.h中将stdcall添加到apitery中,在我记得进行了一次干净的构建之后,我的类似问题得到了解决。
void Init(IntPtr handle, bool fullscreen, bool vSync)
{
this.handle = handle;
#if WINDOWS
//Get DC
dc = WGL.GetDC(handle);
WGL.SwapBuffers(dc);
//Set BackBuffer format
WGL.PIXELFORMATDESCRIPTOR pfd = new WGL.PIXELFORMATDESCRIPTOR();
WGL.ZeroPixelDescriptor(ref pfd);
pfd.nVersion = 1;
pfd.dwFlags = WGL.PFD_DRAW_TO_WINDOW | WGL.PFD_SUPPORT_OPENGL | WGL.PFD_DOUBLEBUFFER;
pfd.iPixelType = (byte)WGL.PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cAlphaBits = 8;
pfd.cDepthBits = 16;
pfd.iLayerType = (byte)WGL.PFD_MAIN_PLANE;
unsafe{pfd.nSize = (ushort)sizeof(WGL.PIXELFORMATDESCRIPTOR);}
int pixelFormatIndex = WGL.ChoosePixelFormat(dc, ref pfd);
if (pixelFormatIndex == 0) Debug.ThrowError("Video", "ChoosePixelFormat failed");
if (WGL.SetPixelFormat(dc, pixelFormatIndex, ref pfd) == 0) Debug.ThrowError("Video", "Failed to set PixelFormat");
ctx = WGL.CreateContext(dc);
if (ctx == IntPtr.Zero) Debug.ThrowError("Video", "Failed to create GL context");
if (WGL.MakeCurrent(dc, ctx) == 0) Debug.ThrowError("Video", "Failed to make GL context current");
WGL.Init();//<< load 'wglSwapIntervalEXT'
WGL.SwapInterval(vSync ? 1 : 0);
}
public const string DLL = "opengl32";
[DllImport(DLL, EntryPoint = "wglGetProcAddress", ExactSpelling = true)]
private static extern IntPtr getProcAddress(string procedureName);