1 /* This code is (C) AllegroGL contributors, and double licensed under
2 * the GPL and zlib licenses. See gpl.txt or zlib.txt for details.
3 */
4 /*----------------------------------------------------------------
5 * amesa.c -- Allegro-Mesa interfacing
6 *----------------------------------------------------------------
7 * This is the interface module for use AllegroGL with Mesa using the AMesa driver.
8 */
9 #include <string.h>
10
11 #include <GL/gl.h>
12 #include <GL/amesa.h>
13
14 #include <allegro.h>
15 #include <allegro/internal/aintern.h>
16
17 #include "alleggl.h"
18 #include "allglint.h"
19 #include "glvtable.h"
20
21
22 static void allegro_gl_amesa_exit(BITMAP *bmp);
23 static void __allegro_gl_init_texture_read_format(void);
24
25 #ifdef GFX_OPENGL_FULLSCREEN
26 static BITMAP *allegro_gl_amesa_fullscreen_init(int w, int h, int vw, int vh, int color_depth);
27
28 GFX_DRIVER gfx_allegro_gl_fullscreen =
29 {
30 GFX_OPENGL_FULLSCREEN,
31 empty_string,
32 empty_string,
33 "AllegroGL Fullscreen (AMesa)",
34 allegro_gl_amesa_fullscreen_init,
35 allegro_gl_amesa_exit,
36 NULL,
37 NULL, //_xwin_vsync,
38 NULL,
39 NULL, NULL, NULL,
40 allegro_gl_create_video_bitmap,
41 allegro_gl_destroy_video_bitmap,
42 NULL, NULL, /* No show/request video bitmaps */
43 NULL, NULL,
44 allegro_gl_set_mouse_sprite,
45 allegro_gl_show_mouse,
46 allegro_gl_hide_mouse,
47 allegro_gl_move_mouse,
48 NULL,
49 NULL, NULL,
50 NULL, /* No fetch_mode_list */
51 0, 0,
52 0,
53 0, 0,
54 0,
55 0,
56 FALSE /* Windowed mode */
57 };
58 #endif /* GFX_OPENGL_FULLSCREEN */
59
60
61 #ifdef GFX_OPENGL_WINDOWED
62 static BITMAP *allegro_gl_amesa_windowed_init(int w, int h, int vw, int vh, int color_depth);
63
64 GFX_DRIVER gfx_allegro_gl_windowed =
65 {
66 GFX_OPENGL_WINDOWED,
67 empty_string,
68 empty_string,
69 "AllegroGL Windowed (AMesa)",
70 allegro_gl_amesa_windowed_init,
71 allegro_gl_amesa_exit,
72 NULL,
73 NULL, //_xwin_vsync,
74 NULL,
75 NULL, NULL, NULL,
76 allegro_gl_create_video_bitmap,
77 allegro_gl_destroy_video_bitmap,
78 NULL, NULL, /* No show/request video bitmaps */
79 NULL, NULL,
80 allegro_gl_set_mouse_sprite,
81 allegro_gl_show_mouse,
82 allegro_gl_hide_mouse,
83 allegro_gl_move_mouse,
84 NULL,
85 NULL, NULL,
86 NULL, /* No fetch_mode_list */
87 0, 0,
88 0,
89 0, 0,
90 0,
91 0,
92 TRUE /* Windowed mode */
93 };
94 #endif /* GFX_OPENGL_WINDOWED */
95
96
97
98 static int allegro_gl_amesa_create_window (int fullscreen);
99 static BITMAP *allegro_gl_amesa_create_screen_bitmap (GFX_DRIVER *drv, int w, int h, int depth);
100
101 struct AMESA_DATA {
102 int fullscreen;
103 AMesaVisual visual;
104 AMesaBuffer buffer;
105 AMesaContext context;
106 } AMESA_DATA;
107
108 static struct AMESA_DATA _amesa;
109 static struct allegro_gl_driver allegro_gl_amesa;
110
111 static BITMAP* subscreen = NULL; /* Sub_bitmap of the virtual screen */
112 static BITMAP* saved_screen = NULL; /* Saves screen address */
113
114 GFX_DRIVER *amesa_gfx_driver = NULL;
115
116 static GFX_VTABLE allegro_gl_generic_vtable;
117 static GFX_VTABLE *old_vtable;
118
119
120
121 /* allegro_gl_amesa_create_screen:
122 * Creates screen bitmap.
123 */
allegro_gl_amesa_create_screen(int w,int h,int vw,int vh,int depth,int fullscreen)124 static BITMAP *allegro_gl_amesa_create_screen(int w, int h, int vw, int vh, int depth, int fullscreen)
125 {
126 int _keyboard_was_installed = FALSE;
127 int _mouse_was_installed = FALSE;
128 GFX_VTABLE vtable, *pvtable;
129
130 pvtable = &vtable;
131
132 if (keyboard_driver) {
133 _keyboard_was_installed = TRUE;
134 remove_keyboard();
135 TRACE("* Note * amesa_create_screen: Removing Keyboard...\n");
136 }
137
138 if (mouse_driver) {
139 _mouse_was_installed = TRUE;
140 remove_mouse();
141 TRACE("* Note * amesa_create_screen: Removing Mouse...\n");
142 }
143
144 if ((w == 0) && (h == 0)) {
145 w = 640;
146 h = 480;
147 }
148
149 if ((vw > w) || (vh > h)) {
150 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
151 get_config_text ("OpenGL drivers do not support virtual screens"));
152 return NULL;
153 }
154
155 allegro_gl_display_info.w = w;
156 allegro_gl_display_info.h = h;
157
158 if (allegro_gl_amesa_create_window(fullscreen)) {
159 if (fullscreen) {
160 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
161 get_config_text ("Unable to switch in AMesa fullscreen"));
162 }
163 else {
164 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
165 get_config_text ("Unable to create AMesa window"));
166 }
167 return NULL;
168 }
169
170 /* If pixel format is Allegro compatible, set up Allegro correctly. */
171
172 if (fullscreen) {
173 #ifdef GFX_OPENGL_FULLSCREEN
174 allegro_gl_screen = allegro_gl_amesa_create_screen_bitmap (&gfx_allegro_gl_fullscreen, w, h, allegro_gl_display_info.colour_depth);
175 #endif
176 }
177 else {
178 #ifdef GFX_OPENGL_WINDOWED
179 allegro_gl_screen = allegro_gl_amesa_create_screen_bitmap (&gfx_allegro_gl_windowed, w, h, allegro_gl_display_info.colour_depth);
180 #endif
181 }
182
183 if (!allegro_gl_screen) {
184 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
185 get_config_text ("Error creating screen bitmap"));
186 return NULL;
187 }
188
189 __allegro_gl_valid_context = TRUE;
190 __allegro_gl_driver = &allegro_gl_amesa;
191 LOCK_DATA(&_amesa, sizeof(AMESA_DATA));
192 LOCK_DATA(__allegro_gl_driver, sizeof(struct allegro_gl_driver));
193
194 /* save the old vtable and create a copy */
195 old_vtable = allegro_gl_screen->vtable;
196 memcpy(&allegro_gl_generic_vtable, allegro_gl_screen->vtable,
197 sizeof(GFX_VTABLE));
198 allegro_gl_screen->vtable = &allegro_gl_generic_vtable;
199
200 /* The generic driver does not use the glvtable (since it already uses
201 * 'pure' Allegro gfx functions. However it needs the AGL-specific
202 * draw_glyph method.
203 * Hence this hack : we call __allegro_gl__glvtable_update_vtable with
204 * 'pvtable' as a parameter since we do not want the regular
205 * allegro_gl_screen->vtable to be crushed.
206 */
207 __allegro_gl__glvtable_update_vtable(&pvtable);
208 allegro_gl_screen->vtable->draw_glyph = pvtable->draw_glyph;
209 memcpy(&_screen_vtable, allegro_gl_screen->vtable, sizeof(GFX_VTABLE));
210 allegro_gl_screen->vtable = &_screen_vtable;
211 __allegro_gl_init_screen_mode();
212
213 /* Print out OpenGL version info */
214 TRACE("\n\nOpenGL Version: %s\nVendor: %s\nRenderer: %s\n",
215 (const char*)glGetString(GL_VERSION),
216 (const char*)glGetString(GL_VENDOR),
217 (const char*)glGetString(GL_RENDERER));
218
219 /* Prints out OpenGL extensions info and activates needed extensions */
220 __allegro_gl_manage_extensions();
221 __allegro_gl_init_texture_read_format();
222
223 if (_keyboard_was_installed) {
224 install_keyboard();
225 TRACE("* Note * amesa_create_screen: Installing Keyboard...\n");
226 }
227
228 if (_mouse_was_installed) {
229 install_mouse();
230 TRACE("* Note * amesa_create_screen: Installing Mouse...\n");
231 }
232
233 /* XXX <rohannessian> Maybe we should leave this for autodetection? */
234 gfx_capabilities |= GFX_HW_CURSOR;
235
236 allegro_gl_info.is_mesa_driver = TRUE;
237 _amesa.fullscreen = fullscreen;
238 return allegro_gl_screen;
239 }
240
241
242
243 #ifdef GFX_OPENGL_WINDOWED
244 /* allegro_gl_amesa_windowed_init:
245 * Creates screen bitmap for windowed driver.
246 */
allegro_gl_amesa_windowed_init(int w,int h,int vw,int vh,int depth)247 static BITMAP *allegro_gl_amesa_windowed_init(int w, int h, int vw, int vh, int depth)
248 {
249 return allegro_gl_amesa_create_screen(w, h, vw, vh, depth, FALSE);
250 }
251 #endif
252
253
254
255 #ifdef GFX_OPENGL_FULLSCREEN
256 /* allegro_gl_amesa_fullscreen_init:
257 * Creates screen bitmap for fullscreen driver.
258 */
allegro_gl_amesa_fullscreen_init(int w,int h,int vw,int vh,int depth)259 static BITMAP *allegro_gl_amesa_fullscreen_init(int w, int h, int vw, int vh, int depth)
260 {
261 return allegro_gl_amesa_create_screen(w, h, vw, vh, depth, TRUE);
262 }
263 #endif
264
265
266
267 /* allegro_gl_amesa_exit:
268 * Shuts down the driver (shared between windowed and full-screen)
269 */
allegro_gl_amesa_exit(BITMAP * bmp)270 static void allegro_gl_amesa_exit(BITMAP *bmp)
271 {
272 /* Restore the screen to its intial value */
273 screen = saved_screen;
274 if (subscreen)
275 destroy_bitmap(subscreen);
276
277 amesa_gfx_driver->exit(screen);
278
279 AMesaMakeCurrent(_amesa.context, NULL);
280 AMesaDestroyVisual(_amesa.visual);
281 AMesaDestroyBuffer(_amesa.buffer);
282 AMesaDestroyContext(_amesa.context);
283
284 __allegro_gl_valid_context = FALSE;
285 }
286
287
288
amesa_choose_gfx_mode(_DRIVER_INFO * driver_info,int * w,int * h,int * colour_depth)289 static void amesa_choose_gfx_mode(_DRIVER_INFO *driver_info, int *w, int *h,
290 int *colour_depth)
291 {
292 GFX_MODE_LIST *mode_list;
293 GFX_MODE *mode;
294 int i;
295
296 TRACE("* Note * amesa_choose_gfx_mode: GFX driver : %s\n",
297 ((GFX_DRIVER*)driver_info->driver)->ascii_name);
298
299 /* Try to find a mode which resolution and color depth are higher or
300 * equal to those requested
301 */
302 mode_list = get_gfx_mode_list(driver_info->id);
303
304 if (mode_list) {
305 TRACE("* Note * amesa_choose_gfx_mode: %i modes\n",
306 mode_list->num_modes);
307
308 mode = mode_list->mode;
309
310 for (i = 0; i < mode_list->num_modes; i++) {
311 TRACE("Mode %i : %ix%i %i bpp\n", i, mode->width, mode->height,
312 mode->bpp);
313 if ((mode->width >= *w) && (mode->height >= *h) &&
314 (mode->bpp >= *colour_depth)) {
315 break;
316 }
317 if (mode->width) {
318 mode++;
319 }
320 }
321 if ((mode->width) && (mode->height) && (mode->bpp)) {
322 allegro_gl_display_info.w = *w = mode->width;
323 allegro_gl_display_info.h = *h = mode->height;
324 allegro_gl_display_info.colour_depth = *colour_depth = mode->bpp;
325 }
326 TRACE("Best Mode : %ix%i %i bpp\n", *w, *h, *colour_depth);
327 destroy_gfx_mode_list(mode_list);
328 }
329 else {
330 TRACE("** Warning ** amesa_choose_gfx_mode: Can not list modes...\n"
331 "Trying %ix%i %i bpp anyway\n", *w, *h, *colour_depth);
332 }
333 }
334
335
336
337 /* amesa_set_gfx_mode :
338 * A light version of set_gfx_mode since when this function is reached we are
339 * ALREADY in set_gfx_mode. No need to initialize some parameters.
340 * Moreover we must choose our driver in saved_gfx_drivers and set the real
341 * gfx driver (i.e. the GFX_OPENGL one) the right way.
342 */
amesa_set_gfx_mode(int fullscreen)343 static int amesa_set_gfx_mode(int fullscreen)
344 {
345 extern void blit_end();
346 _DRIVER_INFO *driver_list;
347 int tried = FALSE;
348 char buf[512], tmp[64];
349 int c, n;
350 int card = GFX_AUTODETECT;
351 int w = allegro_gl_display_info.w;
352 int h = allegro_gl_display_info.h;
353 int check_mode = TRUE, require_window = FALSE;
354
355 driver_list = saved_gfx_drivers();
356
357 if (!fullscreen)
358 require_window = TRUE;
359
360 /* try the drivers that are listed in the config file */
361 for (n=-2; n<255; n++) {
362 switch (n) {
363
364 case -2:
365 /* example: gfx_card_640x480x16 = */
366 usprintf(buf, uconvert_ascii("gfx_card_%dx%dx%d", tmp), w, h,
367 _color_depth);
368 break;
369
370 case -1:
371 /* example: gfx_card_24bpp = */
372 usprintf(buf, uconvert_ascii("gfx_card_%dbpp", tmp),
373 _color_depth);
374 break;
375
376 case 0:
377 /* example: gfx_card = */
378 ustrcpy(buf, uconvert_ascii("gfx_card", tmp));
379 break;
380
381 default:
382 /* example: gfx_card1 = */
383 usprintf(buf, uconvert_ascii("gfx_card%d", tmp), n);
384 break;
385 }
386 card = get_config_id(uconvert_ascii("graphics", tmp), buf,
387 GFX_AUTODETECT);
388
389 if (card != GFX_AUTODETECT) {
390
391 for (c=0; driver_list[c].driver; c++) {
392 if (driver_list[c].id == card) {
393 amesa_gfx_driver = driver_list[c].driver;
394
395 if (check_mode) {
396 if ( ((require_window) && (!amesa_gfx_driver->windowed))
397 || ((!require_window)
398 && (amesa_gfx_driver->windowed))) {
399
400 amesa_gfx_driver = NULL;
401 continue;
402 }
403 }
404 break;
405 }
406 }
407
408 if (amesa_gfx_driver) {
409 tried = TRUE;
410 amesa_gfx_driver->name = amesa_gfx_driver->desc
411 = get_config_text(amesa_gfx_driver->ascii_name);
412
413 amesa_choose_gfx_mode(&driver_list[c], &w, &h, &_color_depth);
414
415 screen = amesa_gfx_driver->init(w, h, 0, 0, _color_depth);
416 if (screen) {
417 break;
418 }
419 else {
420 amesa_gfx_driver = NULL;
421 }
422 }
423 }
424 else {
425 if (n > 1) {
426 break;
427 }
428 }
429 }
430
431 if (!tried) {
432 for (c=0; driver_list[c].driver; c++) {
433
434 if (driver_list[c].autodetect) {
435
436 amesa_gfx_driver = driver_list[c].driver;
437 if (check_mode) {
438 if (((require_window) && (!amesa_gfx_driver->windowed)) ||
439 ((!require_window) && (amesa_gfx_driver->windowed)))
440 continue;
441 }
442
443 amesa_gfx_driver->name = amesa_gfx_driver->desc
444 = get_config_text(amesa_gfx_driver->ascii_name);
445
446 amesa_choose_gfx_mode(&driver_list[c], &w, &h, &_color_depth);
447
448 screen = amesa_gfx_driver->init(w, h, 0, 0, _color_depth);
449
450 if (screen) {
451 break;
452 }
453 }
454 }
455 }
456
457 if (!screen) {
458 amesa_gfx_driver = NULL;
459 return -1;
460 }
461
462 LOCK_DATA(amesa_gfx_driver, sizeof(GFX_DRIVER));
463 _register_switch_bitmap(screen, NULL);
464
465 return 0;
466 }
467
468
469
470 /* create_window:
471 * Based on Bernhard Tschirren AMesa GLUT code.
472 */
allegro_gl_amesa_create_window(int fullscreen)473 static int allegro_gl_amesa_create_window (int fullscreen)
474 {
475 if (!allegro_gl_display_info.colour_depth)
476 allegro_gl_display_info.colour_depth = _color_depth;
477
478 set_color_depth(allegro_gl_display_info.colour_depth);
479
480 if (amesa_set_gfx_mode(fullscreen)) {
481 TRACE("** ERROR ** amesa_create_window: Unable to set a gfx mode!\n");
482 return 1;
483 }
484
485 _amesa.visual = AMesaCreateVisual(allegro_gl_display_info.doublebuffered,
486 allegro_gl_display_info.colour_depth,
487 GL_TRUE, /* RGBA Mode */
488 allegro_gl_display_info.depth_size,
489 allegro_gl_display_info.stencil_size,
490 allegro_gl_display_info.accum_size.rgba.r,
491 allegro_gl_display_info.accum_size.rgba.g,
492 allegro_gl_display_info.accum_size.rgba.b,
493 allegro_gl_display_info.accum_size.rgba.a
494 );
495 if (!_amesa.visual) {
496 TRACE("** ERROR ** amesa_create_window: Unable to create AMesa "
497 "Visual\n");
498 return 1;
499 }
500
501 _amesa.context = AMesaCreateContext(_amesa.visual, NULL);
502 if (!_amesa.context) {
503 TRACE("** ERROR ** amesa_create_window: Unable to create AMesa "
504 "Context\n");
505 AMesaDestroyVisual(_amesa.visual);
506 return 1;
507 }
508
509 if ((screen->w != allegro_gl_display_info.w)
510 || (screen->h != allegro_gl_display_info.h)) {
511
512 subscreen = create_sub_bitmap(screen, 0, 0,
513 allegro_gl_display_info.w, allegro_gl_display_info.h);
514
515 _amesa.buffer = AMesaCreateBuffer(_amesa.visual, subscreen);
516
517 TRACE("** Note ** amesa_create_window: Screen : %ix%i %i bpp\n",
518 ubscreen->w, subscreen->h, bitmap_color_depth(subscreen));
519 }
520 else {
521 _amesa.buffer = AMesaCreateBuffer(_amesa.visual, screen);
522 }
523
524 if (!_amesa.buffer) {
525 AMesaDestroyContext(_amesa.context);
526 AMesaDestroyVisual(_amesa.visual);
527 TRACE("** ERROR ** amesa_create_window: Unable to create AMesa "
528 "Buffer\n");
529 return 1;
530 }
531
532 if (!AMesaMakeCurrent(_amesa.context, _amesa.buffer)) {
533 AMesaDestroyContext(_amesa.context);
534 AMesaDestroyVisual(_amesa.visual);
535 AMesaDestroyBuffer(_amesa.buffer);
536 TRACE("** ERROR ** amesa_create_window: Unable to make context "
537 "current\n");
538 return 1;
539 }
540
541 saved_screen = screen;
542 return 0;
543 }
544
545
546
allegro_gl_amesa_create_screen_bitmap(GFX_DRIVER * drv,int w,int h,int depth)547 static BITMAP *allegro_gl_amesa_create_screen_bitmap (GFX_DRIVER *drv,
548 int w, int h, int depth)
549 {
550 drv->w = w;
551 drv->h = h;
552 drv->linear = amesa_gfx_driver->linear;
553 drv->bank_size = amesa_gfx_driver->bank_size;
554 drv->bank_gran = amesa_gfx_driver->bank_gran;
555 drv->vid_mem = amesa_gfx_driver->vid_mem;
556 drv->vid_phys_base = amesa_gfx_driver->vid_phys_base;
557
558 return AMesaGetColorBuffer(_amesa.buffer, AMESA_ACTIVE);
559 }
560
561
562
__allegro_gl_init_texture_read_format(void)563 static void __allegro_gl_init_texture_read_format(void)
564 {
565 /* 8 bpp (true color mode) */
566 __allegro_gl_texture_read_format[0] = GL_UNSIGNED_BYTE_3_3_2;
567
568 /* 15 bpp */
569 if (_rgb_r_shift_15 > _rgb_b_shift_15) {
570 __allegro_gl_texture_read_format[1] = GL_UNSIGNED_SHORT_5_5_5_1;
571 if (_rgb_r_shift_15 == 10) {
572 __allegro_gl_texture_components[1] = GL_BGRA;
573 }
574 }
575 else {
576 __allegro_gl_texture_read_format[1] = GL_UNSIGNED_SHORT_1_5_5_5_REV;
577 }
578
579 /* 16 bpp */
580 if (_rgb_r_shift_16 > _rgb_b_shift_16) {
581 __allegro_gl_texture_read_format[2] = GL_UNSIGNED_SHORT_5_6_5;
582 }
583 else {
584 __allegro_gl_texture_read_format[2] = GL_UNSIGNED_SHORT_5_6_5_REV;
585 }
586
587 /* 24 bpp */
588 __allegro_gl_texture_read_format[3] = GL_UNSIGNED_BYTE;
589
590 /* 32 bpp */
591 if (_rgb_r_shift_32 > _rgb_b_shift_32) {
592 __allegro_gl_texture_read_format[4] = GL_UNSIGNED_INT_8_8_8_8_REV;
593 if (_rgb_r_shift_32 == 16) {
594 __allegro_gl_texture_components[4] = GL_BGRA;
595 }
596 }
597 else {
598 __allegro_gl_texture_read_format[4] = GL_UNSIGNED_BYTE;
599 }
600 }
601
602
603
604 /******************************/
605 /* AllegroGL driver functions */
606 /******************************/
607
608 /* flip:
609 * Does a page flip / double buffer copy / whatever it really is.
610 */
amesa_flip(void)611 static void amesa_flip (void)
612 {
613 AMesaSwapBuffers (_amesa.buffer);
614 }
615
616
617
618 /* gl_on, gl_off:
619 * Switches to/from GL mode.
620 */
amesa_gl_on(void)621 static void amesa_gl_on (void)
622 {
623 }
624
625
626
amesa_gl_off(void)627 static void amesa_gl_off (void)
628 {
629 }
630
631
632
633 /*****************/
634 /* Driver struct */
635 /*****************/
636
637 static struct allegro_gl_driver allegro_gl_amesa = {
638 amesa_flip,
639 amesa_gl_on,
640 amesa_gl_off
641 };
642
643