我有一个关于如何(正确)使用glewInit()
的问题。
假设我有一个多窗口应用程序,我应该在应用程序(即全局)级别调用glewInit()
一次吗?或者为每个窗口调用glewInit()
(即每个OpenGL
渲染上下文)?
答案 0 :(得分:8)
根据所使用的GLEW构建,水密方法是在每个上下文更改之后调用glewInit
!
使用X11 / GLX函数指针是不变的。
但在Windows OpenGL中,函数指针特定于每个上下文。 GLEW的一些版本是多上下文感知的,而其他版本则不是。因此,为了涵盖这种情况,从技术上讲,每次上下文发生变化时都必须调用它。
(编辑:由于要求澄清)
每个窗口(即每个OpenGL渲染上下文)?
首先要做的事情是:OpenGL上下文与Windows无关。拥有一个窗口但有多个渲染上下文是完全没问题的。在Microsoft Windows中,对OpenGL重要的是与窗口关联的设备上下文(DC)。但它也可以反过来:你可以有一个OpenGL上下文,但是有多个窗口使用它(只要窗口的pixelformat与OpenGL上下文兼容)。
所以这是合法的:
HWND wnd = create_a window()
HDC dc = GetDC(wnd)
PIXELFORMATDESCRIPTOR pf = select_pixelformat();
SetPixelFormat(dc, pf);
HGLRC rc0 = create_opengl_context(dc);
HGLRC rc1 = create_opengl_context(dc);
wglMakeCurrent(dc, rc0);
draw_stuff(); // uses rc0
wglMakeCurrent(dc, rc1);
draw_stuff(); // uses rc1
这是
HWND wnd0 = create_a window()
HDC dc0 = GetDC(wnd)
HWND wnd1 = create_a window()
HDC dc1 = GetDC(wnd)
PIXELFORMATDESCRIPTOR pf = select_pixelformat();
SetPixelFormat(dc0, pf);
SetPixelFormat(dc1, pf);
HGLRC rc = create_opengl_context(dc0); // works also with dc1
wglMakeCurrent(dc0, rc);
draw_stuff();
wglMakeCurrent(dc1, rc);
draw_stuff();
这是扩展进入图片的地方。像glActiveTexture
这样的函数不是OpenGL规范的一部分,它已被固定到Windows应用程序二进制接口(ABI)中。因此,您必须在运行时获取指向它的函数指针。这就是GLEW所做的。在内部它看起来像这样:
首先,它定义了函数指针的类型,将它们声明为外部变量,并使用一些预处理器魔法来避免命名空间冲突。
typedef void (*PFNGLACTIVETEXTURE)(GLenum);
extern PFNGLACTIVETEXTURE glew_ActiveTexture;
#define glActiveTexture glew_ActiveTexture;
在glewInit
中,函数指针变量设置为使用wglGetProcAddress
获得的值(为了便于阅读,我省略了类型转换)。
int glewInit(void)
{
/* ... */
if( openglsupport >= gl1_2 ) {
/* ... */
glew_ActiveTexture = wglGetProcAddress("glActiveTexture");
/* ... */
}
/* ... */
}
现在重要的部分:wglGetProcAddress
适用于调用时当前的OpenGL渲染上下文。所以无论前一次wglMakeCurrent
之前的呼叫是什么。如前所述,扩展函数指针与其OpenGL上下文绑定,不同的OpenGL上下文可以为同一函数提供不同的函数指针。
所以,如果你这样做
wglMakeCurrent(…, rc0);
glewInit();
wglMakeCurrent(…, rc1);
glActiveTexture(…);
可能会失败。因此,通常情况下,对于GLEW,每次拨打wglMakeCurrent
时都必须紧跟glewInit
。 GLEW的一些版本是多上下文感知的并且在内部执行此操作。其他人不是。但是,多次调用glewInit
是完全安全的,所以安全的方法是调用它,只是为了确定。