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

3

13

I have a question about how to (correctly) use 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)?

Incantation answered 28/2, 2016 at 13:50 Comment(0)
K
15

Depending on the GLEW build being used the watertight method is to call glewInit after each and every context change!

With X11/GLX functions pointers are invariant.

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.

(EDIT: due to request for clarification)

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

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).

So this is legitimate:

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

And so is this

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();

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:

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;

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");
    /* ... */
    }

    /* ... */
}

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.

So if you do this

wglMakeCurrent(…, rc0);
glewInit();
wglMakeCurrent(…, rc1);
glActiveTexture(…);

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.

Konikow answered 28/2, 2016 at 20:32 Comment(10)
But I still do not fully understand. Could you explain a little bit more on context "change"?Incantation
I just noticed that glew also provides [glew32mx.lib, glew32mx.dll]. Does this mean If I want to create a multi-window app, I should use glew32mx.dll rather than glew32.dll? And another following-up question. Could you @Konikow provide real application examplex for the multiple-DCs-single-RC & single-DC-multiple-RCs?Incantation
@ChanggongZhang: Multi DC single RC: Most programs that were written before framebuffer objects became available and had to fall back to PBuffers for render to texture (used in shadow mapping or similar). Single DC multiple RC: The majority of 3rd party plugins for 3D modelling applications use their own RC to avoid cluttering the main application's RC.Konikow
@ChanggongZhang: If your multi-window application uses only a single RC you don't need the -mx variant. But using it doesn't hurt, so if you don't know details about the inner workings of your program (regarding OpenGL context management) better be safe than sorry and use mx.Konikow
could you further summarize the pros and cons for the 3 cases {Multi DC Single RC, Single DC Multi RC, Single DC Single RC}?Incantation
@ChanggongZhang: There are no pros and cons. Each case has its very own use case for which it is mutually exclusive with the other cases and that's how you choose what to do.Konikow
@Konikow Rather than using glew, would it be valid/advisable to cache the opengl function pointers for every rendering context, perhaps using a struct? Something like struct GLContext { HGLRC m_context; PFNGLACTIVETEXTURE glActiveTexture; ... }; In order to avoid loading them with every switch? I imagine this could be useful if you had multiple context where each is current in its own different thread, for example.Longinus
@nasser-sh: This is a perfectly fine solution. If you're using OpenGL with Qt the QOpenGLFunctions class is doing exactly that. doc.qt.io/qt-5/qopenglfunctions.html#QOpenGLFunctions-1Konikow
Thank you for nice. answer..But could you explain wnd - dc - rc relation ship more clearly.? I thought all three is one to one matching..Unbalanced
@MarkYang: A Windows GDI HWND can have one to many DCs all tied to it. But that's about it. OpenGL RCs have no ties to anything else, than the pixelformat they have been created with. That the WGL uses a DC's pixelformat as a proxy for configuring that is unfortunate, because it is suggestive. The thing is: You can use any given OpenGL RC on any window and DC, as long as their pixelformat are compatible to what the OpenGL RC has been created for.Konikow
P
1

It should not be necessary to get multiple function ptrs one-per-context according to this... https://github.com/nigels-com/glew/issues/38 in 2016 ....

nigels-com answers this question from kest-relm…  do you think it is correct to call glewInit() for every context change?  Is the above the valid way to go for handling multiple opengl contexts?

…with…

I don't think calling glewInit for each context change is desirable, or even necessary, depending on the circumstances. Obviously this scheme would not be appropriate for multi-threading, anyway.

Kest-relm then says…

From my testing it seems like calling glewInit() repeatedly is not required; the code runs just fine with multiple contexts It is documented here:

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

where it states:

"In practice, if two contexts come from the same vendor and refer to the same GPU, then the function pointers pulled from one context will work in the other."

I assume this should be true for most mainstream Windows GL drivers?

Press answered 20/1, 2022 at 10:34 Comment(0)
S
0

I think it is sufficient to call glewInit() once only. Calling it for each context change could have a lot of overhead.

The Microsoft documentation for wglGetProcAddress says that "The extension function addresses are unique for each pixel format. All rendering contexts of a given pixel format share the same extension function addresses."

https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-wglgetprocaddress

Note that it says pixel format not context here, which is an important distinction.

Most applications that create multiple GL contexts will be using the same pixel format on each context. In this case, the function pointers should be the same, which implies that you should be fine to call glewInit() once only.

However, if you do happen to use different pixel formats, wglGetProcAddress does not strictly guarantee that the function pointers will be the same. That said, my experience in practice is that they usually are the same for two different contexts even with different pixel formats on WIN32, and this experience seems to agree with what it says here: https://www.opengl.org/wiki/Load_OpenGL_Functions

If performance is less critical and you want to use multiple contexts with different pixel formats, then you could consider calling glewInit() once per pixel format change. However, for most applications I think a single call to glewInit() would be sufficient.

Stipel answered 6/7, 2023 at 13:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.