Ok, I finally have found a time to get back to OpenGL, and since GL 3.0 is out, I decided to start from here.
Unfortunately, I cannot even initialize 3.0 in a clean way, and there are quite a few questions I cannot find an answers for.
The questions that confuse me are:
-
Version strings
If I call functions to retrieve version on legacy context, they all return 3.0. Is that something I can rely on, or is it possible that old context will return 2.1 and the new one 3.5 for example? Seems that if I have 3.5 and I query 3.0, then old context will say 3.5, but the new one 3.0?
glGetIntegerv(GL_MAJOR_VERSION, &major);//3
glGetIntegerv(GL_MINOR_VERSION, &minor);//0
glGetString(GL_VERSION);//3.0.0 -
wglGetExtensionsStringARB and wglCreateContextAttribsARB
Both functions are necessary to create 3.0 rendering context in Windows, but what is the correct way to query them?
Can I rely on GL version, or do I have to check the extension string first? If I have to check the extension string, what is the purpose of the GetStringi? I will have to resort to glGetString(GL_EXTENSIONS) anyway because there is no GetStringi in GL 1.0. What is the minimal OpenGL version requirement for GetStringi? -
Extension strings in legacy/future contexts
Do I have to requery extension string in 3.5 context if I have done that in legacy context? Are the extensions supposed to change GL/WGL/GLX? -
WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
Why is glGetStringi(GL_EXTENSIONS, i) failing with error 0x500 (GL_INVALID_ENUM) in forward compatible context?
glGetString(GL_EXTENSIONS) is supposed to be deprecated, but isn’t the glGetStringi the correct way to query extensions now? It works without forward compatible bit though, NVIDIA, FW 182.06. -
wglGetProcAddress
Do I have to requery function addresses in GL 3.5 if I have queried them under legacy context?
BOOL retval = FALSE;
WNDCLASSW wc = {0};
wc.style = CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hIcon = LoadIconW(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszClassName = L"GLWndClass";
retval = RegisterClassW(&wc);
if(!retval)
{
return 1;
}
HWND hWnd = CreateWindowW(L"GLWndClass", L"OpenGL 3.0 Test", WS_POPUPWINDOW | WS_VISIBLE, 10, 10, 512, 512, NULL, NULL, hInstance, NULL);
if(!hWnd)
{
UnregisterClassW(L"GLWndClass", hInstance);
return 1;
}
HDC hDC = GetDC(hWnd);
if(!hDC)
{
DestroyWindow(hWnd);
UnregisterClassW(L"GLWndClass", hInstance);
return 1;
}
PIXELFORMATDESCRIPTOR pfd = {0};
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
int pf = ChoosePixelFormat(hDC, &pfd);
if(!pf)
{
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
UnregisterClassW(L"GLWndClass", hInstance);
return 1;
}
retval = SetPixelFormat(hDC, pf, &pfd);
if(!retval)
{
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
UnregisterClassW(L"GLWndClass", hInstance);
return 1;
}
HGLRC hLegacyRC = wglCreateContext(hDC);
if(!hLegacyRC)
{
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
UnregisterClassW(L"GLWndClass", hInstance);
return 1;
}
retval = wglMakeCurrent(hDC, hLegacyRC);
if(!retval)
{
wglDeleteContext(hLegacyRC);
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
UnregisterClassW(L"GLWndClass", hInstance);
return 1;
}
int major;
glGetIntegerv(GL_MAJOR_VERSION, &major);//3
int minor;
glGetIntegerv(GL_MINOR_VERSION, &minor);//0
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
if(!wglGetExtensionsStringARB || !wglCreateContextAttribsARB)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hLegacyRC);
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
UnregisterClassW(L"GLWndClass", hInstance);
return 1;
}
GLenum err = 0;
const GLubyte *ver1 = glGetString(GL_VERSION);//3.0.0
int params[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 0,
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
NULL, NULL};
HGLRC hNewRC = wglCreateContextAttribsARB(hDC, NULL, params);
if(!hNewRC)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hLegacyRC);
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
UnregisterClassW(L"GLWndClass", hInstance);
return 1;
}
retval = wglMakeCurrent(hDC, hNewRC);
if(retval)
{
wglDeleteContext(hLegacyRC);
hLegacyRC = NULL;
}
else
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hLegacyRC);
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
UnregisterClassW(L"GLWndClass", hInstance);
return 1;
}
const GLubyte *ver2 = glGetString(GL_VERSION);//3.0.0
err = glGetError();
PFNGLGETSTRINGIPROC glGetStringi = (PFNGLGETSTRINGIPROC)wglGetProcAddress("glGetStringi");
glGetIntegerv(GL_MAJOR_VERSION, &major);//3
err = glGetError();
glGetIntegerv(GL_MINOR_VERSION, &minor);//0
err = glGetError();
set<string> extensionList;
GLint extCount;
glGetIntegerv(GL_NUM_EXTENSIONS, &extCount);
for (GLint i = 0; i < extCount; i++)
{
char *currExt = (char*)glGetStringi(GL_EXTENSIONS, i);//returns NULL
err = glGetError();
string ext = currExt; //0x500
extensionList.insert(ext);
}
__asm int 3;