opengl 为每个渲染上下文调用一次glewInit?还是整个应用只运行一次

5rgfhyps  于 2023-08-04  发布在  其他
关注(0)|答案(3)|浏览(116)

如何正确使用glewInit()
假设我有一个多窗口应用程序,我应该在应用程序(即全局)级别调用glewInit()一次吗?或者为每个窗口调用glewInit()(即每个OpenGL渲染上下文)?

7xzttuei

7xzttuei1#

根据所使用的GLEW构建,防水方法是在每次上下文 * 更改 * 之后调用glewInit
使用X11/GLX函数,指针是不变的。
但在Windows中,OpenGL函数指针是特定于每个上下文的。GLEW的一些构建是多上下文感知的,而另一些则不是。所以为了涵盖这种情况,技术上你必须调用它,每次上下文发生变化。

(编辑:由于要求澄清)

对于每个窗口(即每个OpenGL渲染上下文)?
第一件事:OpenGL上下文不与窗口绑定。拥有一个窗口但拥有多个渲染上下文是非常好的。在Microsoft Windows中,对OpenGL来说重要的是与窗口关联的设备上下文(DC)。但它也可以反过来工作:你可以有一个OpenGL上下文,但多个窗口使用它(只要窗口的像素格式与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是完全安全的,所以安全的方法是调用它,只是为了确保安全。

ua4mk5z4

ua4mk5z42#

它不应该是必要的,以获得多个函数ptrs每个上下文根据这个... https://github.com/nigels-com/glew/issues/38 in 2016.
nigels-com回答了来自kest-relm的这个问题...你认为每次上下文更改都调用glewInit()是正确的吗?以上是处理多个opengl上下文的有效方法吗?
和...
我不认为为每个上下文更改调用glewInit是可取的,甚至是必要的,这取决于具体情况。显然,无论如何,这种方案不适合多线程。
Kest-relm接着说。。
从我的测试来看,似乎不需要反复调用glewInit();代码在多个上下文下运行良好,文档如下:
https://www.opengl.org/wiki/Load_OpenGL_Functions
其中规定:
实际上,如果两个上下文来自同一供应商并引用同一GPU,则从一个上下文提取的函数指针将在另一个上下文中工作。
我想这应该是大多数主流的Windows GL驱动程序的真实情况?

rjzwgtxy

rjzwgtxy3#

我认为只调用一次glewInit()就足够了。为每个上下文更改调用它可能会产生大量开销。
微软的wglGetProcAddress文档说“扩展函数地址对于每个 * 像素格式 * 都是唯一的。给定像素格式的所有渲染上下文共享相同的扩展函数地址。”
https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-wglgetprocaddress
请注意,这里说的是 * 像素格式 * 而不是 * 上下文 *,这是一个重要的区别。
大多数创建多个GL上下文的应用程序将在每个上下文上使用相同的像素格式。在这种情况下,函数指针应该是相同的,这意味着您应该只调用一次glewInit()。
但是,如果您碰巧使用不同的像素格式,wglGetProcAddress并不能严格保证函数指针相同。也就是说,我在实践中的经验是,即使在WIN32上使用不同的像素格式,它们在两个不同的上下文中通常是相同的,这种经验似乎与这里所说的一致:https://www.opengl.org/wiki/Load_OpenGL_Functions
如果性能不那么重要,并且您希望使用具有不同像素格式的多个上下文,那么您可以考虑在每个像素格式更改时调用一次glewInit()。然而,对于大多数应用程序,我认为对glewInit()的单个调用就足够了。

相关问题