A question about GLEW Windows setup

Started by
24 comments, last by NicoG 12 years, 8 months ago
Hey everybody, I've been programming an application with wgl and glew, and there's one thing that's been bothering me with the code. It's required that a rendering context needs to be initialized before glew itself can be initialized. But what's getting to me is that, in my case, the rendering context requires glew to be initialized as well (since I call wglChoosePixelFormatARB for the context's pixel format, which is part of glew). This over all requires me to create a "dummy" rendering context just to initialize glew, and thus an extra device context and window (all of which would be deleted and reallocated later on). Is there a better way to implement this? I'd rather my code be a bit more cohesive so that I can reuse my variables more effectively, and managing the creation of these "dummy" variables bulks up my code to an extra 50 lines of code at least.

Here's the code in question, in my case:

bool SetupWindow(int nWidth, int nHeight, bool bUseFS)
{
bool bRetVal = true;

int nWindowX = 0;
int nWindowY = 0;
int nPixelFormat = NULL;
PIXELFORMATDESCRIPTOR pfd;

DWORD dwExtStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
DWORD dwWindStyle = WS_OVERLAPPEDWINDOW;

HINSTANCE g_hInstance = GetModuleHandle(NULL);

if(bUseFS)
{
// Prepare for a mode set to the requested resolution
DEVMODE dm;
memset(&dm,0,sizeof(dm));
dm.dmSize=sizeof(dm);
dm.dmPelsWidth = nWidth;
dm.dmPelsHeight = nHeight;
dm.dmBitsPerPel = 32;
dm.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

long error = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);

if (error != DISP_CHANGE_SUCCESSFUL)
{
// Oops, something went wrong, let the user know.
if (MessageBox(NULL, TEXT("Could not set fullscreen mode.\n\
Your video card may not support the requested mode.\n\
Use windowed mode instead?"),
g_szAppName, MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
g_InFullScreen = false;
dwExtStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwWindStyle = WS_OVERLAPPEDWINDOW;
}
else
{
MessageBox(NULL, TEXT("Program will exit."), TEXT("ERROR"), MB_OK|MB_ICONSTOP);
return false;
}
}
else
{
// Mode set passed, setup the styles for fullscreen
g_InFullScreen = true;
dwExtStyle = WS_EX_APPWINDOW;
dwWindStyle = WS_POPUP;
ShowCursor(FALSE);
}
}

// setup window class
g_windClass.lpszClassName = g_szClassName; // Set the name of the Class
g_windClass.lpfnWndProc = (WNDPROC)WndProc;
g_windClass.hInstance = g_hInstance; // Use this module for the module handle
g_windClass.hCursor = LoadCursor(NULL, IDC_ARROW);// Pick the default mouse cursor
g_windClass.hIcon = LoadIcon(NULL, IDI_WINLOGO);// Pick the default windows icons
g_windClass.hbrBackground = NULL; // No Background
g_windClass.lpszMenuName = NULL; // No menu for this window
g_windClass.style = CS_HREDRAW | CS_OWNDC | // set styles for this class, specifically to catch
CS_VREDRAW; // window redraws, unique DC, and resize
g_windClass.cbClsExtra = 0; // Extra class memory
g_windClass.cbWndExtra = 0; // Extra window memory

// Register the newly defined class
if(!RegisterClass( &g_windClass ))
bRetVal = false;

g_windowRect.left = nWindowX;
g_windowRect.right = nWindowX + nWidth;
g_windowRect.top = nWindowY;
g_windowRect.bottom = nWindowY + nHeight;

// Setup window width and height
AdjustWindowRectEx(&g_windowRect, dwWindStyle, FALSE, dwExtStyle);

//Adjust for adornments
int nWindowWidth = g_windowRect.right - g_windowRect.left;
int nWindowHeight = g_windowRect.bottom - g_windowRect.top;

// Create window
g_hWnd = CreateWindowEx(dwExtStyle, // Extended style
g_szClassName, // class name
g_szAppName, // window name
dwWindStyle |
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN,// window stlye
nWindowX, // window position, x
nWindowY, // window position, y
nWindowWidth, // height
nWindowHeight, // width
NULL, // Parent window
NULL, // menu
g_hInstance, // instance
NULL); // pass this to WM_CREATE

// now that we have a window, setup the pixel format descriptor
g_hDC = GetDC(g_hWnd);

// Set a dummy pixel format so that we can get access to wgl functions
SetPixelFormat( g_hDC, 1, &pfd);
// Create OGL context and make it current
g_hRC = wglCreateContext( g_hDC );
wglMakeCurrent( g_hDC, g_hRC );

if (g_hDC == 0 ||
g_hRC == 0)
{
bRetVal = false;
MessageBox(NULL,
TEXT("!!! An error occured creating an OpenGL window.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);
}

// Setup GLEW which loads OGL function pointers
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
bRetVal = false;
printf("Error: %s\n", glewGetErrorString(err));
}
const GLubyte *oglVersion = glGetString(GL_VERSION);
printf("This system supports OpenGL Version %s.\n", oglVersion);

// Now that extensions are setup, delete window and start over picking a real format.
wglMakeCurrent(NULL, NULL);
wglDeleteContext(g_hRC);
ReleaseDC(g_hWnd, g_hDC);
DestroyWindow(g_hWnd);

// Create the window again
g_hWnd = CreateWindowEx(dwExtStyle, // Extended style
g_szClassName, // class name
g_szAppName, // window name
dwWindStyle |
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN,// window stlye
nWindowX, // window position, x
nWindowY, // window position, y
nWindowWidth, // height
nWindowHeight, // width
NULL, // Parent window
NULL, // menu
g_hInstance, // instance
NULL); // pass this to WM_CREATE

g_hDC = GetDC(g_hWnd);

int nPixCount = 0;

// Specify the important attributes we care about
int pixAttribs[] = { WGL_SUPPORT_OPENGL_ARB, 1, // Must support OGL rendering
WGL_DRAW_TO_WINDOW_ARB, 1, // pf that can run a window
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, // must be HW accelerated
WGL_COLOR_BITS_ARB, 24, // 8 bits of each R, G and B
WGL_DEPTH_BITS_ARB, 16, // 16 bits of depth precision for window
WGL_DOUBLE_BUFFER_ARB, GL_TRUE, // Double buffered context
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, // MSAA on
WGL_SAMPLES_ARB, 8, // 8x MSAA
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, // pf should be RGBA type
0}; // NULL termination

// Ask OpenGL to find the most relevant format matching our attribs
// Only get one format back.
wglChoosePixelFormatARB(g_hDC, pixAttribs, NULL, 1, &nPixelFormat, (UINT*)&nPixCount);

if(nPixelFormat == NULL)
{
MessageBox(NULL,
TEXT("!!! An error occurred trying to find a MSAA pixel format with the requested attribs.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);

// Try again without MSAA
pixAttribs[15] = 1;
wglChoosePixelFormatARB(g_hDC, pixAttribs, NULL, 1, &nPixelFormat, (UINT*)&nPixCount);

if(nPixelFormat == NULL)
{
// Couldn't find a format, perhaps no 3D HW or drivers are installed
g_hDC = 0;
g_hRC = 0;
bRetVal = false;
MessageBox(NULL,
TEXT("!!! An error occurred trying to find a pixel format with the requested attribs.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);
}
}

if(nPixelFormat != NULL)
{
// Check for MSAA
int attrib[] = { WGL_SAMPLES_ARB };
int nResults = 0;
wglGetPixelFormatAttribivARB(g_hDC, nPixelFormat, 0, 1, attrib, &nResults);
printf("Chosen pixel format is MSAA with %d samples.\n", nResults);

// Got a format, now set it as the current one
SetPixelFormat( g_hDC, nPixelFormat, &pfd );

GLint attribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
0 };

g_hRC = wglCreateContextAttribsARB(g_hDC, 0, attribs);
if (g_hRC == NULL)
{
MessageBox(NULL,
TEXT("!!! Could not create an OpenGL 3.3 context.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);

attribs[3] = 2;
g_hRC = wglCreateContextAttribsARB(g_hDC, 0, attribs);

if (g_hRC == NULL)
{
MessageBox(NULL,
TEXT("!!! Could not create an OpenGL 3.2 context.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);

attribs[3] = 1;
g_hRC = wglCreateContextAttribsARB(g_hDC, 0, attribs);

if (g_hRC == NULL)
{
MessageBox(NULL,
TEXT("!!! Could not create an OpenGL 3.1 context.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);

attribs[3] = 0;
g_hRC = wglCreateContextAttribsARB(g_hDC, 0, attribs);

if (g_hRC == NULL)
{
MessageBox(NULL,
TEXT("!!! Could not create an OpenGL 3.0 context.\n!!! OpenGL 3.0 and higher are not supported on this system.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);
}
}
}
}

wglMakeCurrent( g_hDC, g_hRC );
}

if (g_hDC == 0 ||
g_hRC == 0)
{
bRetVal = false;
MessageBox(NULL,
TEXT("!!! An error occured creating an OpenGL window."),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);
}

// If everything went as planned, display the window
if( bRetVal )
{
ShowWindow( g_hWnd, SW_SHOW );
SetForegroundWindow( g_hWnd );
SetFocus( g_hWnd );
g_ContinueRendering = true;
}

return bRetVal;
}


Help is greatly appreciated!

Side note: I know that there is also WGLs ChoosePixelFormat function, but as far as I know that is older than the glew version and not necessarily recommended by the ARB.
Advertisement

Is there a better way to implement this?


No.


I'd rather my code be a bit more cohesive so that I can reuse my variables more effectively, and managing the creation of these "dummy" variables bulks up my code to an extra 50 lines of code at least.
[/quote]

Which are (1) incorrect and (2) can be reduced to about 10. Incorrect because I don't see where you'd set up PIXELFORMATDESCRIPTOR to create dummy context. You may end up with no GL context or 1.1 Microsoft context, and then wonder why glew doesn't work like you'd expect.
Can be reduced because your dummy window doesn't need a style or particular size (1x1 window is enough).
And once you've written that code, you'll hardly be ever touching it again, so in my opinion no big deal here.


Side note: I know that there is also WGLs ChoosePixelFormat function, but as far as I know that is older than the glew version and not necessarily recommended by the ARB.
[/quote]


What makes you think so? ChoosePixelFormat just doesn't allow you to set some additional attributes, that's all. And you still need it to properly set up pfd when creating dummy window.
WBW, capricorn
So basically your code is
PIXELFORMATDESCRIPTOR pfd;
SetPixelFormat( g_hDC, 1, &pfd);

Any reason why you are not using ChoosePixelFormat? And why do you pass a non-initialized variable to SetPixelFormat? There are examples all over the net on how to setup a pixel format.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
You need the dummy context to get the function pointers. There's really no way around that. But what I suggest you do instead of initializing GLEW in the middle of your window manager, just load the handful of function pointers you need to proceed, then go ahead to create the real one using your new functions and destroy the dummy context. Once the dummy context is created, it's just one additional line of code per function you want to use.
[source]
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
[/source]
The reason you need the dummy rendering context is that function pointers is rendering context dependent. This is important to be aware of because if the dummy context is not from your hardware driver, you likely won't get the correct function pointer to set the pixel format, if you get anything at all. It also implies that you shouldn't load function pointers at all until the real rendering context is created. So don't initialize GLEW until after the real rendering context is created, so load the handful of functions you need manually.

edit: Well, what the above said about the pixel format applies of course. But at some point you may need these intermediate functions to manage your rendering context; for example if you do need an exclusive pixel format, or simply a post-3.0 context, then you need to consider this.
I have a bit more understanding about how this is supposed to work, so thanks for the insight so far everybody. Hopefully someone can resolve my last few questions.

It also implies that you shouldn't load function pointers at all until the real rendering context is created. [/quote]
Is wglChoosePixelFormatARB an exception to this? It is part of the creation of the rendering context itself, after all.
And that actually raises another question in my head: how is wglChoosePixelFormatARB itself dependent on the rendering context being initialized?

Any reason why you are not using ChoosePixelFormat? [/quote]
I suppose it's just a tendency on my part to have the most updated material possible to work with. Just personal preference, I suppose. What Brother Bob said at the end of his post.

And why do you pass a non-initialized variable to SetPixelFormat? [/quote]
Are you referring to the pfd? Isn't SetPixelFormat supposed to initialize that to the data held in the pixel format?

Which are (1) incorrect and (2) can be reduced to about 10. Incorrect because I don't see where you'd set up PIXELFORMATDESCRIPTOR to create dummy context. You may end up with no GL context or 1.1 Microsoft context, and then wonder why glew doesn't work like you'd expect.
Can be reduced because your dummy window doesn't need a style or particular size (1x1 window is enough).[/quote]
Do you mean that I don't even need a pfd for the dummy contexts? Or a window?

EDIT: I've tried to trim down the code a bit:

bool SetupWindow(int nWidth, int nHeight)
{
bool bRetVal = true;

int nWindowX = 0;
int nWindowY = 0;
int nPixelFormat = NULL;
PIXELFORMATDESCRIPTOR pfd;

DWORD dwExtStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
DWORD dwWindStyle = WS_OVERLAPPEDWINDOW;

HINSTANCE g_hInstance = GetModuleHandle(NULL);

// setup window class
g_windClass.lpszClassName = g_szClassName; // Set the name of the Class
g_windClass.lpfnWndProc = (WNDPROC)WndProc;
g_windClass.hInstance = g_hInstance; // Use this module for the module handle
g_windClass.hCursor = LoadCursor(NULL, IDC_ARROW);// Pick the default mouse cursor
g_windClass.hIcon = LoadIcon(NULL, IDI_WINLOGO);// Pick the default windows icons
g_windClass.hbrBackground = NULL; // No Background
g_windClass.lpszMenuName = NULL; // No menu for this window
g_windClass.style = CS_HREDRAW | CS_OWNDC | // set styles for this class, specifically to catch
CS_VREDRAW; // window redraws, unique DC, and resize
g_windClass.cbClsExtra = 0; // Extra class memory
g_windClass.cbWndExtra = 0; // Extra window memory

// Register the newly defined class
if(!RegisterClass( &g_windClass ))
bRetVal = false;

g_windowRect.left = nWindowX;
g_windowRect.right = nWindowX + nWidth;
g_windowRect.top = nWindowY;
g_windowRect.bottom = nWindowY + nHeight;

// Setup window width and height
AdjustWindowRectEx(&g_windowRect, dwWindStyle, FALSE, dwExtStyle);

//Adjust for adornments
nWidth = g_windowRect.right - g_windowRect.left;
nHeight = g_windowRect.bottom - g_windowRect.top;

// Create the window
g_hWnd = CreateWindowEx(dwExtStyle, // Extended style
g_szClassName, // class name
g_szAppName, // window name
dwWindStyle |
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN,// window stlye
nWindowX, // window position, x
nWindowY, // window position, y
nWidth, // height
nHeight, // width
NULL, // Parent window
NULL, // menu
g_hInstance, // instance
NULL); // pass this to WM_CREATE

g_hDC = GetDC(g_hWnd);
SetPixelFormat( g_hDC, 1, &pfd); // Set a dummy pixel format so that we can get access to wgl functions
g_hRC = wglCreateContext( g_hDC ); // Create OGL context
wglMakeCurrent( g_hDC, g_hRC ); // and make it current

PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");

int nPixCount = 0;

// Specify the important attributes we care about
int pixAttribs[] = { WGL_SUPPORT_OPENGL_ARB, 1, // Must support OGL rendering
WGL_DRAW_TO_WINDOW_ARB, 1, // pf that can run a window
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, // must be HW accelerated
WGL_COLOR_BITS_ARB, 24, // 8 bits of each R, G and B
WGL_DEPTH_BITS_ARB, 16, // 16 bits of depth precision for window
WGL_DOUBLE_BUFFER_ARB, GL_TRUE, // Double buffered context
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, // MSAA on
WGL_SAMPLES_ARB, 8, // 8x MSAA
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, // pf should be RGBA type
0}; // NULL termination

// Ask OpenGL to find the most relevant format matching our attribs
// Only get one format back.
wglChoosePixelFormat(g_hDC, pixAttribs, NULL, 1, &nPixelFormat, (UINT*)&nPixCount);

if(nPixelFormat == NULL)
{
MessageBox(NULL,
TEXT("!!! An error occurred trying to find a MSAA pixel format with the requested attribs.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);

// Try again without MSAA
pixAttribs[15] = 1;
wglChoosePixelFormat(g_hDC, pixAttribs, NULL, 1, &nPixelFormat, (UINT*)&nPixCount);

if(nPixelFormat == NULL)
{
// Couldn't find a format, perhaps no 3D HW or drivers are installed
g_hDC = 0;
g_hRC = 0;
bRetVal = false;
MessageBox(NULL,
TEXT("!!! An error occurred trying to find a pixel format with the requested attribs.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);
}
}

if(nPixelFormat != NULL)
{
// Got a format, now set it as the current one
SetPixelFormat( g_hDC, nPixelFormat, &pfd );

GLint attribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
0 };

g_hRC = wglCreateContextAttribs(g_hDC, 0, attribs);
if (g_hRC == NULL)
{
MessageBox(NULL,
TEXT("!!! Could not create an OpenGL 3.3 context.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);

attribs[3] = 2;
g_hRC = wglCreateContextAttribs(g_hDC, 0, attribs);

if (g_hRC == NULL)
{
MessageBox(NULL,
TEXT("!!! Could not create an OpenGL 3.2 context.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);

attribs[3] = 1;
g_hRC = wglCreateContextAttribs(g_hDC, 0, attribs);

if (g_hRC == NULL)
{
MessageBox(NULL,
TEXT("!!! Could not create an OpenGL 3.1 context.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);

attribs[3] = 0;
g_hRC = wglCreateContextAttribs(g_hDC, 0, attribs);

if (g_hRC == NULL)
{
MessageBox(NULL,
TEXT("!!! Could not create an OpenGL 3.0 context.\n!!! OpenGL 3.0 and higher are not supported on this system.\n"),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);
}
}
}
}

wglMakeCurrent( g_hDC, g_hRC );
}

if (g_hDC == 0 ||
g_hRC == 0)
{
bRetVal = false;
MessageBox(NULL,
TEXT("!!! An error occured creating an OpenGL window."),
TEXT("ERROR"),
MB_OK|MB_ICONEXCLAMATION);
}

// Setup GLEW which loads OGL function pointers
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
bRetVal = false;
printf("Error: %s\n", glewGetErrorString(err));
}
const GLubyte *oglVersion = glGetString(GL_VERSION);
printf("This system supports OpenGL Version %s.\n", oglVersion);

// If everything went as planned, display the window
if( bRetVal )
{
ShowWindow( g_hWnd, SW_SHOW );
SetForegroundWindow( g_hWnd );
SetFocus( g_hWnd );
g_ContinueRendering = true;
}

return bRetVal;
}


This makes the code a bit cleaner, imo. I've also removed the full screen check just so it's more to the point. Unfortunately this code doesn't work, as all of my other OpenGL calls won't work now! GLEW doesn't return an error in this case, so I'm not sure what could be wrong now... Should I just leave the code as it was in the first place?

I have a bit more understanding about how this is supposed to work, so thanks for the insight so far everybody. Hopefully someone can resolve my last few questions.

It also implies that you shouldn't load function pointers at all until the real rendering context is created.

Is wglChoosePixelFormatARB an exception to this? It is part of the creation of the rendering context itself, after all.
And that actually raises another question in my head: how is wglChoosePixelFormatARB itself dependent on the rendering context being initialized?
[/quote]
Yes, it is a part of context creation, but it is part of an extension, and in order to determine if it's even present, you first need to create that legacy dummy context with plain WinAPI calls.


Any reason why you are not using ChoosePixelFormat? [/quote]
I suppose it's just a tendency on my part to have the most updated material possible to work with. Just personal preference, I suppose. What Brother Bob said at the end of his post.
[/quote]
What Brother Bob said at the end of his post was that he confirmed what I and V-man tried to tell you: that your originally posted code shouldn't work.


And why do you pass a non-initialized variable to SetPixelFormat? [/quote]
Are you referring to the pfd? Isn't SetPixelFormat supposed to initialize that to the data held in the pixel format?
[/quote]
What data? Held where? It is you who should initialize the descriptor to tell Windows that you want driver-provided OpenGL. That's not even funny. It seems you misunderstood all of us and the documentation to boot. See below.


Which are (1) incorrect and (2) can be reduced to about 10. Incorrect because I don't see where you'd set up PIXELFORMATDESCRIPTOR to create dummy context. You may end up with no GL context or 1.1 Microsoft context, and then wonder why glew doesn't work like you'd expect.
Can be reduced because your dummy window doesn't need a style or particular size (1x1 window is enough).[/quote]
Do you mean that I don't even need a pfd for the dummy contexts? Or a window?
[/quote]
No, all's the other way around. You need both dummy context and dummy window. What I meant, and what V-man specifically pointed out, is that in your original snippet (and the current one also), you just declare pfd variable, do not initialize it in any way, do not use ChoosePixelFormat, but simply call SetPixelFormat right away. This is completely and utterly wrong. I'm wondering how it even worked for you before. Either it was a miracle, or your originally posted snippet was incomplete.

The procedure should be like this:
1) Create PIXELFORMATDESCRIPTOR variable
2) Properly initialize it (set cbSize field, buffer sizes, flags (specifically PFD_SUPPORT_OPENGL))
3) Call ChoosePixelFormat to get index of the pixel format that is a closest match to the one you describe in PIXELFORMATDESCRIPTOR variable
4) Call SetPixelFormat
5) Call wglCreateContext.

That's it, your dummy-trow-away-later-context is ready, you can now make it current and proceed with GL initialization as you want.

Both your snippets miss points (2) and (3), which means that best case scenario is that you may get GL 1.1 context as implemented by Microsoft. Which wouldn't have any fancy wglChoosePixelFormat and wglCreateContextAttribs. Worst case - you won't get any context at all. Most terrible case - in release build you may end up with access violation.

Be sure to read carefully through this to clear things up further, specifically the section "Proper context creation".
WBW, capricorn
(Please keep in mind that I'm referring to the code in the OP, not in my latter post which I already know doesn't work)

At the beginning of my code I do only call SetPixelFormat with an uninitialized pfd and so forth because its supposed to be a dummy pixel format. It's only purpose is to help give access to the wgl functions, so that later on I can query for a more sophisticated pixel format with MSAA and other features not supported by the generic wgl implementation.

I had assumed that wglChoosePixelFormatARB used the attributes array ("int attribs[]" in my code) to supersede the pfd. Thus when I called SetPixelFormat, it would supply the pfd with essential information from the attributes and newly found pixel format to supplement for more generic wgl functions that demand a pfd argument. I did some searching though and found that this isn't completely correct, I need to use DescribePixelFormat to apply the pixel format's data to the pfd. For some reason the code seemed to work beforehand on Visual C++ 2010, maybe because the pfd info isn't as critical when using ARB extensions. Maybe because DescribePixelFormat is already called inside the SetPixelFormat function. I honestly don't know. But just to be safe I'm going to put DescribePixelFormat in just for the sake of firm code. Is that the best thing to do?

In terms of the dummy window and contexts, I'm probably just going to leave those in and initialize glew before the pixel format setup like I have, which is probably how it's supposed to work anyway. But advice is still greatly appreciated if there's a more efficient way to go about doing this! I also have a more object-oriented version of this program in the works which might make it a bit cleaner, I'll post it here once I'm done if anybody's interested.

EDIT: I've read the wiki page as suggested, definitely some great stuff in there, it also confirms that it's best to leave my code as it is for the most part. One thing that's a bit vague is where (in "Pixel Format Extensions") it says:

[font="sans-serif"]Once you have a pixel format number, you can set it just like any pixel format with SetPixelFormat.[/font][/quote]
They don't say anything much about the pfd in this case, and it seems to me that the attribs parameter would basically make the pfd redundant, other than for legacy purposes. I suppose that's what DescribePixelFormat is for though.

And sorry if I've offended you at all, capricorn... :S

(Please keep in mind that I'm referring to the code in the OP, not in my latter post which I already know doesn't work)

At the beginning of my code I do only call SetPixelFormat with an uninitialized pfd and so forth because its supposed to be a dummy pixel format. It's only purpose is to help give access to the wgl functions, so that later on I can query for a more sophisticated pixel format with MSAA and other features not supported by the generic wgl implementation.


I think you've overestimated the term 'dummy' here :) It is not supposed to be a dummy pixel format. It is supposed to be a real pixel format suitable for OpenGL context creation. Yes, the context is 'dummy' in the sense that you won't do any rendering with it and you'll throw it away after getting a couple of function pointers (wglChoosePixelFormat and wglCreateContextAttribs), but nevertheless it should be a proper OpenGL context. Trying to create one without setting proper pixel format for DC won't get you far (I already mentioned what you might get).
To set proper pixel format, you need to initialize your pfd struct and feed it to WinAPI's ChoosePixelFormat() function. It will return pixel format index, which you should use in SetPixelFormat() call. Alternatively, you could enumerate all available pixel formats to find suitable index without using ChoosePixelFormat().
In your original snippet you just use index 1, which I suspect just by coincidence happens to be an index for OpenGL-compatible pixel format on your system (the "miracle" I mentioned earlier). You need to substitute this '1' with proper index.
pfd struct won't have any behavioral effects on SetPixelFormat() call. And yes, you may use that same pfd struct later when you call SetPixelFormat() with another index that you get from wglChoosePixelFormatARB(), it won't do any harm. Again, it's pixel format index that matters in the SetPixelFormat() call, not the descriptor.



I had assumed that wglChoosePixelFormatARB used the attributes array ("int attribs[]" in my code) to supersede the pfd.
[/quote]
Precisely so.


Thus when I called SetPixelFormat, it would supply the pfd with essential information from the attributes and newly found pixel format to supplement for more generic wgl functions that demand a pfd argument.
[/quote]
SetPixelFormat() doesn't supply anything. Take a closer look at it's signature, or even better, at it's documentation.


I did some searching though and found that this isn't completely correct, I need to use DescribePixelFormat to apply the pixel format's data to the pfd.
[/quote]
Well, you could do it if only for consistency's sake, but it doesn't really matter. As I explained above, the affecting parameter for SetPixelFormat() is pixel format index, not pfd struct.


In terms of the dummy window and contexts, I'm probably just going to leave those in and initialize glew before the pixel format setup like I have, which is probably how it's supposed to work anyway.
[/quote]
Yep, if you finally get that 'dummy' context creation right.


But advice is still greatly appreciated if there's a more efficient way to go about doing this!
[/quote]
What's inefficient in this approach? It won't hurt your framerate in any way. And as I mentioned earlier, it'd be precisely that kind of code you're unlikely to ever touch again. If you think it's too much lines of code, you can always reformat 'dummy' window creation to one line.


EDIT: I've read the wiki page as suggested, definitely some great stuff in there, it also confirms that it's best to leave my code as it is for the most part. One thing that's a bit vague is where (in "Pixel Format Extensions") it says:

[font="sans-serif"]Once you have a pixel format number, you can set it just like any pixel format with SetPixelFormat.[/font][/quote]
They don't say anything much about the pfd in this case, and it seems to me that the attribs parameter would basically make the pfd redundant, other than for legacy purposes. I suppose that's what DescribePixelFormat is for though.
[/quote]
They don't say anything because it doesn't matter. Though I must say it'd be nice if it was explicitly mentioned :)


And sorry if I've offended you at all, capricorn... :S
[/quote]
Nah, I wasn't offended, I was frustrated. cool.gif
WBW, capricorn

[quote name='AutoBot' timestamp='1311379705' post='4839156']
(Please keep in mind that I'm referring to the code in the OP, not in my latter post which I already know doesn't work)

At the beginning of my code I do only call SetPixelFormat with an uninitialized pfd and so forth because its supposed to be a dummy pixel format. It's only purpose is to help give access to the wgl functions, so that later on I can query for a more sophisticated pixel format with MSAA and other features not supported by the generic wgl implementation.

I think you've overestimated the term 'dummy' here :) It is not supposed to be a dummy pixel format. It is supposed to be a real pixel format suitable for OpenGL context creation. Yes, the context is 'dummy' in the sense that you won't do any rendering with it and you'll throw it away after getting a couple of function pointers (wglChoosePixelFormat and wglCreateContextAttribs), but nevertheless it should be a proper OpenGL context. Trying to create one without setting proper pixel format for DC won't get you far (I already mentioned what you might get).
To set proper pixel format, you need to initialize your pfd struct and feed it to WinAPI's ChoosePixelFormat() function. It will return pixel format index, which you should use in SetPixelFormat() call. Alternatively, you could enumerate all available pixel formats to find suitable index without using ChoosePixelFormat().
In your original snippet you just use index 1, which I suspect just by coincidence happens to be an index for OpenGL-compatible pixel format on your system (the "miracle" I mentioned earlier). You need to substitute this '1' with proper index.
pfd struct won't have any behavioral effects on SetPixelFormat() call. And yes, you may use that same pfd struct later when you call SetPixelFormat() with another index that you get from wglChoosePixelFormatARB(), it won't do any harm. Again, it's pixel format index that matters in the SetPixelFormat() call, not the descriptor.
[/quote]
I would like to extend on this part and explain why it is important to do everything correct, even if it's just a dummy context, and it's from my first reply here where I say that function pointers are context dependent.

Consider what happens if you supply some random pixel format like you do. Windows tries to match your random pixel format with some suitable pixel format that is actually supported. What do you think happens to the rest of your program if that pixel format is only supported by Microsoft's own software implementation? The first thing that happens is that wglChoosePixelFormatARB cannot be loaded, becuase Microsoft's implementation doesn't support it. So if you're not setting a proper pixel format, you may not be able to proceed at all.

This is why it's important to do everything properly, even for the pixel format and the context you're not going to use for the rest of the program, but you are using it for a short time, and it has to be set up properly like any other pixel format or rendering context.
This is the definition of
BOOL SetPixelFormat( HDC hdc, int iPixelFormat, CONST PIXELFORMATDESCRIPTOR * ppfd );

so SetPixelFormat won't modify ppfd. You must set it up and provide it to SetPixelFormat. Also, check MSDN if you want to see how the function works.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);

This topic is closed to new replies.

Advertisement