Je nach verwendetem GLEW-Build lautet die wasserdichte Methode glewInit
nach jedem Kontext Änderung!
Mit X11/GLX-Funktionen sind Zeiger invariant.
Aber in Windows OpenGL Funktionszeiger sind spezifisch für jeden Kontext. Einige Builds von GLEW sind multikontextbewusst, andere nicht. Um diesen Fall zu erfassen, müssen Sie ihn technisch benennen, immer wenn sich der Kontext ändert.
(EDIT: aufgrund Anfrage zur Klärung)
für jedes Fenster (das heißt, jeder OpenGL Rendering-Kontext)?
Das Wichtigste zuerst: OpenGL-Kontexte sind nicht an Windows gebunden. Es ist vollkommen in Ordnung, ein einzelnes Fenster, aber mehrere Renderkontexte zu haben. In Microsoft Windows, was OpenGL betrifft, ist der Gerätekontext (DC) mit einem Fenster verbunden. Es funktioniert aber auch anders herum: Sie können einen einzelnen OpenGL-Kontext haben, aber mehrere Fenster, die ihn verwenden (solange das Pixelformat des Fensters mit dem OpenGL-Kontext kompatibel ist).
Das ist also legitim:
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
Und so ist diese
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();
Hier, wo Erweiterungen das Bild eingeben. Eine Funktion wie glActiveTexture
ist nicht Teil der OpenGL-Spezifikation, die in der Windows Application Binary Interface (ABI) festgelegt wurde. Daher müssen Sie zur Laufzeit einen Funktionszeiger darauf bekommen. Das macht GLEW. Intern sieht es folgendermaßen aus:
Zuerst definiert es Typen für die Funktionszeiger, deklariert sie als externe Variablen und verwendet ein wenig Präprozessor-Magie, um Namespace-Kollisionen zu vermeiden.
typedef void (*PFNGLACTIVETEXTURE)(GLenum);
extern PFNGLACTIVETEXTURE glew_ActiveTexture;
#define glActiveTexture glew_ActiveTexture;
glewInit
In den Funktionszeiger-Variablen werden auf die Werte gesetzt, erhalten unter Verwendung wglGetProcAddress
(aus Gründen der Lesbarkeit ich die Art Gußteile wegzulassen). Jetzt
int glewInit(void)
{
/* ... */
if(openglsupport >= gl1_2) {
/* ... */
glew_ActiveTexture = wglGetProcAddress("glActiveTexture");
/* ... */
}
/* ... */
}
der wichtige Teil: wglGetProcAddress
Arbeiten mit dem OpenGL Rendering Kontext, der zum Zeitpunkt des Aufrufs aktuell ist. Also was immer bis zuletzt wglMakeCurrent
Anruf davor gemacht wurde. Wie bereits erläutert, sind Erweiterungsfunktionszeiger an ihren OpenGL-Kontext gebunden und verschiedene OpenGL-Kontexte können verschiedene Funktionszeiger für dieselbe Funktion ergeben.
Also, wenn Sie dies tun
wglMakeCurrent(…, rc0);
glewInit();
wglMakeCurrent(…, rc1);
glActiveTexture(…);
es fehlschlagen. Im Allgemeinen muss also bei GLEW jedem Aufruf an wglMakeCurrent
sofort eine glewInit
folgen. Einige Builds von GLEW sind multikontextbewusst und tun dies intern. Andere sind nicht. Es ist jedoch absolut sicher, glewInit
mehrere Male zu rufen, also ist der sichere Weg, es zu nennen, nur um sicher zu sein.
Aber ich verstehe immer noch nicht vollständig. Könntest du ein bisschen mehr über Kontext "change" erklären? –
@ChanggongZhang: siehe mein Update. – datenwolf
Ich habe gerade bemerkt, dass glew auch [glew32mx.lib, glew32mx.dll] bereitstellt. Bedeutet das, wenn ich eine Multi-Fenster-App erstellen möchte, sollte ich glew32mx.dll statt glew32.dll verwenden? Und noch eine weitere Frage. Könnten Sie @datenwolf ein echtes Anwendungsbeispiel für die Multi-DCs-Single-RC und Single-DC-Multiple-RCs bieten? –