comparison src/video/windows/SDL_windowsopengl.c @ 5062:e8916fe9cfc8

Fixed bug #925 Changed "win32" to "windows"
author Sam Lantinga <slouken@libsdl.org>
date Thu, 20 Jan 2011 18:04:05 -0800
parents src/video/win32/SDL_win32opengl.c@f7b03b6838cb
children 327f181542f1
comparison
equal deleted inserted replaced
5061:9e9940eae455 5062:e8916fe9cfc8
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2010 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 #include "SDL_windowsvideo.h"
25
26 /* WGL implementation of SDL OpenGL support */
27
28 #if SDL_VIDEO_OPENGL_WGL
29 #include "SDL_opengl.h"
30
31 #define DEFAULT_OPENGL "OPENGL32.DLL"
32
33 #ifndef WGL_ARB_create_context
34 #define WGL_ARB_create_context
35 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
36 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
37 #define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
38 #define WGL_CONTEXT_FLAGS_ARB 0x2093
39 #define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
40 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
41 #endif
42
43 typedef HGLRC(APIENTRYP PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC,
44 HGLRC
45 hShareContext,
46 const int
47 *attribList);
48
49 int
50 WIN_GL_LoadLibrary(_THIS, const char *path)
51 {
52 LPTSTR wpath;
53 HANDLE handle;
54
55 if (path == NULL) {
56 path = SDL_getenv("SDL_OPENGL_LIBRARY");
57 }
58 if (path == NULL) {
59 path = DEFAULT_OPENGL;
60 }
61 wpath = WIN_UTF8ToString(path);
62 _this->gl_config.dll_handle = LoadLibrary(wpath);
63 SDL_free(wpath);
64 if (!_this->gl_config.dll_handle) {
65 char message[1024];
66 SDL_snprintf(message, SDL_arraysize(message), "LoadLibrary(\"%s\")",
67 path);
68 WIN_SetError(message);
69 return -1;
70 }
71 SDL_strlcpy(_this->gl_config.driver_path, path,
72 SDL_arraysize(_this->gl_config.driver_path));
73
74 /* Allocate OpenGL memory */
75 _this->gl_data =
76 (struct SDL_GLDriverData *) SDL_calloc(1,
77 sizeof(struct
78 SDL_GLDriverData));
79 if (!_this->gl_data) {
80 SDL_OutOfMemory();
81 return -1;
82 }
83
84 /* Load function pointers */
85 handle = _this->gl_config.dll_handle;
86 _this->gl_data->wglGetProcAddress = (void *(WINAPI *) (const char *))
87 GetProcAddress(handle, "wglGetProcAddress");
88 _this->gl_data->wglCreateContext = (HGLRC(WINAPI *) (HDC))
89 GetProcAddress(handle, "wglCreateContext");
90 _this->gl_data->wglDeleteContext = (BOOL(WINAPI *) (HGLRC))
91 GetProcAddress(handle, "wglDeleteContext");
92 _this->gl_data->wglMakeCurrent = (BOOL(WINAPI *) (HDC, HGLRC))
93 GetProcAddress(handle, "wglMakeCurrent");
94 _this->gl_data->wglSwapIntervalEXT = (void (WINAPI *) (int))
95 GetProcAddress(handle, "wglSwapIntervalEXT");
96 _this->gl_data->wglGetSwapIntervalEXT = (int (WINAPI *) (void))
97 GetProcAddress(handle, "wglGetSwapIntervalEXT");
98
99 if (!_this->gl_data->wglGetProcAddress ||
100 !_this->gl_data->wglCreateContext ||
101 !_this->gl_data->wglDeleteContext ||
102 !_this->gl_data->wglMakeCurrent) {
103 SDL_SetError("Could not retrieve OpenGL functions");
104 FreeLibrary(handle);
105 return -1;
106 }
107
108 return 0;
109 }
110
111 void *
112 WIN_GL_GetProcAddress(_THIS, const char *proc)
113 {
114 void *func;
115
116 /* This is to pick up extensions */
117 func = _this->gl_data->wglGetProcAddress(proc);
118 if (!func) {
119 /* This is probably a normal GL function */
120 func = GetProcAddress(_this->gl_config.dll_handle, proc);
121 }
122 return func;
123 }
124
125 void
126 WIN_GL_UnloadLibrary(_THIS)
127 {
128 FreeLibrary((HMODULE) _this->gl_config.dll_handle);
129 _this->gl_config.dll_handle = NULL;
130
131 /* Free OpenGL memory */
132 SDL_free(_this->gl_data);
133 _this->gl_data = NULL;
134 }
135
136 static void
137 WIN_GL_SetupPixelFormat(_THIS, PIXELFORMATDESCRIPTOR * pfd)
138 {
139 SDL_zerop(pfd);
140 pfd->nSize = sizeof(*pfd);
141 pfd->nVersion = 1;
142 pfd->dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
143 if (_this->gl_config.double_buffer) {
144 pfd->dwFlags |= PFD_DOUBLEBUFFER;
145 }
146 if (_this->gl_config.stereo) {
147 pfd->dwFlags |= PFD_STEREO;
148 }
149 pfd->iLayerType = PFD_MAIN_PLANE;
150 pfd->iPixelType = PFD_TYPE_RGBA;
151 pfd->cRedBits = _this->gl_config.red_size;
152 pfd->cGreenBits = _this->gl_config.green_size;
153 pfd->cBlueBits = _this->gl_config.blue_size;
154 pfd->cAlphaBits = _this->gl_config.alpha_size;
155 if (_this->gl_config.buffer_size) {
156 pfd->cColorBits =
157 _this->gl_config.buffer_size - _this->gl_config.alpha_size;
158 } else {
159 pfd->cColorBits = (pfd->cRedBits + pfd->cGreenBits + pfd->cBlueBits);
160 }
161 pfd->cAccumRedBits = _this->gl_config.accum_red_size;
162 pfd->cAccumGreenBits = _this->gl_config.accum_green_size;
163 pfd->cAccumBlueBits = _this->gl_config.accum_blue_size;
164 pfd->cAccumAlphaBits = _this->gl_config.accum_alpha_size;
165 pfd->cAccumBits =
166 (pfd->cAccumRedBits + pfd->cAccumGreenBits + pfd->cAccumBlueBits +
167 pfd->cAccumAlphaBits);
168 pfd->cDepthBits = _this->gl_config.depth_size;
169 pfd->cStencilBits = _this->gl_config.stencil_size;
170 }
171
172 /* Choose the closest pixel format that meets or exceeds the target.
173 FIXME: Should we weight any particular attribute over any other?
174 */
175 static int
176 WIN_GL_ChoosePixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR * target)
177 {
178 PIXELFORMATDESCRIPTOR pfd;
179 int count, index, best = 0;
180 unsigned int dist, best_dist = ~0U;
181
182 count = DescribePixelFormat(hdc, 1, sizeof(pfd), NULL);
183
184 for (index = 1; index <= count; index++) {
185
186 if (!DescribePixelFormat(hdc, index, sizeof(pfd), &pfd)) {
187 continue;
188 }
189
190 if ((pfd.dwFlags & target->dwFlags) != target->dwFlags) {
191 continue;
192 }
193
194 if (pfd.iLayerType != target->iLayerType) {
195 continue;
196 }
197 if (pfd.iPixelType != target->iPixelType) {
198 continue;
199 }
200
201 dist = 0;
202
203 if (pfd.cColorBits < target->cColorBits) {
204 continue;
205 } else {
206 dist += (pfd.cColorBits - target->cColorBits);
207 }
208 if (pfd.cRedBits < target->cRedBits) {
209 continue;
210 } else {
211 dist += (pfd.cRedBits - target->cRedBits);
212 }
213 if (pfd.cGreenBits < target->cGreenBits) {
214 continue;
215 } else {
216 dist += (pfd.cGreenBits - target->cGreenBits);
217 }
218 if (pfd.cBlueBits < target->cBlueBits) {
219 continue;
220 } else {
221 dist += (pfd.cBlueBits - target->cBlueBits);
222 }
223 if (pfd.cAlphaBits < target->cAlphaBits) {
224 continue;
225 } else {
226 dist += (pfd.cAlphaBits - target->cAlphaBits);
227 }
228 if (pfd.cAccumBits < target->cAccumBits) {
229 continue;
230 } else {
231 dist += (pfd.cAccumBits - target->cAccumBits);
232 }
233 if (pfd.cAccumRedBits < target->cAccumRedBits) {
234 continue;
235 } else {
236 dist += (pfd.cAccumRedBits - target->cAccumRedBits);
237 }
238 if (pfd.cAccumGreenBits < target->cAccumGreenBits) {
239 continue;
240 } else {
241 dist += (pfd.cAccumGreenBits - target->cAccumGreenBits);
242 }
243 if (pfd.cAccumBlueBits < target->cAccumBlueBits) {
244 continue;
245 } else {
246 dist += (pfd.cAccumBlueBits - target->cAccumBlueBits);
247 }
248 if (pfd.cAccumAlphaBits < target->cAccumAlphaBits) {
249 continue;
250 } else {
251 dist += (pfd.cAccumAlphaBits - target->cAccumAlphaBits);
252 }
253 if (pfd.cDepthBits < target->cDepthBits) {
254 continue;
255 } else {
256 dist += (pfd.cDepthBits - target->cDepthBits);
257 }
258 if (pfd.cStencilBits < target->cStencilBits) {
259 continue;
260 } else {
261 dist += (pfd.cStencilBits - target->cStencilBits);
262 }
263
264 if (dist < best_dist) {
265 best = index;
266 best_dist = dist;
267 }
268 }
269
270 return best;
271 }
272
273 static SDL_bool
274 HasExtension(const char *extension, const char *extensions)
275 {
276 const char *start;
277 const char *where, *terminator;
278
279 /* Extension names should not have spaces. */
280 where = SDL_strchr(extension, ' ');
281 if (where || *extension == '\0')
282 return SDL_FALSE;
283
284 if (!extensions)
285 return SDL_FALSE;
286
287 /* It takes a bit of care to be fool-proof about parsing the
288 * OpenGL extensions string. Don't be fooled by sub-strings,
289 * etc. */
290
291 start = extensions;
292
293 for (;;) {
294 where = SDL_strstr(start, extension);
295 if (!where)
296 break;
297
298 terminator = where + SDL_strlen(extension);
299 if (where == start || *(where - 1) == ' ')
300 if (*terminator == ' ' || *terminator == '\0')
301 return SDL_TRUE;
302
303 start = terminator;
304 }
305 return SDL_FALSE;
306 }
307
308 static void
309 WIN_GL_InitExtensions(_THIS, HDC hdc)
310 {
311 const char *(WINAPI * wglGetExtensionsStringARB) (HDC) = 0;
312 const char *extensions;
313
314 wglGetExtensionsStringARB = (const char *(WINAPI *) (HDC))
315 _this->gl_data->wglGetProcAddress("wglGetExtensionsStringARB");
316 if (wglGetExtensionsStringARB) {
317 extensions = wglGetExtensionsStringARB(hdc);
318 } else {
319 extensions = NULL;
320 }
321
322 /* Check for WGL_ARB_pixel_format */
323 _this->gl_data->WGL_ARB_pixel_format = 0;
324 if (HasExtension("WGL_ARB_pixel_format", extensions)) {
325 _this->gl_data->wglChoosePixelFormatARB = (BOOL(WINAPI *)
326 (HDC, const int *,
327 const FLOAT *, UINT,
328 int *, UINT *))
329 WIN_GL_GetProcAddress(_this, "wglChoosePixelFormatARB");
330 _this->gl_data->wglGetPixelFormatAttribivARB =
331 (BOOL(WINAPI *) (HDC, int, int, UINT, const int *, int *))
332 WIN_GL_GetProcAddress(_this, "wglGetPixelFormatAttribivARB");
333
334 if ((_this->gl_data->wglChoosePixelFormatARB != NULL) &&
335 (_this->gl_data->wglGetPixelFormatAttribivARB != NULL)) {
336 _this->gl_data->WGL_ARB_pixel_format = 1;
337 }
338 }
339
340 /* Check for WGL_EXT_swap_control */
341 if (HasExtension("WGL_EXT_swap_control", extensions)) {
342 _this->gl_data->wglSwapIntervalEXT =
343 WIN_GL_GetProcAddress(_this, "wglSwapIntervalEXT");
344 _this->gl_data->wglGetSwapIntervalEXT =
345 WIN_GL_GetProcAddress(_this, "wglGetSwapIntervalEXT");
346 } else {
347 _this->gl_data->wglSwapIntervalEXT = NULL;
348 _this->gl_data->wglGetSwapIntervalEXT = NULL;
349 }
350 }
351
352 static int
353 WIN_GL_ChoosePixelFormatARB(_THIS, int *iAttribs, float *fAttribs)
354 {
355 HWND hwnd;
356 HDC hdc;
357 PIXELFORMATDESCRIPTOR pfd;
358 HGLRC hglrc;
359 int pixel_format = 0;
360 unsigned int matching;
361
362 hwnd =
363 CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0,
364 10, 10, NULL, NULL, SDL_Instance, NULL);
365 WIN_PumpEvents(_this);
366
367 hdc = GetDC(hwnd);
368
369 WIN_GL_SetupPixelFormat(_this, &pfd);
370
371 SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
372
373 hglrc = _this->gl_data->wglCreateContext(hdc);
374 if (hglrc) {
375 _this->gl_data->wglMakeCurrent(hdc, hglrc);
376
377 WIN_GL_InitExtensions(_this, hdc);
378
379 if (_this->gl_data->WGL_ARB_pixel_format) {
380 _this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs,
381 1, &pixel_format,
382 &matching);
383 }
384
385 _this->gl_data->wglMakeCurrent(NULL, NULL);
386 _this->gl_data->wglDeleteContext(hglrc);
387 }
388 ReleaseDC(hwnd, hdc);
389 DestroyWindow(hwnd);
390 WIN_PumpEvents(_this);
391
392 return pixel_format;
393 }
394
395 int
396 WIN_GL_SetupWindow(_THIS, SDL_Window * window)
397 {
398 HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
399 PIXELFORMATDESCRIPTOR pfd;
400 int pixel_format;
401 int iAttribs[64];
402 int *iAttr;
403 float fAttribs[1] = { 0 };
404
405 WIN_GL_SetupPixelFormat(_this, &pfd);
406
407 /* setup WGL_ARB_pixel_format attribs */
408 iAttr = &iAttribs[0];
409
410 *iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
411 *iAttr++ = GL_TRUE;
412 *iAttr++ = WGL_ACCELERATION_ARB;
413 *iAttr++ = WGL_FULL_ACCELERATION_ARB;
414 *iAttr++ = WGL_RED_BITS_ARB;
415 *iAttr++ = _this->gl_config.red_size;
416 *iAttr++ = WGL_GREEN_BITS_ARB;
417 *iAttr++ = _this->gl_config.green_size;
418 *iAttr++ = WGL_BLUE_BITS_ARB;
419 *iAttr++ = _this->gl_config.blue_size;
420
421 if (_this->gl_config.alpha_size) {
422 *iAttr++ = WGL_ALPHA_BITS_ARB;
423 *iAttr++ = _this->gl_config.alpha_size;
424 }
425
426 *iAttr++ = WGL_DOUBLE_BUFFER_ARB;
427 *iAttr++ = _this->gl_config.double_buffer;
428
429 *iAttr++ = WGL_DEPTH_BITS_ARB;
430 *iAttr++ = _this->gl_config.depth_size;
431
432 if (_this->gl_config.stencil_size) {
433 *iAttr++ = WGL_STENCIL_BITS_ARB;
434 *iAttr++ = _this->gl_config.stencil_size;
435 }
436
437 if (_this->gl_config.accum_red_size) {
438 *iAttr++ = WGL_ACCUM_RED_BITS_ARB;
439 *iAttr++ = _this->gl_config.accum_red_size;
440 }
441
442 if (_this->gl_config.accum_green_size) {
443 *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
444 *iAttr++ = _this->gl_config.accum_green_size;
445 }
446
447 if (_this->gl_config.accum_blue_size) {
448 *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
449 *iAttr++ = _this->gl_config.accum_blue_size;
450 }
451
452 if (_this->gl_config.accum_alpha_size) {
453 *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
454 *iAttr++ = _this->gl_config.accum_alpha_size;
455 }
456
457 if (_this->gl_config.stereo) {
458 *iAttr++ = WGL_STEREO_ARB;
459 *iAttr++ = GL_TRUE;
460 }
461
462 if (_this->gl_config.multisamplebuffers) {
463 *iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
464 *iAttr++ = _this->gl_config.multisamplebuffers;
465 }
466
467 if (_this->gl_config.multisamplesamples) {
468 *iAttr++ = WGL_SAMPLES_ARB;
469 *iAttr++ = _this->gl_config.multisamplesamples;
470 }
471
472 if (_this->gl_config.accelerated >= 0) {
473 *iAttr++ = WGL_ACCELERATION_ARB;
474 *iAttr++ =
475 (_this->gl_config.accelerated ? WGL_GENERIC_ACCELERATION_ARB :
476 WGL_NO_ACCELERATION_ARB);
477 }
478
479 *iAttr = 0;
480
481 /* Choose and set the closest available pixel format */
482 pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
483 if (!pixel_format) {
484 pixel_format = WIN_GL_ChoosePixelFormat(hdc, &pfd);
485 }
486 if (!pixel_format) {
487 SDL_SetError("No matching GL pixel format available");
488 return -1;
489 }
490 if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
491 WIN_SetError("SetPixelFormat()");
492 return (-1);
493 }
494 return 0;
495 }
496
497 SDL_GLContext
498 WIN_GL_CreateContext(_THIS, SDL_Window * window)
499 {
500 HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
501 HGLRC context;
502
503 if (_this->gl_config.major_version < 3) {
504 context = _this->gl_data->wglCreateContext(hdc);
505 } else {
506 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
507 HGLRC temp_context = _this->gl_data->wglCreateContext(hdc);
508 if (!temp_context) {
509 SDL_SetError("Could not create GL context");
510 return NULL;
511 }
512
513 /* Make the context current */
514 if (WIN_GL_MakeCurrent(_this, window, temp_context) < 0) {
515 WIN_GL_DeleteContext(_this, temp_context);
516 return NULL;
517 }
518
519 wglCreateContextAttribsARB =
520 (PFNWGLCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
521 wglGetProcAddress("wglCreateContextAttribsARB");
522 if (!wglCreateContextAttribsARB) {
523 SDL_SetError("GL 3.x is not supported");
524 context = temp_context;
525 } else {
526 int attribs[] = {
527 WGL_CONTEXT_MAJOR_VERSION_ARB, _this->gl_config.major_version,
528 WGL_CONTEXT_MINOR_VERSION_ARB, _this->gl_config.minor_version,
529 0
530 };
531 /* Create the GL 3.x context */
532 context = wglCreateContextAttribsARB(hdc, 0, attribs);
533 /* Delete the GL 2.x context */
534 _this->gl_data->wglDeleteContext(temp_context);
535 }
536 }
537
538 if (!context) {
539 WIN_SetError("Could not create GL context");
540 return NULL;
541 }
542
543 if (WIN_GL_MakeCurrent(_this, window, context) < 0) {
544 WIN_GL_DeleteContext(_this, context);
545 return NULL;
546 }
547
548 WIN_GL_InitExtensions(_this, hdc);
549
550 return context;
551 }
552
553 int
554 WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
555 {
556 HDC hdc;
557 int status;
558
559 if (window) {
560 hdc = ((SDL_WindowData *) window->driverdata)->hdc;
561 } else {
562 hdc = NULL;
563 }
564 if (!_this->gl_data->wglMakeCurrent(hdc, (HGLRC) context)) {
565 WIN_SetError("wglMakeCurrent()");
566 status = -1;
567 } else {
568 status = 0;
569 }
570 return status;
571 }
572
573 int
574 WIN_GL_SetSwapInterval(_THIS, int interval)
575 {
576 if (_this->gl_data->wglSwapIntervalEXT) {
577 _this->gl_data->wglSwapIntervalEXT(interval);
578 return 0;
579 } else {
580 SDL_Unsupported();
581 return -1;
582 }
583 }
584
585 int
586 WIN_GL_GetSwapInterval(_THIS)
587 {
588 if (_this->gl_data->wglGetSwapIntervalEXT) {
589 return _this->gl_data->wglGetSwapIntervalEXT();
590 } else {
591 SDL_Unsupported();
592 return -1;
593 }
594 }
595
596 void
597 WIN_GL_SwapWindow(_THIS, SDL_Window * window)
598 {
599 HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
600
601 SwapBuffers(hdc);
602 }
603
604 void
605 WIN_GL_DeleteContext(_THIS, SDL_GLContext context)
606 {
607 _this->gl_data->wglDeleteContext((HGLRC) context);
608 }
609
610 #endif /* SDL_VIDEO_OPENGL_WGL */
611
612 /* vi: set ts=4 sw=4 expandtab: */