问题描述
我对如何(正确)使用glewInit()
有疑问.
I have a question about how to (correctly) use glewInit()
.
假设我有一个多窗口应用程序,我应该在应用程序(即全局)级别上完全调用一次glewInit()
吗?或为每个窗口(即每个OpenGL
渲染上下文)调用glewInit()
?
Assume I have an multiple-window application, should I call glewInit()
exactly once at application (i.e., global) level? or call glewInit()
for each window (i.e., each OpenGL
rendering context)?
推荐答案
根据所使用的GLEW构建,防水方法是在每个上下文更改之后调用glewInit
!
Depending on the GLEW build being used the watertight method is to call glewInit
after each and every context change!
对于X11/GLX函数,指针是不变的.
With X11/GLX functions pointers are invariant.
但是在Windows中,OpenGL函数指针特定于每个上下文.某些GLEW构建具有多上下文感知能力,而其他构建则不是.因此,要涵盖这种情况,从技术上讲,每次上下文确实发生更改时,您都必须调用它.
But in Windows OpenGL function pointers are specific to each context. Some builds of GLEW are multi context aware, while others are not. So to cover that case, technically you have to call it, everytime the context did change.
(由于需要澄清)
第一件事:OpenGL上下文不绑定到Windows.一个窗口但有多个渲染上下文是完全可以的.在Microsoft Windows中,对OpenGL重要的是与窗口关联的设备上下文(DC).但这也反过来起作用:您可以有一个OpenGL上下文,但可以使用多个OpenGL窗口(只要窗口的pixelformat与OpenGL上下文兼容).
First things first: OpenGL contexts are not tied to windows. It is perfectly fine to have a single window but multiple rendering contexts. In Microsoft Windows what matters to OpenGL is the device context (DC) associated with a window. But it also works the other way round: You can have a single OpenGL context, but multiple windows using it (as long as the window's pixelformat is compatible with the OpenGL context).
所以这是合法的:
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所做的.内部看起来像这样:
Here's where extensions enter the picture. A function like glActiveTexture
is not part of the OpenGL specification that has been pinned down into the Windows Application Binary Interface (ABI). Hence you have to get a function pointer to it at runtime. That's what GLEW does. Internally it looks like this:
首先,它为函数指针定义类型,将它们声明为extern变量,并使用一些预处理器魔术来避免名称空间冲突.
First it defines types for the function pointers, declares them as extern variables and uses a little bit of preprocessor magic to avoid namespace collisions.
typedef void (*PFNGLACTIVETEXTURE)(GLenum);
extern PFNGLACTIVETEXTURE glew_ActiveTexture;
#define glActiveTexture glew_ActiveTexture;
在glewInit
中,将函数指针变量设置为使用wglGetProcAddress
获得的值(出于可读性考虑,我省略了类型转换).
In glewInit
the function pointer variables are set to the values obtained using wglGetProcAddress
(for the sake of readability I omit the type castings).
int glewInit(void)
{
/* ... */
if( openglsupport >= gl1_2 ) {
/* ... */
glew_ActiveTexture = wglGetProcAddress("glActiveTexture");
/* ... */
}
/* ... */
}
现在是重要的部分:wglGetProcAddress
与调用时最新的OpenGL渲染上下文一起使用.因此,对之前进行的最后一个wglMakeCurrent
调用所做的都是什么.如前所述,扩展功能指针与它们的OpenGL上下文相关联,并且不同的OpenGL上下文可能为同一函数提供不同的功能指针.
Now the important part: wglGetProcAddress
works with the OpenGL rendering context that is current at the time of calling. So whatever was to the very last wglMakeCurrent
call made before it. As already explained, extension function pointers are tied to their OpenGL context and different OpenGL contexts may give different function pointers for the same function.
因此,如果您这样做
wglMakeCurrent(…, rc0);
glewInit();
wglMakeCurrent(…, rc1);
glActiveTexture(…);
它可能会失败.因此,通常,对于GLEW,每次对wglMakeCurrent
的调用都必须紧随其后的是glewInit
.某些GLEW的版本具有多上下文意识,并且在内部执行此操作.其他不是.但是,多次调用glewInit
是绝对安全的,因此,请确保安全地调用它.
it may fail. So in general, with GLEW, every call to wglMakeCurrent
must immediately be followed by a glewInit
. Some builds of GLEW are multi context aware and do this internally. Others are not. However it is perfectly safe to call glewInit
multiple times, so the safe way is to call it, just to be sure.
这篇关于为每个渲染上下文调用一次glewInit吗?还是整个应用一次?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!