为每个渲染上下文调用一次 glewInit?还是整个应用程序只有一次?

Call glewInit once for each rendering context? or exactly once for the whole app?

我有一个关于如何(正确)使用 glewInit() 的问题。

假设我有一个多 window 应用程序,我应该在应用程序(即全局)级别只调用一次 glewInit() 吗?或为每个 window(即每个 OpenGL 呈现上下文)调用 glewInit()

根据所使用的 GLEW 构建,无懈可击的方法是在每个上下文 change!

之后调用 glewInit

对于 X11/GLX 函数,指针是不变的。

但在 Windows 中,OpenGL 函数指针特定于每个上下文。 GLEW 的一些构建是多上下文感知的,而另一些则不是。因此,为了涵盖这种情况,从技术上讲,每次上下文确实发生变化时,您都必须调用它。

(编辑:由于要求澄清)

for each window (i.e., each OpenGL rendering context)?

首先要注意的是:OpenGL 上下文与 windows 无关。拥有一个 window 但多个渲染上下文是完全没问题的。在 Microsoft Windows 中,对 OpenGL 重要的是与 window 关联的 设备上下文 (DC)。但它也可以反过来工作:您可以有一个 OpenGL 上下文,但多个 windows 使用它(只要 window 的像素格式与 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 之类的函数不是已固定到 Windows 应用程序二进制接口 (ABI) 中的 OpenGL 规范的一部分。因此,您必须在运行时获取指向它的函数指针。这就是 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 是绝对安全的,所以安全的方法是调用它,只是为了确定。

根据这个,应该没有必要在每个上下文中获得多个功能指针... https://github.com/nigels-com/glew/issues/38 2016 ....

nigels-com 从 kest-relm 回答了这个问题…  你认为每次上下文变化都调用 glewInit() 是正确的吗?  以上是处理多个 opengl 上下文的有效方法吗?

...与...

我不认为每次上下文更改都调用 glewInit 是可取的,甚至是必要的,具体取决于具体情况。 显然这个方案无论如何都不适合多线程。

Kest-relm 然后说……

根据我的测试,似乎不需要重复调​​用 glewInit();代码在多个上下文中运行得很好 它记录在这里:

https://www.opengl.org/wiki/Load_OpenGL_Functions

其中指出:

“实际上,如果两个上下文来自同一个供应商并引用同一个 GPU,那么从一个上下文中提取的函数指针将在另一个上下文中工作。”

我认为这对于大多数主流 Windows GL 驱动程序应该是正确的?