A seconda del build GLEW utilizzato, il metodo a tenuta stagna consiste nel chiamare glewInit
dopo ogni singolo modifica!
con funzioni X11/GLX puntatori sono invarianti.
Ma in puntatori a funzione di Windows OpenGL sono specifici per ogni contesto. Alcune versioni di GLEW sono multi-context aware, mentre altre no. Quindi, per coprire quel caso, tecnicamente devi chiamarlo, ogni volta che cambia il contesto.
(EDIT: a causa di richiesta di chiarimenti)
per ogni finestra (vale a dire, ogni rendering OpenGL contesto)?
Per prima cosa: i contesti OpenGL non sono legati a Windows. È perfetto avere un'unica finestra ma più contesti di rendering. In Microsoft Windows ciò che conta per OpenGL è il contesto dispositivo (DC) associato a una finestra. Ma funziona anche al contrario: puoi avere un singolo contesto OpenGL, ma più finestre che lo usano (a patto che pixelformat della finestra sia compatibile con il contesto OpenGL).
Quindi questa è legittima:
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
così è questa
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();
Ecco dove estensioni entrano in scena. Una funzione come glActiveTexture
non fa parte delle specifiche OpenGL che sono state bloccate in Windows Application Binary Interface (ABI). Quindi è necessario ottenere un puntatore a funzione in fase di esecuzione. Questo è ciò che GLEW fa. Internamente è simile al seguente:
Prima definisce i tipi per i puntatori di funzione, li dichiara come variabili esterne e utilizza un po 'di magia del preprocessore per evitare collisioni nello spazio dei nomi.
typedef void (*PFNGLACTIVETEXTURE)(GLenum);
extern PFNGLACTIVETEXTURE glew_ActiveTexture;
#define glActiveTexture glew_ActiveTexture;
In glewInit
variabili puntatore funzione sono impostati ai valori ottenuti usando wglGetProcAddress
(per motivi di leggibilità I omettere i getti di tipo).
int glewInit(void)
{
/* ... */
if(openglsupport >= gl1_2) {
/* ... */
glew_ActiveTexture = wglGetProcAddress("glActiveTexture");
/* ... */
}
/* ... */
}
Ora la parte importante: wglGetProcAddress
lavori con il contesto di rendering OpenGL che è in corso al momento della chiamata. Quindi, qualunque cosa fosse fino all'ultimo, la chiamata effettuata da wglMakeCurrent
. Come già spiegato, i puntatori alle funzioni di estensione sono legati al loro contesto OpenGL e diversi contesti OpenGL possono fornire diversi puntatori di funzione per la stessa funzione.
Quindi, se si esegue questa operazione
wglMakeCurrent(…, rc0);
glewInit();
wglMakeCurrent(…, rc1);
glActiveTexture(…);
potrebbe non riuscire. Quindi, in generale, con GLEW, ogni chiamata a wglMakeCurrent
deve essere immediatamente seguita da un glewInit
. Alcune versioni di GLEW sono multi-context aware e lo fanno internamente. Gli altri non lo sono. Tuttavia è perfettamente sicuro chiamare più volte glewInit
, quindi il modo sicuro è chiamarlo, per sicurezza.
Ma ancora non capisco completamente. Potresti spiegare un po 'di più sul contesto "cambiare"? –
@ChanggongZhang: vedere il mio aggiornamento. – datenwolf
Ho appena notato che glew fornisce anche [glew32mx.lib, glew32mx.dll]. Questo significa che se voglio creare un'applicazione multi-finestra, dovrei usare glew32mx.dll piuttosto che glew32.dll? E un'altra domanda di follow-up. Potresti @datenwolf fornire una vera e propria applicazione examplex per i multiple-DC-single-RC e single-DC-multiple-RCs? –