1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Windows OpenGL display driver
12 *
13 * By Milan Mimica.
14 * Based on AllegroGL Windows display driver.
15 *
16 */
17
18 #if 0
19 /* Raw input */
20 #define _WIN32_WINNT 0x0501
21 #ifndef WINVER
22 #define WINVER 0x0501
23 #endif
24 #endif
25
26 #include <windows.h>
27
28 #include "allegro5/allegro.h"
29 #include "allegro5/allegro_opengl.h"
30 #include "allegro5/system.h"
31 #include "allegro5/internal/aintern.h"
32 #include "allegro5/internal/aintern_bitmap.h"
33 #include "allegro5/internal/aintern_opengl.h"
34 #include "allegro5/internal/aintern_vector.h"
35 #include "allegro5/internal/aintern_wclipboard.h"
36 #include "allegro5/platform/aintwin.h"
37 #include "allegro5/internal/aintern_wunicode.h"
38
39 #include "wgl.h"
40
41 #include <process.h>
42
43 ALLEGRO_DEBUG_CHANNEL("display")
44
45 static ALLEGRO_DISPLAY_INTERFACE vt;
46
47 /* Forward declarations: */
48 static void display_thread_proc(void *arg);
49 static void destroy_display_internals(ALLEGRO_DISPLAY_WGL *wgl_disp);
50 static bool wgl_acknowledge_resize(ALLEGRO_DISPLAY *d);
51
52 /* Prevents switching to desktop resolution when destroying the display. Used
53 on full screen resize. */
54 static bool _wgl_do_not_change_display_mode = false;
55
56 /*
57 * These parameters cannot be gotten by the display thread because
58 * they're thread local. We get them in the calling thread first.
59 */
60 typedef struct WGL_DISPLAY_PARAMETERS {
61 ALLEGRO_DISPLAY_WGL *display;
62 volatile bool init_failed;
63 HANDLE AckEvent;
64 int window_x, window_y;
65 /* Not owned. */
66 const char* window_title;
67 } WGL_DISPLAY_PARAMETERS;
68
is_wgl_extension_supported(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB,const char * extension,HDC dc)69 static bool is_wgl_extension_supported(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB, const char *extension, HDC dc)
70 {
71 int ret;
72
73 /* XXX deprecated in OpenGL 3.0 */
74 if (!glGetString(GL_EXTENSIONS))
75 return false;
76 if (!_wglGetExtensionsStringARB)
77 return false;
78
79 ret = _al_ogl_look_for_an_extension(extension,
80 (const GLubyte*)_wglGetExtensionsStringARB(dc));
81
82 return ret;
83 }
84
85
init_temp_context(HWND wnd)86 static HGLRC init_temp_context(HWND wnd)
87 {
88 PIXELFORMATDESCRIPTOR pfd;
89 int pf;
90 HDC dc;
91 HGLRC glrc;
92
93 dc = GetDC(wnd);
94
95 memset(&pfd, 0, sizeof(pfd));
96 pfd.nSize = sizeof(pfd);
97 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL
98 | PFD_DOUBLEBUFFER_DONTCARE | PFD_STEREO_DONTCARE;
99 pfd.iPixelType = PFD_TYPE_RGBA;
100 pfd.iLayerType = PFD_MAIN_PLANE;
101 pfd.cColorBits = 32;
102
103 pf = ChoosePixelFormat(dc, &pfd);
104 if (!pf) {
105 ALLEGRO_ERROR("Unable to chose a temporary pixel format. %s\n",
106 _al_win_last_error());
107 return NULL;
108 }
109
110 memset(&pfd, 0, sizeof(pfd));
111 if (!SetPixelFormat(dc, pf, &pfd)) {
112 ALLEGRO_ERROR("Unable to set a temporary pixel format. %s\n",
113 _al_win_last_error());
114 return NULL;
115 }
116
117 glrc = wglCreateContext(dc);
118 if (!glrc) {
119 ALLEGRO_ERROR("Unable to create a render context. %s\n",
120 _al_win_last_error());
121 return NULL;
122 }
123
124 if (!wglMakeCurrent(dc, glrc)) {
125 ALLEGRO_ERROR("Unable to set the render context as current. %s\n",
126 _al_win_last_error());
127 wglDeleteContext(glrc);
128 return NULL;
129 }
130
131 return glrc;
132 }
133
134
135 static _ALLEGRO_wglGetPixelFormatAttribivARB_t _wglGetPixelFormatAttribivARB = NULL;
136 static _ALLEGRO_wglGetPixelFormatAttribivEXT_t _wglGetPixelFormatAttribivEXT = NULL;
137
init_pixel_format_extensions(void)138 static bool init_pixel_format_extensions(void)
139 {
140 /* Load the ARB_p_f symbol - Note, we shouldn't use the extension
141 * mechanism here, because it hasn't been initialized yet!
142 */
143 _wglGetPixelFormatAttribivARB =
144 (_ALLEGRO_wglGetPixelFormatAttribivARB_t)wglGetProcAddress("wglGetPixelFormatAttribivARB");
145 _wglGetPixelFormatAttribivEXT =
146 (_ALLEGRO_wglGetPixelFormatAttribivEXT_t)wglGetProcAddress("wglGetPixelFormatAttribivEXT");
147
148 if (!_wglGetPixelFormatAttribivARB && !_wglGetPixelFormatAttribivEXT) {
149 ALLEGRO_ERROR("WGL_ARB/EXT_pf not supported.\n");
150 return false;
151 }
152
153 return true;
154 }
155
156
157 static _ALLEGRO_wglCreateContextAttribsARB_t _wglCreateContextAttribsARB = NULL;
158
init_context_creation_extensions(void)159 static bool init_context_creation_extensions(void)
160 {
161 _wglCreateContextAttribsARB =
162 (_ALLEGRO_wglCreateContextAttribsARB_t)wglGetProcAddress("wglCreateContextAttribsARB");
163
164 if (!_wglCreateContextAttribsARB) {
165 ALLEGRO_ERROR("wglCreateContextAttribs not supported!\n");
166 return false;
167 }
168
169 return true;
170 }
171
172
get_pixel_formats_count_old(HDC dc)173 static int get_pixel_formats_count_old(HDC dc)
174 {
175 PIXELFORMATDESCRIPTOR pfd;
176 int ret;
177
178 ret = DescribePixelFormat(dc, 1, sizeof(pfd), &pfd);
179 if (!ret) {
180 ALLEGRO_ERROR("DescribePixelFormat failed! %s\n",
181 _al_win_last_error());
182 }
183
184 return ret;
185 }
186
187
get_pixel_formats_count_ext(HDC dc)188 static int get_pixel_formats_count_ext(HDC dc)
189 {
190 int attrib[1];
191 int value[1];
192
193 attrib[0] = WGL_NUMBER_PIXEL_FORMATS_ARB;
194 if ((_wglGetPixelFormatAttribivARB(dc, 0, 0, 1, attrib, value) == GL_FALSE)
195 && (_wglGetPixelFormatAttribivEXT(dc, 0, 0, 1, attrib, value) == GL_FALSE)) {
196 ALLEGRO_ERROR("WGL_ARB/EXT_pixel_format use failed! %s\n",
197 _al_win_last_error());
198 }
199
200 return value[0];
201 }
202
203
display_pixel_format(ALLEGRO_EXTRA_DISPLAY_SETTINGS * eds)204 static void display_pixel_format(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds)
205 {
206 ALLEGRO_INFO("Accelerated: %s\n", eds->settings[ALLEGRO_RENDER_METHOD] ? "yes" : "no");
207 ALLEGRO_INFO("Single-buffer: %s\n", eds->settings[ALLEGRO_SINGLE_BUFFER] ? "yes" : "no");
208 if (eds->settings[ALLEGRO_SWAP_METHOD] > 0)
209 ALLEGRO_INFO("Swap method: %s\n", eds->settings[ALLEGRO_SWAP_METHOD] == 2 ? "flip" : "copy");
210 else
211 ALLEGRO_INFO("Swap method: undefined\n");
212 ALLEGRO_INFO("Color format: r%i g%i b%i a%i, %i bit\n",
213 eds->settings[ALLEGRO_RED_SIZE],
214 eds->settings[ALLEGRO_GREEN_SIZE],
215 eds->settings[ALLEGRO_BLUE_SIZE],
216 eds->settings[ALLEGRO_ALPHA_SIZE],
217 eds->settings[ALLEGRO_COLOR_SIZE]);
218 ALLEGRO_INFO("Depth buffer: %i bits\n", eds->settings[ALLEGRO_DEPTH_SIZE]);
219 ALLEGRO_INFO("Sample buffers: %s\n", eds->settings[ALLEGRO_SAMPLE_BUFFERS] ? "yes" : "no");
220 ALLEGRO_INFO("Samples: %i\n", eds->settings[ALLEGRO_SAMPLES]);
221 }
222
223
decode_pixel_format_old(PIXELFORMATDESCRIPTOR * pfd,ALLEGRO_EXTRA_DISPLAY_SETTINGS * eds)224 static int decode_pixel_format_old(PIXELFORMATDESCRIPTOR *pfd,
225 ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds)
226 {
227 ALLEGRO_INFO("Decoding:\n");
228
229 /* Not interested if it doesn't support OpenGL and RGBA */
230 if (!(pfd->dwFlags & PFD_SUPPORT_OPENGL)) {
231 ALLEGRO_INFO("OpenGL Unsupported\n");
232 return false;
233 }
234 if (pfd->iPixelType != PFD_TYPE_RGBA) {
235 ALLEGRO_INFO("Not RGBA mode\n");
236 return false;
237 }
238
239 /* hardware acceleration */
240 if (((pfd->dwFlags & PFD_GENERIC_ACCELERATED) && (pfd->dwFlags & PFD_GENERIC_FORMAT))
241 || (!(pfd->dwFlags & PFD_GENERIC_ACCELERATED) && !(pfd->dwFlags & PFD_GENERIC_FORMAT)))
242 eds->settings[ALLEGRO_RENDER_METHOD] = 1;
243 else
244 eds->settings[ALLEGRO_RENDER_METHOD] = 0;
245
246 /* Depths of colour buffers */
247 eds->settings[ALLEGRO_RED_SIZE] = pfd->cRedBits;
248 eds->settings[ALLEGRO_GREEN_SIZE] = pfd->cGreenBits;
249 eds->settings[ALLEGRO_BLUE_SIZE] = pfd->cBlueBits;
250 eds->settings[ALLEGRO_ALPHA_SIZE] = pfd->cAlphaBits;
251
252 /* Depths of accumulation buffer */
253 eds->settings[ALLEGRO_ACC_RED_SIZE] = pfd->cAccumRedBits;
254 eds->settings[ALLEGRO_ACC_GREEN_SIZE] = pfd->cAccumGreenBits;
255 eds->settings[ALLEGRO_ACC_BLUE_SIZE] = pfd->cAccumBlueBits;
256 eds->settings[ALLEGRO_ACC_ALPHA_SIZE] = pfd->cAccumAlphaBits;
257
258 /* Miscellaneous settings */
259 eds->settings[ALLEGRO_SINGLE_BUFFER] = !(pfd->dwFlags & PFD_DOUBLEBUFFER);
260 eds->settings[ALLEGRO_DEPTH_SIZE] = pfd->cDepthBits;
261 eds->settings[ALLEGRO_STENCIL_SIZE] = pfd->cStencilBits;
262 eds->settings[ALLEGRO_COLOR_SIZE] = pfd->cColorBits;
263 eds->settings[ALLEGRO_STEREO] = pfd->dwFlags & PFD_STEREO;
264 eds->settings[ALLEGRO_AUX_BUFFERS] = pfd->cAuxBuffers;
265
266 /* These are the component shifts. */
267 eds->settings[ALLEGRO_RED_SHIFT] = pfd->cRedShift;
268 eds->settings[ALLEGRO_GREEN_SHIFT] = pfd->cGreenShift;
269 eds->settings[ALLEGRO_BLUE_SHIFT] = pfd->cBlueShift;
270 eds->settings[ALLEGRO_ALPHA_SHIFT] = pfd->cAlphaShift;
271
272 /* Multisampling isn't supported under Windows if we don't also use
273 * WGL_ARB_pixel_format or WGL_EXT_pixel_format.
274 */
275 eds->settings[ALLEGRO_SAMPLE_BUFFERS] = 0;
276 eds->settings[ALLEGRO_SAMPLES] = 0;
277
278 /* Swap method can't be detected without WGL_ARB_pixel_format or
279 * WGL_EXT_pixel_format
280 */
281 eds->settings[ALLEGRO_SWAP_METHOD] = 0;
282
283 /* Float depth/color isn't supported under Windows if we don't also use
284 * AGL_ARB_pixel_format or WGL_EXT_pixel_format.
285 */
286 eds->settings[ALLEGRO_FLOAT_COLOR] = 0;
287 eds->settings[ALLEGRO_FLOAT_DEPTH] = 0;
288
289 // FIXME
290
291 eds->settings[ALLEGRO_COMPATIBLE_DISPLAY] = 1;
292
293 return true;
294 }
295
296
decode_pixel_format_attrib(ALLEGRO_EXTRA_DISPLAY_SETTINGS * eds,int num_attribs,const int * attrib,const int * value)297 static bool decode_pixel_format_attrib(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds, int num_attribs,
298 const int *attrib, const int *value)
299 {
300 int i;
301
302 ALLEGRO_INFO("Decoding:\n");
303
304 eds->settings[ALLEGRO_SAMPLES] = 0;
305 eds->settings[ALLEGRO_SAMPLE_BUFFERS] = 0;
306 eds->settings[ALLEGRO_FLOAT_DEPTH] = 0;
307 eds->settings[ALLEGRO_FLOAT_COLOR] = 0;
308 eds->settings[ALLEGRO_COMPATIBLE_DISPLAY] = 1;
309
310 for (i = 0; i < num_attribs; i++) {
311 /* Not interested if it doesn't support OpenGL or window drawing or RGBA. */
312 if (attrib[i] == WGL_SUPPORT_OPENGL_ARB && value[i] == 0) {
313 ALLEGRO_INFO("OpenGL Unsupported\n");
314 return false;
315 }
316 else if (attrib[i] == WGL_DRAW_TO_WINDOW_ARB && value[i] == 0) {
317 ALLEGRO_INFO("Can't draw to window\n");
318 return false;
319 }
320 else if (attrib[i] == WGL_PIXEL_TYPE_ARB
321 && (value[i] != WGL_TYPE_RGBA_ARB && value[i] != WGL_TYPE_RGBA_FLOAT_ARB)) {
322 ALLEGRO_INFO("Not RGBA mode\n");
323 return false;
324 }
325 /* hardware acceleration */
326 else if (attrib[i] == WGL_ACCELERATION_ARB) {
327 eds->settings[ALLEGRO_RENDER_METHOD] = (value[i] == WGL_NO_ACCELERATION_ARB) ? 0 : 1;
328 }
329 /* Depths of colour buffers */
330 else if (attrib[i] == WGL_RED_BITS_ARB) {
331 eds->settings[ALLEGRO_RED_SIZE] = value[i];
332 }
333 else if (attrib[i] == WGL_GREEN_BITS_ARB) {
334 eds->settings[ALLEGRO_GREEN_SIZE] = value[i];
335 }
336 else if (attrib[i] == WGL_BLUE_BITS_ARB) {
337 eds->settings[ALLEGRO_BLUE_SIZE] = value[i];
338 }
339 else if (attrib[i] == WGL_ALPHA_BITS_ARB) {
340 eds->settings[ALLEGRO_ALPHA_SIZE] = value[i];
341 }
342 /* Shift of color components */
343 else if (attrib[i] == WGL_RED_SHIFT_ARB) {
344 eds->settings[ALLEGRO_RED_SHIFT] = value[i];
345 }
346 else if (attrib[i] == WGL_GREEN_SHIFT_ARB) {
347 eds->settings[ALLEGRO_GREEN_SHIFT] = value[i];
348 }
349 else if (attrib[i] == WGL_BLUE_SHIFT_ARB) {
350 eds->settings[ALLEGRO_BLUE_SHIFT] = value[i];
351 }
352 else if (attrib[i] == WGL_ALPHA_SHIFT_ARB) {
353 eds->settings[ALLEGRO_ALPHA_SHIFT] = value[i];
354 }
355 /* Miscellaneous settings */
356 else if (attrib[i] == WGL_DOUBLE_BUFFER_ARB) {
357 eds->settings[ALLEGRO_SINGLE_BUFFER] = !(value[i]);
358 }
359 else if (attrib[i] == WGL_SWAP_METHOD_ARB) {
360 if (value[i] == WGL_SWAP_UNDEFINED_ARB)
361 eds->settings[ALLEGRO_SWAP_METHOD] = 0;
362 else if (value[i] == WGL_SWAP_COPY_ARB)
363 eds->settings[ALLEGRO_SWAP_METHOD] = 1;
364 else if (value[i] == WGL_SWAP_EXCHANGE_ARB)
365 eds->settings[ALLEGRO_SWAP_METHOD] = 2;
366 }
367
368 else if (attrib[i] == WGL_STEREO_ARB) {
369 eds->settings[ALLEGRO_STEREO] = value[i];
370 }
371 else if (attrib[i] == WGL_AUX_BUFFERS_ARB) {
372 eds->settings[ALLEGRO_AUX_BUFFERS] = value[i];
373 }
374 else if (attrib[i] == WGL_STENCIL_BITS_ARB) {
375 eds->settings[ALLEGRO_STENCIL_SIZE] = value[i];
376 }
377 /* Depths of accumulation buffer */
378 else if (attrib[i] == WGL_ACCUM_RED_BITS_ARB) {
379 eds->settings[ALLEGRO_ACC_RED_SIZE] = value[i];
380 }
381 else if (attrib[i] == WGL_ACCUM_GREEN_BITS_ARB) {
382 eds->settings[ALLEGRO_ACC_GREEN_SIZE] = value[i];
383 }
384 else if (attrib[i] == WGL_ACCUM_BLUE_BITS_ARB) {
385 eds->settings[ALLEGRO_ACC_BLUE_SIZE] = value[i];
386 }
387 else if (attrib[i] == WGL_ACCUM_ALPHA_BITS_ARB) {
388 eds->settings[ALLEGRO_ACC_ALPHA_SIZE] = value[i];
389 }
390
391 else if (attrib[i] == WGL_DEPTH_BITS_ARB) {
392 eds->settings[ALLEGRO_DEPTH_SIZE] = value[i];
393 }
394 else if (attrib[i] == WGL_COLOR_BITS_ARB) {
395 eds->settings[ALLEGRO_COLOR_SIZE] = value[i];
396 }
397 /* Multisampling bits */
398 else if (attrib[i] == WGL_SAMPLE_BUFFERS_ARB) {
399 eds->settings[ALLEGRO_SAMPLE_BUFFERS] = value[i];
400 }
401 else if (attrib[i] == WGL_SAMPLES_ARB) {
402 eds->settings[ALLEGRO_SAMPLES] = value[i];
403 }
404 /* Float color */
405 if (attrib[i] == WGL_PIXEL_TYPE_ARB && value[i] == WGL_TYPE_RGBA_FLOAT_ARB) {
406 eds->settings[ALLEGRO_FLOAT_COLOR] = true;
407 }
408 /* Float depth */
409 else if (attrib[i] == WGL_DEPTH_FLOAT_EXT) {
410 eds->settings[ALLEGRO_FLOAT_DEPTH] = value[i];
411 }
412 }
413
414 return true;
415 }
416
417
read_pixel_format_old(int fmt,HDC dc)418 static ALLEGRO_EXTRA_DISPLAY_SETTINGS* read_pixel_format_old(int fmt, HDC dc)
419 {
420 ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = NULL;
421 PIXELFORMATDESCRIPTOR pfd;
422 int result;
423
424 result = DescribePixelFormat(dc, fmt+1, sizeof(pfd), &pfd);
425 if (!result) {
426 ALLEGRO_WARN("DescribePixelFormat() failed. %s\n", _al_win_last_error());
427 return NULL;
428 }
429
430 eds = al_calloc(1, sizeof *eds);
431 if (!decode_pixel_format_old(&pfd, eds)) {
432 al_free(eds);
433 return NULL;
434 }
435
436 return eds;
437 }
438
439
read_pixel_format_ext(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB,int fmt,HDC dc)440 static ALLEGRO_EXTRA_DISPLAY_SETTINGS* read_pixel_format_ext(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB, int fmt, HDC dc)
441 {
442 ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = NULL;
443
444 /* Note: Even though we use te ARB suffix, all those enums are compatible
445 * with EXT_pixel_format.
446 */
447 int attrib[] = {
448 WGL_SUPPORT_OPENGL_ARB,
449 WGL_DRAW_TO_WINDOW_ARB,
450 WGL_PIXEL_TYPE_ARB,
451 WGL_ACCELERATION_ARB,
452 WGL_DOUBLE_BUFFER_ARB,
453 WGL_DEPTH_BITS_ARB,
454 WGL_SWAP_METHOD_ARB,
455 WGL_COLOR_BITS_ARB,
456 WGL_RED_BITS_ARB,
457 WGL_GREEN_BITS_ARB,
458 WGL_BLUE_BITS_ARB,
459 WGL_ALPHA_BITS_ARB,
460 WGL_RED_SHIFT_ARB,
461 WGL_GREEN_SHIFT_ARB,
462 WGL_BLUE_SHIFT_ARB,
463 WGL_ALPHA_SHIFT_ARB,
464 WGL_STENCIL_BITS_ARB,
465 WGL_STEREO_ARB,
466 WGL_ACCUM_BITS_ARB,
467 WGL_ACCUM_RED_BITS_ARB,
468 WGL_ACCUM_GREEN_BITS_ARB,
469 WGL_ACCUM_BLUE_BITS_ARB,
470 WGL_ACCUM_ALPHA_BITS_ARB,
471 WGL_AUX_BUFFERS_ARB,
472
473 /* The following are used by extensions that add to WGL_pixel_format.
474 * If WGL_p_f isn't supported though, we can't use the (then invalid)
475 * enums. We can't use any magic number either, so we settle for
476 * replicating one. The pixel format decoder
477 * (decode_pixel_format_attrib()) doesn't care about duplicates.
478 */
479 WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_SAMPLE_BUFFERS_ARB */
480 WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_SAMPLES_ARB */
481 WGL_AUX_BUFFERS_ARB, /* placeholder for WGL_DEPTH_FLOAT_EXT */
482 };
483
484 const int num_attribs = sizeof(attrib) / sizeof(attrib[0]);
485 int *value = (int*)al_malloc(sizeof(int) * num_attribs);
486 int ret;
487
488 if (!value)
489 return NULL;
490
491 /* If multisampling is supported, query for it. */
492 if (is_wgl_extension_supported(_wglGetExtensionsStringARB, "WGL_ARB_multisample", dc)) {
493 attrib[num_attribs - 3] = WGL_SAMPLE_BUFFERS_ARB;
494 attrib[num_attribs - 2] = WGL_SAMPLES_ARB;
495 }
496 if (is_wgl_extension_supported(_wglGetExtensionsStringARB, "WGL_EXT_depth_float", dc)) {
497 attrib[num_attribs - 1] = WGL_DEPTH_FLOAT_EXT;
498 }
499
500 /* Get the pf attributes */
501 if (_wglGetPixelFormatAttribivARB) {
502 ret = _wglGetPixelFormatAttribivARB(dc, fmt+1, 0, num_attribs, attrib, value);
503 }
504 else if (_wglGetPixelFormatAttribivEXT) {
505 ret = _wglGetPixelFormatAttribivEXT(dc, fmt+1, 0, num_attribs, attrib, value);
506 }
507 else {
508 ret = 0;
509 }
510
511 if (!ret) {
512 ALLEGRO_ERROR("wglGetPixelFormatAttrib failed! %s\n", _al_win_last_error());
513 al_free(value);
514 return NULL;
515 }
516
517 eds = al_calloc(1, sizeof *eds);
518 if (!decode_pixel_format_attrib(eds, num_attribs, attrib, value)) {
519 al_free(eds);
520 eds = NULL;
521 }
522
523 al_free(value);
524
525 /* Hack: for some reason this happens for me under Wine. */
526 if (eds &&
527 eds->settings[ALLEGRO_RED_SHIFT] == 0 &&
528 eds->settings[ALLEGRO_GREEN_SHIFT] == 0 &&
529 eds->settings[ALLEGRO_BLUE_SHIFT] == 0 &&
530 eds->settings[ALLEGRO_ALPHA_SHIFT] == 0) {
531 eds->settings[ALLEGRO_RED_SHIFT] = 0;
532 eds->settings[ALLEGRO_GREEN_SHIFT] = 8;
533 eds->settings[ALLEGRO_BLUE_SHIFT] = 16;
534 eds->settings[ALLEGRO_ALPHA_SHIFT] = 24;
535 }
536
537 return eds;
538 }
539
540
change_display_mode(ALLEGRO_DISPLAY * d)541 static bool change_display_mode(ALLEGRO_DISPLAY *d)
542 {
543 DEVMODE dm;
544 DEVMODE fallback_dm;
545 DISPLAY_DEVICE dd;
546 TCHAR* dev_name = NULL;
547 int i, modeswitch, result;
548 int fallback_dm_valid = 0;
549 int bpp;
550 int adapter = al_get_new_display_adapter();
551
552 if (adapter >= 0) {
553 memset(&dd, 0, sizeof(dd));
554 dd.cb = sizeof(dd);
555 if (EnumDisplayDevices(NULL, adapter, &dd, 0) == false)
556 return false;
557 dev_name = dd.DeviceName;
558 }
559
560 memset(&fallback_dm, 0, sizeof(fallback_dm));
561 memset(&dm, 0, sizeof(dm));
562 dm.dmSize = sizeof(DEVMODE);
563
564 bpp = d->extra_settings.settings[ALLEGRO_COLOR_SIZE];
565 if (!bpp)
566 bpp = 32;
567
568 i = 0;
569 do {
570 modeswitch = EnumDisplaySettings(dev_name, i, &dm);
571 if (!modeswitch)
572 break;
573
574 if ((dm.dmPelsWidth == (unsigned) d->w)
575 && (dm.dmPelsHeight == (unsigned) d->h)
576 && (dm.dmBitsPerPel == (unsigned) bpp)
577 && (dm.dmDisplayFrequency != (unsigned) d->refresh_rate))
578 {
579 /* Keep it as fallback if refresh rate request could not
580 * be satisfied. Try to get as close to 60Hz as possible though,
581 * it's a bit better for a fallback than just blindly picking
582 * something like 47Hz or 200Hz.
583 */
584 if (!fallback_dm_valid) {
585 fallback_dm = dm;
586 fallback_dm_valid = 1;
587 }
588 else if (dm.dmDisplayFrequency >= 60) {
589 if (dm.dmDisplayFrequency < fallback_dm.dmDisplayFrequency) {
590 fallback_dm = dm;
591 }
592 }
593 }
594 i++;
595 }
596 while ((dm.dmPelsWidth != (unsigned) d->w)
597 || (dm.dmPelsHeight != (unsigned) d->h)
598 || (dm.dmBitsPerPel != (unsigned) bpp)
599 || (dm.dmDisplayFrequency != (unsigned) d->refresh_rate));
600
601 if (!modeswitch && !fallback_dm_valid) {
602 ALLEGRO_ERROR("Mode not found.\n");
603 return false;
604 }
605
606 if (!modeswitch && fallback_dm_valid)
607 dm = fallback_dm;
608
609 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
610 result = ChangeDisplaySettingsEx(dev_name, &dm, NULL, CDS_FULLSCREEN, 0);
611
612 d->refresh_rate = dm.dmDisplayFrequency;
613
614 if (result != DISP_CHANGE_SUCCESSFUL) {
615 ALLEGRO_ERROR("Unable to set mode. %s\n", _al_win_last_error());
616 return false;
617 }
618
619 ALLEGRO_INFO("Mode seccessfuly set.\n");
620 return true;
621 }
622
623
init_ogl_context_ex(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB,HDC dc,bool fc,int major,int minor)624 static HGLRC init_ogl_context_ex(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB, HDC dc, bool fc, int major, int minor)
625 {
626 HWND testwnd = NULL;
627 HDC testdc = NULL;
628 HGLRC testrc = NULL;
629 HGLRC old_rc = NULL;
630 HDC old_dc = NULL;
631 HGLRC glrc = NULL;
632
633 testwnd = _al_win_create_hidden_window();
634 if (!testwnd)
635 return NULL;
636
637 old_rc = wglGetCurrentContext();
638 old_dc = wglGetCurrentDC();
639
640 testdc = GetDC(testwnd);
641 testrc = init_temp_context(testwnd);
642 if (!testrc)
643 goto bail;
644
645 if (is_wgl_extension_supported(_wglGetExtensionsStringARB, "WGL_ARB_create_context", testdc)) {
646 int attrib[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, major,
647 WGL_CONTEXT_MINOR_VERSION_ARB, minor,
648 WGL_CONTEXT_FLAGS_ARB, 0,
649 0};
650 if (fc)
651 attrib[5] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
652 if (!init_context_creation_extensions())
653 goto bail;
654 /* TODO: we could use the context sharing feature */
655 glrc = _wglCreateContextAttribsARB(dc, 0, attrib);
656 }
657 else
658 goto bail;
659
660 bail:
661 wglMakeCurrent(NULL, NULL);
662 if (testrc) {
663 wglDeleteContext(testrc);
664 }
665
666 wglMakeCurrent(old_dc, old_rc);
667
668 _wglCreateContextAttribsARB = NULL;
669
670 if (testwnd) {
671 ReleaseDC(testwnd, testdc);
672 DestroyWindow(testwnd);
673 }
674
675 return glrc;
676 }
677
678
get_available_pixel_formats_ext(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB,int * count)679 static ALLEGRO_EXTRA_DISPLAY_SETTINGS** get_available_pixel_formats_ext(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB, int *count)
680 {
681 HWND testwnd = NULL;
682 HDC testdc = NULL;
683 HGLRC testrc = NULL;
684 HGLRC old_rc = NULL;
685 HDC old_dc = NULL;
686 ALLEGRO_EXTRA_DISPLAY_SETTINGS **eds_list = NULL;
687 ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref;
688 int maxindex;
689 int i, j;
690
691 *count = 0;
692 ref = _al_get_new_display_settings();
693
694 /* We need to create a dummy window with a pixel format to get the
695 * list of valid PFDs
696 */
697 testwnd = _al_win_create_hidden_window();
698 if (!testwnd)
699 return false;
700
701 old_rc = wglGetCurrentContext();
702 old_dc = wglGetCurrentDC();
703
704 testdc = GetDC(testwnd);
705 testrc = init_temp_context(testwnd);
706 if (!testrc)
707 goto bail;
708
709 if (!is_wgl_extension_supported(_wglGetExtensionsStringARB, "WGL_ARB_pixel_format", testdc) &&
710 !is_wgl_extension_supported(_wglGetExtensionsStringARB, "WGL_EXT_pixel_format", testdc)) {
711 ALLEGRO_ERROR("WGL_ARB/EXT_pf not supported.\n");
712 goto bail;
713 }
714
715 if (!init_pixel_format_extensions())
716 goto bail;
717
718 maxindex = get_pixel_formats_count_ext(testdc);
719 if (maxindex < 1)
720 goto bail;
721
722 ALLEGRO_INFO("Got %i visuals.\n", maxindex);
723
724 eds_list = al_calloc(maxindex, sizeof(*eds_list));
725 if (!eds_list)
726 goto bail;
727
728 for (j = i = 0; i < maxindex; i++) {
729 ALLEGRO_INFO("-- \n");
730 ALLEGRO_INFO("Decoding visual no. %i...\n", i+1);
731 eds_list[j] = read_pixel_format_ext(_wglGetExtensionsStringARB, i, testdc);
732 if (!eds_list[j])
733 continue;
734 // Fill vsync setting here and enable/disable it after display creation
735 eds_list[j]->settings[ALLEGRO_VSYNC] = ref->settings[ALLEGRO_VSYNC];
736 display_pixel_format(eds_list[j]);
737 eds_list[j]->score = _al_score_display_settings(eds_list[j], ref);
738 if (eds_list[j]->score == -1) {
739 al_free(eds_list[j]);
740 eds_list[j] = NULL;
741 continue;
742 }
743 /* In WinAPI first index is 1 ::) */
744 eds_list[j]->index = i+1;
745 j++;
746 }
747
748 ALLEGRO_INFO("%i visuals are good enough.\n", j);
749 *count = j;
750
751 bail:
752 wglMakeCurrent(NULL, NULL);
753 if (testrc) {
754 wglDeleteContext(testrc);
755 }
756
757 wglMakeCurrent(old_dc, old_rc);
758
759 _wglGetPixelFormatAttribivARB = NULL;
760 _wglGetPixelFormatAttribivEXT = NULL;
761
762 if (testwnd) {
763 ReleaseDC(testwnd, testdc);
764 DestroyWindow(testwnd);
765 }
766
767 return eds_list;
768 }
769
770
get_available_pixel_formats_old(int * count,HDC dc)771 static ALLEGRO_EXTRA_DISPLAY_SETTINGS** get_available_pixel_formats_old(int *count, HDC dc)
772 {
773 ALLEGRO_EXTRA_DISPLAY_SETTINGS **eds_list = NULL;
774 ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref;
775 int maxindex;
776 int i, j;
777
778 *count = 0;
779 ref = _al_get_new_display_settings();
780
781 maxindex = get_pixel_formats_count_old(dc);
782 if (maxindex < 1)
783 return NULL;
784
785 ALLEGRO_INFO("Got %i visuals.\n", maxindex);
786
787 eds_list = al_calloc(maxindex, sizeof(*eds_list));
788 if (!eds_list)
789 return NULL;
790
791 for (j = i = 0; i < maxindex; i++) {
792 ALLEGRO_INFO("-- \n");
793 ALLEGRO_INFO("Decoding visual no. %i...\n", i+1);
794 eds_list[j] = read_pixel_format_old(i, dc);
795 if (!eds_list[j])
796 continue;
797 #ifdef DEBUGMODE
798 display_pixel_format(eds_list[j]);
799 #endif
800 eds_list[j]->score = _al_score_display_settings(eds_list[j], ref);
801 if (eds_list[j]->score == -1) {
802 al_free(eds_list[j]);
803 eds_list[j] = NULL;
804 continue;
805 }
806 /* In WinAPI first index is 1 ::) */
807 eds_list[j]->index = i+1;
808 j++;
809 }
810
811 ALLEGRO_INFO("%i visuals are good enough.\n", j);
812 *count = j;
813
814 return eds_list;
815 }
816
817
select_pixel_format(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB,ALLEGRO_DISPLAY_WGL * d,HDC dc)818 static bool select_pixel_format(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB, ALLEGRO_DISPLAY_WGL *d, HDC dc)
819 {
820 ALLEGRO_EXTRA_DISPLAY_SETTINGS **eds = NULL;
821 ALLEGRO_CONFIG *sys_cfg = al_get_system_config();
822 int eds_count = 0;
823 int i;
824 bool force_old = false;
825 const char *selection_mode;
826
827 selection_mode = al_get_config_value(sys_cfg, "graphics",
828 "config_selection");
829 if (selection_mode && selection_mode[0] != '\0') {
830 if (!_al_stricmp(selection_mode, "old")) {
831 ALLEGRO_INFO("Forcing OLD visual selection method.\n");
832 force_old = true;
833 }
834 else if (!_al_stricmp(selection_mode, "new"))
835 force_old = false;
836 }
837
838 if (!force_old)
839 eds = get_available_pixel_formats_ext(_wglGetExtensionsStringARB, &eds_count);
840 if (!eds)
841 eds = get_available_pixel_formats_old(&eds_count, dc);
842
843 if (!eds || !eds_count) {
844 ALLEGRO_ERROR("Didn't find any suitable pixel format!\n");
845 return false;
846 }
847
848 qsort(eds, eds_count, sizeof(eds[0]), _al_display_settings_sorter);
849
850 for (i = 0; i < eds_count ; i++) {
851 if (SetPixelFormat(d->dc, eds[i]->index, NULL)) {
852 ALLEGRO_INFO("Chose visual no. %i\n\n", eds[i]->index);
853 display_pixel_format(eds[i]);
854 break;
855 }
856 else {
857 ALLEGRO_WARN("Unable to set pixel format! %s\n", _al_win_last_error());
858 ALLEGRO_WARN("Trying next one.\n");
859 }
860 }
861
862 if (i == eds_count) {
863 ALLEGRO_ERROR("Unable to set any pixel format! %s\n", _al_win_last_error());
864 for (i = 0; i < eds_count; i++)
865 al_free(eds[i]);
866 al_free(eds);
867 return false;
868 }
869
870 memcpy(&d->win_display.display.extra_settings, eds[i], sizeof(ALLEGRO_EXTRA_DISPLAY_SETTINGS));
871
872 for (i = 0; i < eds_count; i++)
873 al_free(eds[i]);
874 if (eds)
875 al_free(eds);
876
877 return true;
878 }
879
create_display_internals(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB,ALLEGRO_DISPLAY_WGL * wgl_disp)880 static bool create_display_internals(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB, ALLEGRO_DISPLAY_WGL *wgl_disp)
881 {
882 ALLEGRO_DISPLAY *disp = (void*)wgl_disp;
883 ALLEGRO_DISPLAY_WIN *win_disp = (void*)wgl_disp;
884 WGL_DISPLAY_PARAMETERS ndp;
885 int window_x, window_y;
886 int major, minor;
887
888 /* The window is created in a separate thread so we need to pass this
889 * TLS on
890 */
891 al_get_new_window_position(&window_x, &window_y);
892 ndp.window_x = window_x;
893 ndp.window_y = window_y;
894 ndp.window_title = al_get_new_window_title();
895
896 /* _beginthread closes the handle automatically. */
897 ndp.display = wgl_disp;
898 ndp.init_failed = true;
899 ndp.AckEvent = CreateEvent(NULL, false, false, NULL);
900 _beginthread(display_thread_proc, 0, &ndp);
901
902 /* Wait some _finite_ time (10 secs or so) for display thread to init, and
903 * give up if something horrible happened to it, unless we're in debug mode
904 * and we may have intentionally stopped the execution to analyze the code.
905 */
906 #ifdef DEBUGMODE
907 WaitForSingleObject(ndp.AckEvent, INFINITE);
908 #else
909 WaitForSingleObject(ndp.AckEvent, 10*1000);
910 #endif
911
912 CloseHandle(ndp.AckEvent);
913
914 if (ndp.init_failed) {
915 ALLEGRO_ERROR("Failed to create display.\n");
916 return false;
917 }
918
919 /* WGL display lists cannot be shared with the API currently in use. */
920 disp->ogl_extras->is_shared = false;
921
922 if (!select_pixel_format(_wglGetExtensionsStringARB, wgl_disp, wgl_disp->dc)) {
923 destroy_display_internals(wgl_disp);
924 return false;
925 }
926
927 major = al_get_new_display_option(ALLEGRO_OPENGL_MAJOR_VERSION, 0);
928 minor = al_get_new_display_option(ALLEGRO_OPENGL_MINOR_VERSION, 0);
929
930 // TODO: request GLES context in GLES builds
931 if ((disp->flags & ALLEGRO_OPENGL_3_0) || major != 0) {
932 if (major == 0)
933 major = 3;
934 bool fc = (disp->flags & ALLEGRO_OPENGL_FORWARD_COMPATIBLE) != 0;
935 wgl_disp->glrc = init_ogl_context_ex(_wglGetExtensionsStringARB, wgl_disp->dc, fc, major,
936 minor);
937 }
938 else {
939 wgl_disp->glrc = wglCreateContext(wgl_disp->dc);
940 }
941
942 if (!wgl_disp->glrc) {
943 ALLEGRO_ERROR("Unable to create a render context! %s\n", _al_win_last_error());
944 destroy_display_internals(wgl_disp);
945 return false;
946 }
947
948 /* make the context the current one */
949 if (!wglMakeCurrent(wgl_disp->dc, wgl_disp->glrc)) {
950 ALLEGRO_ERROR("Unable to make the context current! %s\n", _al_win_last_error());
951 destroy_display_internals(wgl_disp);
952 return false;
953 }
954
955 _al_ogl_manage_extensions(disp);
956 _al_ogl_set_extensions(disp->ogl_extras->extension_api);
957
958 if (disp->ogl_extras->ogl_info.version < _ALLEGRO_OPENGL_VERSION_1_2) {
959 ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds = _al_get_new_display_settings();
960 if (eds->required & (1<<ALLEGRO_COMPATIBLE_DISPLAY)) {
961 ALLEGRO_WARN("Allegro requires at least OpenGL version 1.2 to work.\n");
962 destroy_display_internals(wgl_disp);
963 return false;
964 }
965 disp->extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY] = 0;
966 }
967
968 /* Fill in the display settings for opengl major and minor versions...*/
969 const int v = disp->ogl_extras->ogl_info.version;
970 disp->extra_settings.settings[ALLEGRO_OPENGL_MAJOR_VERSION] = (v >> 24) & 0xFF;
971 disp->extra_settings.settings[ALLEGRO_OPENGL_MINOR_VERSION] = (v >> 16) & 0xFF;
972
973 /* Try to enable or disable vsync as requested */
974 /* NOTE: my drivers claim I don't have WGL_EXT_swap_control
975 * (according to al_have_opengl_extension), but wglSwapIntervalEXT
976 * does get loaded, so just check for that.
977 */
978 if (wglSwapIntervalEXT) {
979 if (disp->extra_settings.settings[ALLEGRO_VSYNC] == 1) {
980 wglSwapIntervalEXT(1);
981 }
982 else if (disp->extra_settings.settings[ALLEGRO_VSYNC] == 2) {
983 wglSwapIntervalEXT(0);
984 }
985 }
986
987 win_disp->mouse_selected_hcursor = 0;
988 win_disp->mouse_cursor_shown = false;
989 win_disp->can_acknowledge = false;
990
991 _al_win_grab_input(win_disp);
992
993 if (disp->extra_settings.settings[ALLEGRO_COMPATIBLE_DISPLAY])
994 _al_ogl_setup_gl(disp);
995
996 return true;
997 }
998
999
wgl_create_display(int w,int h)1000 static ALLEGRO_DISPLAY* wgl_create_display(int w, int h)
1001 {
1002 ALLEGRO_SYSTEM_WIN *system = (ALLEGRO_SYSTEM_WIN *)al_get_system_driver();
1003 ALLEGRO_DISPLAY_WGL **add;
1004 ALLEGRO_DISPLAY_WGL *wgl_display = al_calloc(1, sizeof *wgl_display);
1005 ALLEGRO_DISPLAY *ogl_display = (void*)wgl_display;
1006 ALLEGRO_DISPLAY *display = (void*)ogl_display;
1007 ALLEGRO_DISPLAY_WIN *win_disp = (ALLEGRO_DISPLAY_WIN *)display;
1008
1009 win_disp->adapter = _al_win_determine_adapter();
1010
1011 display->w = w;
1012 display->h = h;
1013 display->refresh_rate = al_get_new_display_refresh_rate();
1014 display->flags = al_get_new_display_flags();
1015 #ifdef ALLEGRO_CFG_OPENGLES2
1016 display->flags |= ALLEGRO_PROGRAMMABLE_PIPELINE;
1017 #endif
1018 #ifdef ALLEGRO_CFG_OPENGLES
1019 display->flags |= ALLEGRO_OPENGL_ES_PROFILE;
1020 #endif
1021 display->vt = &vt;
1022
1023 display->ogl_extras = al_calloc(1, sizeof(ALLEGRO_OGL_EXTRAS));
1024
1025 _ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB
1026 = (_ALLEGRO_wglGetExtensionsStringARB_t)wglGetProcAddress("wglGetExtensionsStringARB");
1027 if (!create_display_internals(_wglGetExtensionsStringARB, wgl_display)) {
1028 al_free(display->ogl_extras);
1029 al_free(display);
1030 return NULL;
1031 }
1032
1033 /* Print out OpenGL version info */
1034 ALLEGRO_INFO("OpenGL Version: %s\n", (const char*)glGetString(GL_VERSION));
1035 ALLEGRO_INFO("Vendor: %s\n", (const char*)glGetString(GL_VENDOR));
1036 ALLEGRO_INFO("Renderer: %s\n\n", (const char*)glGetString(GL_RENDERER));
1037
1038 /* Add ourself to the list of displays. */
1039 add = _al_vector_alloc_back(&system->system.displays);
1040 *add = wgl_display;
1041
1042 /* Each display is an event source. */
1043 _al_event_source_init(&display->es);
1044
1045 _al_win_set_system_mouse_cursor(display, ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW);
1046 _al_win_show_mouse_cursor(display);
1047
1048 _al_win_post_create_window(display);
1049
1050 return display;
1051 }
1052
1053
destroy_display_internals(ALLEGRO_DISPLAY_WGL * wgl_disp)1054 static void destroy_display_internals(ALLEGRO_DISPLAY_WGL *wgl_disp)
1055 {
1056 ALLEGRO_DISPLAY *disp = (ALLEGRO_DISPLAY *)wgl_disp;
1057 ALLEGRO_DISPLAY_WIN *win_disp = (ALLEGRO_DISPLAY_WIN *)wgl_disp;
1058
1059 /* We need to convert all our bitmaps to display independent (memory)
1060 * bitmaps because WGL driver doesn't support sharing of resources. */
1061 while (disp->bitmaps._size > 0) {
1062 ALLEGRO_BITMAP **bptr = _al_vector_ref_back(&disp->bitmaps);
1063 ALLEGRO_BITMAP *bmp = *bptr;
1064 _al_convert_to_memory_bitmap(bmp);
1065 }
1066
1067 if (disp->ogl_extras->backbuffer)
1068 _al_ogl_destroy_backbuffer(disp->ogl_extras->backbuffer);
1069 disp->ogl_extras->backbuffer = NULL;
1070
1071 _al_ogl_unmanage_extensions(disp);
1072
1073 PostMessage(win_disp->window, _al_win_msg_suicide, (WPARAM)win_disp, 0);
1074
1075 while (!win_disp->thread_ended)
1076 al_rest(0.001);
1077
1078 if (wgl_disp->glrc) {
1079 wglDeleteContext(wgl_disp->glrc);
1080 wgl_disp->glrc = NULL;
1081 }
1082 if (wgl_disp->dc) {
1083 ReleaseDC(win_disp->window, wgl_disp->dc);
1084 wgl_disp->dc = NULL;
1085 }
1086
1087 if (disp->flags & ALLEGRO_FULLSCREEN && !_wgl_do_not_change_display_mode) {
1088 ChangeDisplaySettings(NULL, 0);
1089 }
1090
1091 if (win_disp->window) {
1092 DestroyWindow(win_disp->window);
1093 win_disp->window = NULL;
1094 }
1095 }
1096
1097
wgl_destroy_display(ALLEGRO_DISPLAY * disp)1098 static void wgl_destroy_display(ALLEGRO_DISPLAY *disp)
1099 {
1100 ALLEGRO_SYSTEM_WIN *system = (ALLEGRO_SYSTEM_WIN *)al_get_system_driver();
1101 ALLEGRO_DISPLAY_WGL *wgl_disp = (ALLEGRO_DISPLAY_WGL *)disp;
1102 ALLEGRO_DISPLAY *old_disp = al_get_current_display();
1103
1104 if (old_disp != disp)
1105 _al_set_current_display_only(disp);
1106
1107 if (system->mouse_grab_display == disp)
1108 system->mouse_grab_display = NULL;
1109
1110 _al_win_destroy_display_icons(disp);
1111
1112 destroy_display_internals(wgl_disp);
1113 _al_event_source_free(&disp->es);
1114 _al_vector_find_and_delete(&system->system.displays, &disp);
1115
1116 _al_vector_free(&disp->bitmaps);
1117 _al_vector_free(&((ALLEGRO_DISPLAY_WIN*) disp)->msg_callbacks);
1118 al_free(disp->ogl_extras);
1119
1120 if (old_disp != disp)
1121 _al_set_current_display_only(old_disp);
1122
1123 al_free(disp->vertex_cache);
1124 al_free(wgl_disp);
1125 }
1126
1127
wgl_set_current_display(ALLEGRO_DISPLAY * d)1128 static bool wgl_set_current_display(ALLEGRO_DISPLAY *d)
1129 {
1130 ALLEGRO_DISPLAY_WGL *wgl_disp = (ALLEGRO_DISPLAY_WGL *)d;
1131 HGLRC current_glrc;
1132
1133 current_glrc = wglGetCurrentContext();
1134
1135 if (!current_glrc || (current_glrc && current_glrc != wgl_disp->glrc)) {
1136 /* make the context the current one */
1137 if (!wglMakeCurrent(wgl_disp->dc, wgl_disp->glrc)) {
1138 ALLEGRO_ERROR("Unable to make the context current! %s\n",
1139 _al_win_last_error());
1140 return false;
1141 }
1142
1143 _al_ogl_set_extensions(d->ogl_extras->extension_api);
1144 }
1145
1146 _al_ogl_update_render_state(d);
1147
1148 return true;
1149 }
1150
1151
wgl_unset_current_display(ALLEGRO_DISPLAY * d)1152 static void wgl_unset_current_display(ALLEGRO_DISPLAY *d)
1153 {
1154 (void)d;
1155
1156 if (!wglMakeCurrent(NULL, NULL)) {
1157 ALLEGRO_ERROR("Unable unset the current context! %s\n", _al_win_last_error());
1158 }
1159 }
1160
1161
1162 /*
1163 * The window must be created in the same thread that
1164 * runs the message loop.
1165 */
display_thread_proc(void * arg)1166 static void display_thread_proc(void *arg)
1167 {
1168 WGL_DISPLAY_PARAMETERS *ndp = arg;
1169 ALLEGRO_DISPLAY *disp = (ALLEGRO_DISPLAY*)ndp->display;
1170 ALLEGRO_DISPLAY_WGL *wgl_disp = (void*)disp;
1171 ALLEGRO_DISPLAY_WIN *win_disp = (void*)disp;
1172 MSG msg;
1173
1174 /* So that we can call the functions using TLS from this thread. */
1175 al_set_new_display_flags(disp->flags);
1176 al_set_new_window_position(ndp->window_x, ndp->window_y);
1177 al_set_new_window_title(ndp->window_title);
1178
1179 if (disp->flags & ALLEGRO_FULLSCREEN) {
1180 if (!change_display_mode(disp)) {
1181 win_disp->thread_ended = true;
1182 destroy_display_internals(wgl_disp);
1183 SetEvent(ndp->AckEvent);
1184 return;
1185 }
1186 }
1187 else if (disp->flags & ALLEGRO_FULLSCREEN_WINDOW) {
1188 ALLEGRO_MONITOR_INFO mi;
1189 int adapter = win_disp->adapter;
1190 al_get_monitor_info(adapter, &mi);
1191
1192 win_disp->toggle_w = disp->w;
1193 win_disp->toggle_h = disp->h;
1194
1195 disp->w = mi.x2 - mi.x1;
1196 disp->h = mi.y2 - mi.y1;
1197
1198 disp->refresh_rate = al_get_monitor_refresh_rate(adapter);
1199 }
1200 else {
1201 int adapter = win_disp->adapter;
1202 win_disp->toggle_w = disp->w;
1203 win_disp->toggle_h = disp->h;
1204
1205 disp->refresh_rate = al_get_monitor_refresh_rate(adapter);
1206 }
1207
1208 win_disp->window = _al_win_create_window(disp, disp->w, disp->h, disp->flags);
1209
1210 if (!win_disp->window) {
1211 win_disp->thread_ended = true;
1212 destroy_display_internals(wgl_disp);
1213 SetEvent(ndp->AckEvent);
1214 return;
1215 }
1216
1217 /* FIXME: can't _al_win_create_window() do this? */
1218 if ((disp->flags & ALLEGRO_FULLSCREEN) ||
1219 (disp->flags & ALLEGRO_FULLSCREEN_WINDOW)) {
1220 RECT rect;
1221 rect.left = 0;
1222 rect.right = disp->w;
1223 rect.top = 0;
1224 rect.bottom = disp->h;
1225 SetWindowPos(win_disp->window, 0, rect.left, rect.top,
1226 rect.right - rect.left, rect.bottom - rect.top,
1227 SWP_NOZORDER | SWP_FRAMECHANGED);
1228 }
1229
1230 if (disp->flags & ALLEGRO_FULLSCREEN_WINDOW) {
1231 bool frameless = true;
1232 _al_win_set_window_frameless(disp, win_disp->window, frameless);
1233 }
1234
1235 /* Yep, the following is really needed sometimes. */
1236 /* ... Or is it now that we have dumped DInput? */
1237 /* <rohannessian> Win98/2k/XP's window forground rules don't let us
1238 * make our window the topmost window on launch. This causes issues on
1239 * full-screen apps, as DInput loses input focus on them.
1240 * We use this trick to force the window to be topmost, when switching
1241 * to full-screen only. Note that this only works for Win98 and greater.
1242 * Win95 will ignore our SystemParametersInfo() calls.
1243 *
1244 * See http://support.microsoft.com:80/support/kb/articles/Q97/9/25.asp
1245 * for details.
1246 */
1247 {
1248 DWORD lock_time;
1249 HWND wnd = win_disp->window;
1250
1251 #define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000
1252 #define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001
1253 if (disp->flags & ALLEGRO_FULLSCREEN) {
1254 SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,
1255 0, (LPVOID)&lock_time, 0);
1256 SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
1257 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
1258 }
1259
1260 ShowWindow(wnd, SW_SHOWNORMAL);
1261 SetForegroundWindow(wnd);
1262 /* In some rare cases, it doesn't seem to work without the loop. And we
1263 * absolutely need this to succeed, else we trap the user in a
1264 * fullscreen window without input.
1265 */
1266 while (GetForegroundWindow() != wnd) {
1267 al_rest(0.01);
1268 SetForegroundWindow(wnd);
1269 }
1270 UpdateWindow(wnd);
1271
1272 if (disp->flags & ALLEGRO_FULLSCREEN) {
1273 SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
1274 0, (LPVOID)&lock_time, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
1275 }
1276 #undef SPI_GETFOREGROUNDLOCKTIMEOUT
1277 #undef SPI_SETFOREGROUNDLOCKTIMEOUT
1278 }
1279
1280 #if 0
1281 if (disp->flags & ALLEGRO_FULLSCREEN && al_is_mouse_installed()) {
1282 RAWINPUTDEVICE rid[1];
1283 rid[0].usUsagePage = 0x01;
1284 rid[0].usUsage = 0x02;
1285 rid[0].dwFlags = RIDEV_NOLEGACY;
1286 rid[0].hwndTarget = 0;
1287 if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) {
1288 ALLEGRO_ERROR(
1289 "Failed to init mouse. %s\n", get_error_desc(GetLastError()));
1290 }
1291 }
1292 #endif
1293
1294 /* get the device context of our window */
1295 wgl_disp->dc = GetDC(win_disp->window);
1296
1297 win_disp->thread_ended = false;
1298 win_disp->end_thread = false;
1299 ndp->init_failed = false;
1300 SetEvent(ndp->AckEvent);
1301
1302 while (!win_disp->end_thread) {
1303 /* get a message from the queue */
1304 if (GetMessage(&msg, NULL, 0, 0) != 0)
1305 DispatchMessage(&msg);
1306 else
1307 break; /* WM_QUIT received or error (GetMessage returned -1) */
1308 }
1309
1310 ALLEGRO_INFO("wgl display thread exits\n");
1311 win_disp->thread_ended = true;
1312 }
1313
1314
wgl_flip_display(ALLEGRO_DISPLAY * d)1315 static void wgl_flip_display(ALLEGRO_DISPLAY *d)
1316 {
1317 ALLEGRO_DISPLAY_WGL* disp = (ALLEGRO_DISPLAY_WGL*)d;
1318 glFlush();
1319 if (!d->extra_settings.settings[ALLEGRO_SINGLE_BUFFER])
1320 SwapBuffers(disp->dc);
1321 }
1322
1323
wgl_update_display_region(ALLEGRO_DISPLAY * d,int x,int y,int width,int height)1324 static void wgl_update_display_region(ALLEGRO_DISPLAY *d,
1325 int x, int y, int width, int height)
1326 {
1327 if (al_get_opengl_extension_list()->ALLEGRO_WGL_WIN_swap_hint) {
1328 /* FIXME: This is just a driver hint and there is no guarantee that the
1329 * contens of the front buffer outside the given rectangle will be preserved,
1330 * thus we should really return false here and do nothing. */
1331 ALLEGRO_DISPLAY_WGL* disp = (ALLEGRO_DISPLAY_WGL*)d;
1332 wglAddSwapHintRectWIN(x, y, width, height);
1333 glFlush();
1334 SwapBuffers(disp->dc);
1335 return;
1336 }
1337 wgl_flip_display(d);
1338 }
1339
1340
wgl_resize_helper(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB,ALLEGRO_DISPLAY * d,int width,int height)1341 static bool wgl_resize_helper(_ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB, ALLEGRO_DISPLAY *d, int width, int height)
1342 {
1343 ALLEGRO_DISPLAY_WGL *wgl_disp = (ALLEGRO_DISPLAY_WGL *)d;
1344 ALLEGRO_DISPLAY_WIN *win_disp = (ALLEGRO_DISPLAY_WIN *)d;
1345 int full_w, full_h;
1346 ALLEGRO_MONITOR_INFO mi;
1347 int adapter = al_get_new_display_adapter();
1348 if (adapter < 0)
1349 adapter = 0;
1350 al_get_monitor_info(adapter, &mi);
1351 full_w = mi.x2 - mi.x1;
1352 full_h = mi.y2 - mi.y1;
1353
1354 if ((d->flags & ALLEGRO_FULLSCREEN_WINDOW) && (full_w != width || full_h != height)) {
1355 win_disp->toggle_w = width;
1356 win_disp->toggle_h = height;
1357 return true;
1358 }
1359
1360 win_disp->can_acknowledge = false;
1361
1362 if (d->flags & ALLEGRO_FULLSCREEN) {
1363 ALLEGRO_BITMAP *target_bmp;
1364 _AL_VECTOR disp_bmps;
1365 bool was_backbuffer = false;
1366 size_t i;
1367
1368 target_bmp = al_get_target_bitmap();
1369 if (target_bmp && target_bmp->vt) {
1370 ALLEGRO_BITMAP_EXTRA_OPENGL *extra = target_bmp->parent ?
1371 target_bmp->parent->extra : target_bmp->extra;
1372 was_backbuffer = extra->is_backbuffer;
1373 }
1374
1375 /* Remember display bitmaps. */
1376 _al_vector_init(&disp_bmps, sizeof(ALLEGRO_BITMAP*));
1377 for (i = 0; i < _al_vector_size(&d->bitmaps); i++) {
1378 ALLEGRO_BITMAP **dis = _al_vector_ref(&d->bitmaps, i);
1379 ALLEGRO_BITMAP **mem = _al_vector_alloc_back(&disp_bmps);
1380 *mem = *dis;
1381 }
1382
1383 /* This flag prevents from switching to desktop resolution in between. */
1384 _wgl_do_not_change_display_mode = true;
1385 destroy_display_internals(wgl_disp);
1386 _wgl_do_not_change_display_mode = false;
1387
1388 d->w = width;
1389 d->h = height;
1390 if(!create_display_internals(_wglGetExtensionsStringARB, wgl_disp))
1391 return false;
1392
1393 /* We have a new backbuffer now. */
1394 if (was_backbuffer)
1395 al_set_target_bitmap(al_get_backbuffer(d));
1396
1397 /* Reupload bitmaps. */
1398 while (_al_vector_is_nonempty(&disp_bmps)) {
1399 ALLEGRO_BITMAP **back = _al_vector_ref_back(&disp_bmps);
1400 _al_convert_to_display_bitmap(*back);
1401 _al_vector_delete_at(&disp_bmps, _al_vector_size(&disp_bmps) - 1);
1402 }
1403 }
1404 else {
1405 RECT win_size;
1406 WINDOWINFO wi;
1407
1408 win_size.left = 0;
1409 win_size.top = 0;
1410 win_size.right = width;
1411 win_size.bottom = height;
1412
1413 wi.cbSize = sizeof(WINDOWINFO);
1414 GetWindowInfo(win_disp->window, &wi);
1415
1416 AdjustWindowRectEx(&win_size, wi.dwStyle, GetMenu(win_disp->window) ? TRUE : FALSE, wi.dwExStyle);
1417
1418 if (!SetWindowPos(win_disp->window, HWND_TOP,
1419 0, 0,
1420 win_size.right - win_size.left,
1421 win_size.bottom - win_size.top,
1422 SWP_NOMOVE|SWP_NOZORDER))
1423 return false;
1424
1425 d->w = width;
1426 d->h = height;
1427 if (!(d->flags & ALLEGRO_FULLSCREEN_WINDOW)) {
1428 win_disp->toggle_w = width;
1429 win_disp->toggle_h = height;
1430 }
1431 }
1432
1433 return true;
1434 }
1435
wgl_resize_display(ALLEGRO_DISPLAY * d,int width,int height)1436 static bool wgl_resize_display(ALLEGRO_DISPLAY *d, int width, int height)
1437 {
1438 ALLEGRO_DISPLAY_WIN *win_display = (ALLEGRO_DISPLAY_WIN *)d;
1439 int orig_w = d->w;
1440 int orig_h = d->h;
1441 bool ret;
1442
1443 win_display->ignore_resize = true;
1444
1445 _ALLEGRO_wglGetExtensionsStringARB_t _wglGetExtensionsStringARB
1446 = (_ALLEGRO_wglGetExtensionsStringARB_t)wglGetProcAddress("wglGetExtensionsStringARB");
1447 if (!wgl_resize_helper(_wglGetExtensionsStringARB, d, width, height)) {
1448 wgl_resize_helper(_wglGetExtensionsStringARB, d, orig_w, orig_h);
1449 ret = false;
1450 } else {
1451 ret = true;
1452 wgl_acknowledge_resize(d);
1453 }
1454
1455 win_display->ignore_resize = false;
1456
1457 return ret;
1458 }
1459
wgl_acknowledge_resize(ALLEGRO_DISPLAY * d)1460 static bool wgl_acknowledge_resize(ALLEGRO_DISPLAY *d)
1461 {
1462 WINDOWINFO wi;
1463 ALLEGRO_DISPLAY_WIN *win_disp = (ALLEGRO_DISPLAY_WIN *)d;
1464 int w, h;
1465 ALLEGRO_STATE state;
1466
1467 wi.cbSize = sizeof(WINDOWINFO);
1468 GetWindowInfo(win_disp->window, &wi);
1469 w = wi.rcClient.right - wi.rcClient.left;
1470 h = wi.rcClient.bottom - wi.rcClient.top;
1471
1472 d->w = w;
1473 d->h = h;
1474
1475 _al_ogl_setup_gl(d);
1476 _al_ogl_update_render_state(d);
1477
1478 al_store_state(&state, ALLEGRO_STATE_DISPLAY | ALLEGRO_STATE_TARGET_BITMAP);
1479 al_set_target_backbuffer(d);
1480 al_set_clipping_rectangle(0, 0, w, h);
1481 al_restore_state(&state);
1482
1483 return true;
1484 }
1485
1486
wgl_is_compatible_bitmap(ALLEGRO_DISPLAY * display,ALLEGRO_BITMAP * bitmap)1487 static bool wgl_is_compatible_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap)
1488 {
1489 /* Note: WGL driver doesn't support sharing of resources between contexts,
1490 * thus all bitmaps are tied to the display which was current at the time
1491 * al_create_bitmap was called.
1492 */
1493 return display == _al_get_bitmap_display(bitmap);
1494 }
1495
1496
wgl_switch_in(ALLEGRO_DISPLAY * display)1497 static void wgl_switch_in(ALLEGRO_DISPLAY *display)
1498 {
1499 (void)display;
1500 /*
1501 ALLEGRO_DISPLAY_WIN *win_disp = (ALLEGRO_DISPLAY_WIN *)display;
1502
1503 if (al_is_mouse_installed())
1504 al_set_mouse_range(win_disp->mouse_range_x1, win_disp->mouse_range_y1,
1505 win_disp->mouse_range_x2, win_disp->mouse_range_y2);
1506 */
1507 }
1508
1509
wgl_switch_out(ALLEGRO_DISPLAY * display)1510 static void wgl_switch_out(ALLEGRO_DISPLAY *display)
1511 {
1512 (void)display;
1513 }
1514
1515
wgl_set_window_position(ALLEGRO_DISPLAY * display,int x,int y)1516 static void wgl_set_window_position(ALLEGRO_DISPLAY *display, int x, int y)
1517 {
1518 _al_win_set_window_position(((ALLEGRO_DISPLAY_WIN *)display)->window, x, y);
1519 }
1520
1521
wgl_get_window_position(ALLEGRO_DISPLAY * display,int * x,int * y)1522 static void wgl_get_window_position(ALLEGRO_DISPLAY *display, int *x, int *y)
1523 {
1524 _al_win_get_window_position(((ALLEGRO_DISPLAY_WIN *)display)->window, x, y);
1525 }
1526
1527
1528 /* Obtain a reference to this driver. */
_al_display_wgl_driver(void)1529 ALLEGRO_DISPLAY_INTERFACE *_al_display_wgl_driver(void)
1530 {
1531 if (vt.create_display)
1532 return &vt;
1533
1534 vt.create_display = wgl_create_display;
1535 vt.destroy_display = wgl_destroy_display;
1536 vt.resize_display = wgl_resize_display;
1537 vt.set_current_display = wgl_set_current_display;
1538 vt.unset_current_display = wgl_unset_current_display;
1539 vt.flip_display = wgl_flip_display;
1540 vt.update_display_region = wgl_update_display_region;
1541 vt.acknowledge_resize = wgl_acknowledge_resize;
1542 vt.create_bitmap = _al_ogl_create_bitmap;
1543 vt.get_backbuffer = _al_ogl_get_backbuffer;
1544 vt.set_target_bitmap = _al_ogl_set_target_bitmap;
1545 vt.is_compatible_bitmap = wgl_is_compatible_bitmap;
1546 vt.switch_in = wgl_switch_in;
1547 vt.switch_out = wgl_switch_out;
1548
1549 vt.set_mouse_cursor = _al_win_set_mouse_cursor;
1550 vt.set_system_mouse_cursor = _al_win_set_system_mouse_cursor;
1551 vt.show_mouse_cursor = _al_win_show_mouse_cursor;
1552 vt.hide_mouse_cursor = _al_win_hide_mouse_cursor;
1553
1554 vt.set_icons = _al_win_set_display_icons;
1555 vt.set_window_position = wgl_set_window_position;
1556 vt.get_window_position = wgl_get_window_position;
1557 vt.set_window_constraints = _al_win_set_window_constraints;
1558 vt.get_window_constraints = _al_win_get_window_constraints;
1559 vt.apply_window_constraints = _al_win_apply_window_constraints;
1560 vt.set_display_flag = _al_win_set_display_flag;
1561 vt.set_window_title = _al_win_set_window_title;
1562
1563 vt.update_render_state = _al_ogl_update_render_state;
1564 _al_ogl_add_drawing_functions(&vt);
1565 _al_win_add_clipboard_functions(&vt);
1566
1567 return &vt;
1568 }
1569
_al_wgl_get_num_display_modes(int format,int refresh_rate,int flags)1570 int _al_wgl_get_num_display_modes(int format, int refresh_rate, int flags)
1571 {
1572 DEVMODE dm;
1573 int count = 0;
1574
1575 /* FIXME: Ignoring format.
1576 * To get a list of pixel formats we have to create a window with a valid DC, which
1577 * would even require to change the video mode in fullscreen cases and we really
1578 * don't want to do that.
1579 */
1580 (void)format;
1581 (void)refresh_rate;
1582 (void)flags;
1583
1584 memset(&dm, 0, sizeof(dm));
1585 dm.dmSize = sizeof(dm);
1586
1587 while (EnumDisplaySettings(NULL, count, &dm) != false) {
1588 count++;
1589 }
1590
1591 return count;
1592 }
1593
1594
_al_wgl_get_display_mode(int index,int format,int refresh_rate,int flags,ALLEGRO_DISPLAY_MODE * mode)1595 ALLEGRO_DISPLAY_MODE *_al_wgl_get_display_mode(int index, int format,
1596 int refresh_rate, int flags,
1597 ALLEGRO_DISPLAY_MODE *mode)
1598 {
1599 DEVMODE dm;
1600
1601 /*
1602 * FIXME: see the comment in _al_wgl_get_num_display_modes
1603 */
1604 (void)format;
1605 (void)refresh_rate;
1606 (void)flags;
1607
1608 memset(&dm, 0, sizeof(dm));
1609 dm.dmSize = sizeof(dm);
1610
1611 if (!EnumDisplaySettings(NULL, index, &dm))
1612 return NULL;
1613
1614 mode->width = dm.dmPelsWidth;
1615 mode->height = dm.dmPelsHeight;
1616 mode->refresh_rate = dm.dmDisplayFrequency;
1617 mode->format = format;
1618 switch (dm.dmBitsPerPel) {
1619 case 32:
1620 if (format == ALLEGRO_PIXEL_FORMAT_ANY)
1621 mode->format = ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA;
1622 else if (format == ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA)
1623 mode->format = ALLEGRO_PIXEL_FORMAT_ANY_32_NO_ALPHA;
1624 break;
1625 case 24:
1626 mode->format = ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA;
1627 break;
1628 case 16:
1629 if (format == ALLEGRO_PIXEL_FORMAT_ANY)
1630 mode->format = ALLEGRO_PIXEL_FORMAT_ANY_16_WITH_ALPHA;
1631 else if(format == ALLEGRO_PIXEL_FORMAT_ANY_NO_ALPHA)
1632 mode->format = ALLEGRO_PIXEL_FORMAT_ANY_16_NO_ALPHA;
1633 break;
1634 default:
1635 break;
1636 }
1637
1638 return mode;
1639 }
1640
1641 /* vi: set sts=3 sw=3 et: */
1642
1643