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