OpenGL 3.0 confusion

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:

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

  2. 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?

  3. 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?

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

  5. 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;
  1. Version queries seem to work with the added twist that in a GL3 context you use the new entry points.

  2. You need a valid context to get either of these procs anyway (a bit like creating a multisample context).

  3. The MSDNL suggests that the procs belonging to one context (pixelformat?) are not necessarily valid in another, tho in practice this restriction/warning may be relaxed/lifted. Anyway the pattern of first creating a “default” context followed by the version du jour seems to be our lot in life going forward.

  4. Dunno.

  5. Likely as in (3) I would think, but you’ll probably want to grab the goods in GL3 anyways. I’d go for the clean slate with a fresh batch of procs per version/context.

Well, all this thing looks even nastier than I thought. The only thing that is available is OpenGL 3.0 spec and GLSL 1.3 spec. They are full of glBegin sort of stuff that is not even supported in forward compatible context.
All functions seem to be deprecated and the only way to specify vertices seems to be through VBO.

Matrix functions are gone, and there are no built in functions to perform any sort of matrix manipulation.

Ok, I’m not scared as of yet, as I know the math behind matrix algebra and I’ve done some GLSL 1.1 + VBO + FBO stuff, but OpenGL is far from newbie friendly now.

Right now I need to reread VBO specs, reimplement matrix algebra for projection and translation stuff, find where is the old quaternion classes I used before, recheck the GLSL syntax and all of this to draw a triangle.

Crazy…

Remember, in 3.0 everything is still there. Deprecated only means it could be removed in a future version context (which your app would have to explicitly request once available). You can continue to use the deprecated functions in a 3.0 context.

Well, as far as I understand, not if you use FORWARD_COMPATIBLE flag.

And you will have to switch to new functions eventually, it’s better to do than now rather than later. Which isn’t newbie friendly like the GL used to be compared to DX.

That’s correct, if you request forward compatible then you have to restrict yourself to the non deprecated core features.

If you’re a true beginner then you may not need the feature set of 3.1 or higher and 3.0 could be the right place to start. The thing to keep in mind is that no one is being forced to go to the higher versions until they are ready to do so.

Your POV may be that you want to start using the newer functions (avoiding deprecated functionality) sooner rather than later, and that is your choice to make. However it is not a choice that is forced upon anyone.