1 /*
2  * Copyright (C) 2011 Morgan Armand <morgan.devel@gmail.com>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20  */
21 
22 #include <windows.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <glad/glad.h>
26 #include <glad/glad_wgl.h>
27 
28 static LRESULT CALLBACK
WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)29 WndProc(HWND hWnd,
30         UINT uMsg,
31         WPARAM wParam,
32         LPARAM lParam )
33 {
34    switch (uMsg) {
35    case WM_DESTROY:
36       PostQuitMessage(0);
37       break;
38    default:
39       return DefWindowProc(hWnd, uMsg, wParam, lParam);
40    }
41 
42    return 0;
43 }
44 
45 static const char *
context_error_to_string(DWORD error)46 context_error_to_string(DWORD error)
47 {
48    switch (error) {
49    case ERROR_INVALID_VERSION_ARB:  return "ERROR_INVALID_VERSION_ARB";
50    case ERROR_INVALID_PROFILE_ARB:  return "ERROR_INVALID_PROFILE_ARB";
51    case ERROR_INVALID_OPERATION:    return "ERROR_INVALID_OPERATION";
52    case ERROR_DC_NOT_FOUND:         return "ERROR_DC_NOT_FOUND";
53    case ERROR_INVALID_PIXEL_FORMAT: return "ERROR_INVALID_PIXEL_FORMAT";
54    case ERROR_NO_SYSTEM_RESOURCES:  return "ERROR_NO_SYSTEM_RESOURCES";
55    case ERROR_INVALID_PARAMETER:    return "ERROR_INVALID_PARAMETER";
56    default:                         return "Unknown Error";
57    }
58 }
59 
60 static char *
profile_mask_to_string(GLint profileMask)61 profile_mask_to_string(GLint profileMask)
62 {
63    switch (profileMask) {
64    case GL_CONTEXT_CORE_PROFILE_BIT:
65       return "GL_CONTEXT_CORE_PROFILE_BIT";
66    case GL_CONTEXT_COMPATIBILITY_PROFILE_BIT:
67       return "GL_CONTEXT_COMPATIBILITY_PROFILE_BIT";
68    default:
69       return "0";
70    }
71 }
72 
73 static char *
context_flags_to_string(GLint flags)74 context_flags_to_string(GLint flags)
75 {
76    static char buf[1000] = {0};
77    if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
78       strcat(buf, "GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT | ");
79    if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
80       strcat(buf, "GL_CONTEXT_FLAG_DEBUG_BIT | ");
81    if (flags & GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT)
82       strcat(buf, "GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT | ");
83    if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR)
84       strcat(buf, "GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR | ");
85 
86    int n = strlen(buf);
87    if (n >= 3) {
88       /* rm the trailing " | " */
89       buf[n-3] = 0;
90    }
91    else {
92       strcat(buf, "(none)");
93    }
94 
95    return buf;
96 }
97 
98 static void
print_context_infos(void)99 print_context_infos(void)
100 {
101    GLint majorVersion;
102    GLint minorVersion;
103    GLint profileMask, flags;
104    const char *version, *vendor, *renderer;
105 
106    fprintf(stdout, "Context Informations\n");
107 
108    version = (const char *)glGetString(GL_VERSION);
109    fprintf(stdout, "GL_VERSION: %s\n", version);
110 
111    vendor = (const char *)glGetString(GL_VENDOR);
112    fprintf(stdout, "GL_VENDOR: %s\n", vendor);
113 
114    renderer = (const char *)glGetString(GL_RENDERER);
115    fprintf(stdout, "GL_RENDERER: %s\n", renderer);
116 
117    // Request informations with the new 3.x features.
118    if (sscanf(version, "%d.%d", &majorVersion, &minorVersion) != 2)
119       return;
120 
121    if (majorVersion >= 3) {
122       glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
123       glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
124       fprintf(stdout, "GL_MAJOR_VERSION: %d\n", majorVersion);
125       fprintf(stdout, "GL_MINOR_VERSION: %d\n", minorVersion);
126    }
127    if (majorVersion * 10 + minorVersion >= 32) {
128       glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profileMask);
129       glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
130       fprintf(stdout, "GL_CONTEXT_PROFILE_MASK: %s\n",
131               profile_mask_to_string(profileMask));
132       fprintf(stdout, "GL_CONTEXT_FLAGS: %s\n",
133               context_flags_to_string(flags));
134    }
135 
136    /* Test if deprecated features work or generate an error */
137    while (glGetError() != GL_NO_ERROR)
138       ;
139 
140    (void) glGenLists(1);
141    if (glGetError()) {
142       fprintf(stdout, "glGenLists generated an error.\n");
143    }
144    else {
145       fprintf(stdout, "glGenLists generated no error.\n");
146    }
147 }
148 
149 static void
create_context(int majorVersion,int minorVersion,int profileMask,int contextFlags)150 create_context(int majorVersion, int minorVersion, int profileMask, int contextFlags)
151 {
152    WNDCLASS wc;
153    HWND win;
154    HDC hdc;
155    PIXELFORMATDESCRIPTOR pfd;
156    int pixelFormat;
157    HGLRC tmp, ctx;
158 
159    memset(&wc, 0, sizeof(wc));
160    wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
161    wc.lpfnWndProc = WndProc;
162    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
163    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
164    wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
165    wc.lpszClassName = "wglcontext";
166 
167    if (!RegisterClass(&wc)) {
168       fprintf(stderr, "RegisterClass() failed\n");
169       return;
170    }
171 
172    win = CreateWindowEx(0,
173                      wc.lpszClassName,
174                      "wglinfo",
175                      WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
176                      CW_USEDEFAULT,
177                      CW_USEDEFAULT,
178                      CW_USEDEFAULT,
179                      CW_USEDEFAULT,
180                      NULL,
181                      NULL,
182                      wc.hInstance,
183                      NULL);
184    if (!win) {
185       fprintf(stderr, "CreateWindowEx() failed\n");
186       return;
187    }
188 
189    hdc = GetDC(win);
190    if (!hdc) {
191       fprintf(stderr, "GetDC() failed\n");
192       return;
193    }
194 
195    memset(&pfd, 0, sizeof(pfd));
196    pfd.nSize = sizeof(pfd);
197    pfd.nVersion = 1;
198    pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
199    pfd.iPixelType = PFD_TYPE_RGBA;
200    pfd.cColorBits = 24;
201    pfd.cDepthBits = 24;
202    pfd.iLayerType = PFD_MAIN_PLANE;
203 
204    pixelFormat = ChoosePixelFormat(hdc, &pfd);
205    if (!pixelFormat) {
206       fprintf(stderr, "ChoosePixelFormat() failed\n");
207       return;
208    }
209 
210    if (!SetPixelFormat(hdc, pixelFormat, &pfd)) {
211       fprintf(stderr, "SetPixelFormat() failed\n");
212       return;
213    }
214 
215    tmp = wglCreateContext(hdc);
216    if (!tmp) {
217       fprintf(stderr, "wglCreateContext() failed\n");
218       return;
219    }
220 
221    if (!wglMakeCurrent(hdc, tmp)) {
222       fprintf(stderr, "wglMakeCurrent() failed\n");
223       return;
224    }
225 
226    gladLoadGL();
227    gladLoadWGL(hdc);
228 
229    if (!GLAD_WGL_ARB_create_context) {
230       fprintf(stderr, "wglCreateContextAttribsARB isn't supported\n");
231       return;
232    }
233 
234    int attribsList[20];
235    int i = 0;
236    attribsList[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
237    attribsList[i++] = majorVersion;
238    attribsList[i++] = WGL_CONTEXT_MINOR_VERSION_ARB;
239    attribsList[i++] = minorVersion;
240    if (contextFlags) {
241       attribsList[i++] = WGL_CONTEXT_FLAGS_ARB;
242       attribsList[i++] = contextFlags;
243    }
244    if (profileMask) {
245       attribsList[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
246       attribsList[i++] = profileMask;
247    }
248    attribsList[i++] = 0;
249 
250    ctx = wglCreateContextAttribsARB(hdc, 0, attribsList);
251    if (!ctx) {
252       DWORD error = GetLastError();
253       fprintf(stderr, "wglCreateContextAttribsARB failed(): %s (0x%lx)\n",
254               context_error_to_string(error), error);
255       return;
256    }
257 
258    wglMakeCurrent(NULL, NULL);
259    wglDeleteContext(tmp);
260 
261    if (!wglMakeCurrent(hdc, ctx)) {
262       fprintf(stderr, "wglMakeCurrent() failed\n");
263       return;
264    }
265 
266    print_context_infos();
267 }
268 
269 static void
usage(void)270 usage(void)
271 {
272    fprintf(stdout, "Usage: wglcontext [-h] [-major <major>] [-minor <minor>] [-core] [-compat] [-debug] [-forward]\n");
273    fprintf(stdout, "   -major   : specify the major version you want\n");
274    fprintf(stdout, "   -minor   : specify the minor version you want\n");
275    fprintf(stdout, "   -core    : request a context implementing the core profile\n");
276    fprintf(stdout, "   -compat  : request a context implementing the compatibility profile\n");
277    fprintf(stdout, "   -debug   : request a debug context\n");
278    fprintf(stdout, "   -forward : request a forward-compatible context\n");
279 }
280 
281 int
main(int argc,char * argv[])282 main(int argc, char *argv[])
283 {
284    int i;
285    int majorVersion = 1, minorVersion = 0;
286    int contextFlags = 0x0;
287    int profileMask = 0x0;
288 
289    for (i = 1; i < argc; i++) {
290       if (strcmp(argv[i], "-h") == 0) {
291          usage();
292          exit(0);
293       }
294       else if (strcmp(argv[i], "-major") == 0 && i + 1 < argc) {
295          majorVersion = (int)strtol(argv[i + 1], (char **)NULL, 10);
296          i++;
297       }
298       else if (strcmp(argv[i], "-minor") == 0 && i + 1 < argc) {
299          minorVersion = (int)strtol(argv[i + 1], (char **)NULL, 10);
300          i++;
301       }
302       else if (strcmp(argv[i], "-core") == 0) {
303          profileMask = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
304       }
305       else if (strcmp(argv[i], "-compat") == 0) {
306          profileMask = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
307       }
308       else if (strcmp(argv[i], "-debug") == 0) {
309          contextFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
310       }
311       else if (strcmp(argv[i], "-forward") == 0) {
312          contextFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
313       }
314       else {
315          usage();
316          exit(1);
317       }
318    }
319 
320    create_context(majorVersion, minorVersion,
321                   profileMask, contextFlags);
322 
323    return 0;
324 }
325