AllegroGL 0.4.4
|
00001 /* This code is (C) AllegroGL contributors, and double licensed under 00002 * the GPL and zlib licenses. See gpl.txt or zlib.txt for details. 00003 */ 00004 /*---------------------------------------------------------------- 00005 * amesa.c -- Allegro-Mesa interfacing 00006 *---------------------------------------------------------------- 00007 * This is the interface module for use AllegroGL with Mesa using the AMesa driver. 00008 */ 00009 #include <string.h> 00010 00011 #include <GL/gl.h> 00012 #include <GL/amesa.h> 00013 00014 #include <allegro.h> 00015 #include <allegro/internal/aintern.h> 00016 00017 #include "alleggl.h" 00018 #include "allglint.h" 00019 #include "glvtable.h" 00020 00021 00022 static void allegro_gl_amesa_exit(BITMAP *bmp); 00023 static void __allegro_gl_init_texture_read_format(void); 00024 00025 #ifdef GFX_OPENGL_FULLSCREEN 00026 static BITMAP *allegro_gl_amesa_fullscreen_init(int w, int h, int vw, int vh, int color_depth); 00027 00028 GFX_DRIVER gfx_allegro_gl_fullscreen = 00029 { 00030 GFX_OPENGL_FULLSCREEN, 00031 empty_string, 00032 empty_string, 00033 "AllegroGL Fullscreen (AMesa)", 00034 allegro_gl_amesa_fullscreen_init, 00035 allegro_gl_amesa_exit, 00036 NULL, 00037 NULL, //_xwin_vsync, 00038 NULL, 00039 NULL, NULL, NULL, 00040 allegro_gl_create_video_bitmap, 00041 allegro_gl_destroy_video_bitmap, 00042 NULL, NULL, /* No show/request video bitmaps */ 00043 NULL, NULL, 00044 allegro_gl_set_mouse_sprite, 00045 allegro_gl_show_mouse, 00046 allegro_gl_hide_mouse, 00047 allegro_gl_move_mouse, 00048 NULL, 00049 NULL, NULL, 00050 NULL, /* No fetch_mode_list */ 00051 0, 0, 00052 0, 00053 0, 0, 00054 0, 00055 0, 00056 FALSE /* Windowed mode */ 00057 }; 00058 #endif /* GFX_OPENGL_FULLSCREEN */ 00059 00060 00061 #ifdef GFX_OPENGL_WINDOWED 00062 static BITMAP *allegro_gl_amesa_windowed_init(int w, int h, int vw, int vh, int color_depth); 00063 00064 GFX_DRIVER gfx_allegro_gl_windowed = 00065 { 00066 GFX_OPENGL_WINDOWED, 00067 empty_string, 00068 empty_string, 00069 "AllegroGL Windowed (AMesa)", 00070 allegro_gl_amesa_windowed_init, 00071 allegro_gl_amesa_exit, 00072 NULL, 00073 NULL, //_xwin_vsync, 00074 NULL, 00075 NULL, NULL, NULL, 00076 allegro_gl_create_video_bitmap, 00077 allegro_gl_destroy_video_bitmap, 00078 NULL, NULL, /* No show/request video bitmaps */ 00079 NULL, NULL, 00080 allegro_gl_set_mouse_sprite, 00081 allegro_gl_show_mouse, 00082 allegro_gl_hide_mouse, 00083 allegro_gl_move_mouse, 00084 NULL, 00085 NULL, NULL, 00086 NULL, /* No fetch_mode_list */ 00087 0, 0, 00088 0, 00089 0, 0, 00090 0, 00091 0, 00092 TRUE /* Windowed mode */ 00093 }; 00094 #endif /* GFX_OPENGL_WINDOWED */ 00095 00096 00097 00098 static int allegro_gl_amesa_create_window (int fullscreen); 00099 static BITMAP *allegro_gl_amesa_create_screen_bitmap (GFX_DRIVER *drv, int w, int h, int depth); 00100 00101 struct AMESA_DATA { 00102 int fullscreen; 00103 AMesaVisual visual; 00104 AMesaBuffer buffer; 00105 AMesaContext context; 00106 } AMESA_DATA; 00107 00108 static struct AMESA_DATA _amesa; 00109 static struct allegro_gl_driver allegro_gl_amesa; 00110 00111 static BITMAP* subscreen = NULL; /* Sub_bitmap of the virtual screen */ 00112 static BITMAP* saved_screen = NULL; /* Saves screen address */ 00113 00114 GFX_DRIVER *amesa_gfx_driver = NULL; 00115 00116 static GFX_VTABLE allegro_gl_generic_vtable; 00117 static GFX_VTABLE *old_vtable; 00118 00119 00120 00121 /* allegro_gl_amesa_create_screen: 00122 * Creates screen bitmap. 00123 */ 00124 static BITMAP *allegro_gl_amesa_create_screen(int w, int h, int vw, int vh, int depth, int fullscreen) 00125 { 00126 int _keyboard_was_installed = FALSE; 00127 int _mouse_was_installed = FALSE; 00128 GFX_VTABLE vtable, *pvtable; 00129 00130 pvtable = &vtable; 00131 00132 if (keyboard_driver) { 00133 _keyboard_was_installed = TRUE; 00134 remove_keyboard(); 00135 TRACE("* Note * amesa_create_screen: Removing Keyboard...\n"); 00136 } 00137 00138 if (mouse_driver) { 00139 _mouse_was_installed = TRUE; 00140 remove_mouse(); 00141 TRACE("* Note * amesa_create_screen: Removing Mouse...\n"); 00142 } 00143 00144 if ((w == 0) && (h == 0)) { 00145 w = 640; 00146 h = 480; 00147 } 00148 00149 if ((vw > w) || (vh > h)) { 00150 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, 00151 get_config_text ("OpenGL drivers do not support virtual screens")); 00152 return NULL; 00153 } 00154 00155 allegro_gl_display_info.w = w; 00156 allegro_gl_display_info.h = h; 00157 00158 if (allegro_gl_amesa_create_window(fullscreen)) { 00159 if (fullscreen) { 00160 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, 00161 get_config_text ("Unable to switch in AMesa fullscreen")); 00162 } 00163 else { 00164 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, 00165 get_config_text ("Unable to create AMesa window")); 00166 } 00167 return NULL; 00168 } 00169 00170 /* If pixel format is Allegro compatible, set up Allegro correctly. */ 00171 00172 if (fullscreen) { 00173 #ifdef GFX_OPENGL_FULLSCREEN 00174 allegro_gl_screen = allegro_gl_amesa_create_screen_bitmap (&gfx_allegro_gl_fullscreen, w, h, allegro_gl_display_info.colour_depth); 00175 #endif 00176 } 00177 else { 00178 #ifdef GFX_OPENGL_WINDOWED 00179 allegro_gl_screen = allegro_gl_amesa_create_screen_bitmap (&gfx_allegro_gl_windowed, w, h, allegro_gl_display_info.colour_depth); 00180 #endif 00181 } 00182 00183 if (!allegro_gl_screen) { 00184 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, 00185 get_config_text ("Error creating screen bitmap")); 00186 return NULL; 00187 } 00188 00189 __allegro_gl_valid_context = TRUE; 00190 __allegro_gl_driver = &allegro_gl_amesa; 00191 LOCK_DATA(&_amesa, sizeof(AMESA_DATA)); 00192 LOCK_DATA(__allegro_gl_driver, sizeof(struct allegro_gl_driver)); 00193 00194 /* save the old vtable and create a copy */ 00195 old_vtable = allegro_gl_screen->vtable; 00196 memcpy(&allegro_gl_generic_vtable, allegro_gl_screen->vtable, 00197 sizeof(GFX_VTABLE)); 00198 allegro_gl_screen->vtable = &allegro_gl_generic_vtable; 00199 00200 /* The generic driver does not use the glvtable (since it already uses 00201 * 'pure' Allegro gfx functions. However it needs the AGL-specific 00202 * draw_glyph method. 00203 * Hence this hack : we call __allegro_gl__glvtable_update_vtable with 00204 * 'pvtable' as a parameter since we do not want the regular 00205 * allegro_gl_screen->vtable to be crushed. 00206 */ 00207 __allegro_gl__glvtable_update_vtable(&pvtable); 00208 allegro_gl_screen->vtable->draw_glyph = pvtable->draw_glyph; 00209 memcpy(&_screen_vtable, allegro_gl_screen->vtable, sizeof(GFX_VTABLE)); 00210 allegro_gl_screen->vtable = &_screen_vtable; 00211 __allegro_gl_init_screen_mode(); 00212 00213 /* Print out OpenGL version info */ 00214 TRACE("\n\nOpenGL Version: %s\nVendor: %s\nRenderer: %s\n", 00215 (const char*)glGetString(GL_VERSION), 00216 (const char*)glGetString(GL_VENDOR), 00217 (const char*)glGetString(GL_RENDERER)); 00218 00219 /* Prints out OpenGL extensions info and activates needed extensions */ 00220 __allegro_gl_manage_extensions(); 00221 __allegro_gl_init_texture_read_format(); 00222 00223 if (_keyboard_was_installed) { 00224 install_keyboard(); 00225 TRACE("* Note * amesa_create_screen: Installing Keyboard...\n"); 00226 } 00227 00228 if (_mouse_was_installed) { 00229 install_mouse(); 00230 TRACE("* Note * amesa_create_screen: Installing Mouse...\n"); 00231 } 00232 00233 /* XXX <rohannessian> Maybe we should leave this for autodetection? */ 00234 gfx_capabilities |= GFX_HW_CURSOR; 00235 00236 allegro_gl_info.is_mesa_driver = TRUE; 00237 _amesa.fullscreen = fullscreen; 00238 return allegro_gl_screen; 00239 } 00240 00241 00242 00243 #ifdef GFX_OPENGL_WINDOWED 00244 /* allegro_gl_amesa_windowed_init: 00245 * Creates screen bitmap for windowed driver. 00246 */ 00247 static BITMAP *allegro_gl_amesa_windowed_init(int w, int h, int vw, int vh, int depth) 00248 { 00249 return allegro_gl_amesa_create_screen(w, h, vw, vh, depth, FALSE); 00250 } 00251 #endif 00252 00253 00254 00255 #ifdef GFX_OPENGL_FULLSCREEN 00256 /* allegro_gl_amesa_fullscreen_init: 00257 * Creates screen bitmap for fullscreen driver. 00258 */ 00259 static BITMAP *allegro_gl_amesa_fullscreen_init(int w, int h, int vw, int vh, int depth) 00260 { 00261 return allegro_gl_amesa_create_screen(w, h, vw, vh, depth, TRUE); 00262 } 00263 #endif 00264 00265 00266 00267 /* allegro_gl_amesa_exit: 00268 * Shuts down the driver (shared between windowed and full-screen) 00269 */ 00270 static void allegro_gl_amesa_exit(BITMAP *bmp) 00271 { 00272 /* Restore the screen to its intial value */ 00273 screen = saved_screen; 00274 if (subscreen) 00275 destroy_bitmap(subscreen); 00276 00277 amesa_gfx_driver->exit(screen); 00278 00279 AMesaMakeCurrent(_amesa.context, NULL); 00280 AMesaDestroyVisual(_amesa.visual); 00281 AMesaDestroyBuffer(_amesa.buffer); 00282 AMesaDestroyContext(_amesa.context); 00283 00284 __allegro_gl_valid_context = FALSE; 00285 } 00286 00287 00288 00289 static void amesa_choose_gfx_mode(_DRIVER_INFO *driver_info, int *w, int *h, 00290 int *colour_depth) 00291 { 00292 GFX_MODE_LIST *mode_list; 00293 GFX_MODE *mode; 00294 int i; 00295 00296 TRACE("* Note * amesa_choose_gfx_mode: GFX driver : %s\n", 00297 ((GFX_DRIVER*)driver_info->driver)->ascii_name); 00298 00299 /* Try to find a mode which resolution and color depth are higher or 00300 * equal to those requested 00301 */ 00302 mode_list = get_gfx_mode_list(driver_info->id); 00303 00304 if (mode_list) { 00305 TRACE("* Note * amesa_choose_gfx_mode: %i modes\n", 00306 mode_list->num_modes); 00307 00308 mode = mode_list->mode; 00309 00310 for (i = 0; i < mode_list->num_modes; i++) { 00311 TRACE("Mode %i : %ix%i %i bpp\n", i, mode->width, mode->height, 00312 mode->bpp); 00313 if ((mode->width >= *w) && (mode->height >= *h) && 00314 (mode->bpp >= *colour_depth)) { 00315 break; 00316 } 00317 if (mode->width) { 00318 mode++; 00319 } 00320 } 00321 if ((mode->width) && (mode->height) && (mode->bpp)) { 00322 allegro_gl_display_info.w = *w = mode->width; 00323 allegro_gl_display_info.h = *h = mode->height; 00324 allegro_gl_display_info.colour_depth = *colour_depth = mode->bpp; 00325 } 00326 TRACE("Best Mode : %ix%i %i bpp\n", *w, *h, *colour_depth); 00327 destroy_gfx_mode_list(mode_list); 00328 } 00329 else { 00330 TRACE("** Warning ** amesa_choose_gfx_mode: Can not list modes...\n" 00331 "Trying %ix%i %i bpp anyway\n", *w, *h, *colour_depth); 00332 } 00333 } 00334 00335 00336 00337 /* amesa_set_gfx_mode : 00338 * A light version of set_gfx_mode since when this function is reached we are 00339 * ALREADY in set_gfx_mode. No need to initialize some parameters. 00340 * Moreover we must choose our driver in saved_gfx_drivers and set the real 00341 * gfx driver (i.e. the GFX_OPENGL one) the right way. 00342 */ 00343 static int amesa_set_gfx_mode(int fullscreen) 00344 { 00345 extern void blit_end(); 00346 _DRIVER_INFO *driver_list; 00347 int tried = FALSE; 00348 char buf[512], tmp[64]; 00349 int c, n; 00350 int card = GFX_AUTODETECT; 00351 int w = allegro_gl_display_info.w; 00352 int h = allegro_gl_display_info.h; 00353 int check_mode = TRUE, require_window = FALSE; 00354 00355 driver_list = saved_gfx_drivers(); 00356 00357 if (!fullscreen) 00358 require_window = TRUE; 00359 00360 /* try the drivers that are listed in the config file */ 00361 for (n=-2; n<255; n++) { 00362 switch (n) { 00363 00364 case -2: 00365 /* example: gfx_card_640x480x16 = */ 00366 usprintf(buf, uconvert_ascii("gfx_card_%dx%dx%d", tmp), w, h, 00367 _color_depth); 00368 break; 00369 00370 case -1: 00371 /* example: gfx_card_24bpp = */ 00372 usprintf(buf, uconvert_ascii("gfx_card_%dbpp", tmp), 00373 _color_depth); 00374 break; 00375 00376 case 0: 00377 /* example: gfx_card = */ 00378 ustrcpy(buf, uconvert_ascii("gfx_card", tmp)); 00379 break; 00380 00381 default: 00382 /* example: gfx_card1 = */ 00383 usprintf(buf, uconvert_ascii("gfx_card%d", tmp), n); 00384 break; 00385 } 00386 card = get_config_id(uconvert_ascii("graphics", tmp), buf, 00387 GFX_AUTODETECT); 00388 00389 if (card != GFX_AUTODETECT) { 00390 00391 for (c=0; driver_list[c].driver; c++) { 00392 if (driver_list[c].id == card) { 00393 amesa_gfx_driver = driver_list[c].driver; 00394 00395 if (check_mode) { 00396 if ( ((require_window) && (!amesa_gfx_driver->windowed)) 00397 || ((!require_window) 00398 && (amesa_gfx_driver->windowed))) { 00399 00400 amesa_gfx_driver = NULL; 00401 continue; 00402 } 00403 } 00404 break; 00405 } 00406 } 00407 00408 if (amesa_gfx_driver) { 00409 tried = TRUE; 00410 amesa_gfx_driver->name = amesa_gfx_driver->desc 00411 = get_config_text(amesa_gfx_driver->ascii_name); 00412 00413 amesa_choose_gfx_mode(&driver_list[c], &w, &h, &_color_depth); 00414 00415 screen = amesa_gfx_driver->init(w, h, 0, 0, _color_depth); 00416 if (screen) { 00417 break; 00418 } 00419 else { 00420 amesa_gfx_driver = NULL; 00421 } 00422 } 00423 } 00424 else { 00425 if (n > 1) { 00426 break; 00427 } 00428 } 00429 } 00430 00431 if (!tried) { 00432 for (c=0; driver_list[c].driver; c++) { 00433 00434 if (driver_list[c].autodetect) { 00435 00436 amesa_gfx_driver = driver_list[c].driver; 00437 if (check_mode) { 00438 if (((require_window) && (!amesa_gfx_driver->windowed)) || 00439 ((!require_window) && (amesa_gfx_driver->windowed))) 00440 continue; 00441 } 00442 00443 amesa_gfx_driver->name = amesa_gfx_driver->desc 00444 = get_config_text(amesa_gfx_driver->ascii_name); 00445 00446 amesa_choose_gfx_mode(&driver_list[c], &w, &h, &_color_depth); 00447 00448 screen = amesa_gfx_driver->init(w, h, 0, 0, _color_depth); 00449 00450 if (screen) { 00451 break; 00452 } 00453 } 00454 } 00455 } 00456 00457 if (!screen) { 00458 amesa_gfx_driver = NULL; 00459 return -1; 00460 } 00461 00462 LOCK_DATA(amesa_gfx_driver, sizeof(GFX_DRIVER)); 00463 _register_switch_bitmap(screen, NULL); 00464 00465 return 0; 00466 } 00467 00468 00469 00470 /* create_window: 00471 * Based on Bernhard Tschirren AMesa GLUT code. 00472 */ 00473 static int allegro_gl_amesa_create_window (int fullscreen) 00474 { 00475 if (!allegro_gl_display_info.colour_depth) 00476 allegro_gl_display_info.colour_depth = _color_depth; 00477 00478 set_color_depth(allegro_gl_display_info.colour_depth); 00479 00480 if (amesa_set_gfx_mode(fullscreen)) { 00481 TRACE("** ERROR ** amesa_create_window: Unable to set a gfx mode!\n"); 00482 return 1; 00483 } 00484 00485 _amesa.visual = AMesaCreateVisual(allegro_gl_display_info.doublebuffered, 00486 allegro_gl_display_info.colour_depth, 00487 GL_TRUE, /* RGBA Mode */ 00488 allegro_gl_display_info.depth_size, 00489 allegro_gl_display_info.stencil_size, 00490 allegro_gl_display_info.accum_size.rgba.r, 00491 allegro_gl_display_info.accum_size.rgba.g, 00492 allegro_gl_display_info.accum_size.rgba.b, 00493 allegro_gl_display_info.accum_size.rgba.a 00494 ); 00495 if (!_amesa.visual) { 00496 TRACE("** ERROR ** amesa_create_window: Unable to create AMesa " 00497 "Visual\n"); 00498 return 1; 00499 } 00500 00501 _amesa.context = AMesaCreateContext(_amesa.visual, NULL); 00502 if (!_amesa.context) { 00503 TRACE("** ERROR ** amesa_create_window: Unable to create AMesa " 00504 "Context\n"); 00505 AMesaDestroyVisual(_amesa.visual); 00506 return 1; 00507 } 00508 00509 if ((screen->w != allegro_gl_display_info.w) 00510 || (screen->h != allegro_gl_display_info.h)) { 00511 00512 subscreen = create_sub_bitmap(screen, 0, 0, 00513 allegro_gl_display_info.w, allegro_gl_display_info.h); 00514 00515 _amesa.buffer = AMesaCreateBuffer(_amesa.visual, subscreen); 00516 00517 TRACE("** Note ** amesa_create_window: Screen : %ix%i %i bpp\n", 00518 ubscreen->w, subscreen->h, bitmap_color_depth(subscreen)); 00519 } 00520 else { 00521 _amesa.buffer = AMesaCreateBuffer(_amesa.visual, screen); 00522 } 00523 00524 if (!_amesa.buffer) { 00525 AMesaDestroyContext(_amesa.context); 00526 AMesaDestroyVisual(_amesa.visual); 00527 TRACE("** ERROR ** amesa_create_window: Unable to create AMesa " 00528 "Buffer\n"); 00529 return 1; 00530 } 00531 00532 if (!AMesaMakeCurrent(_amesa.context, _amesa.buffer)) { 00533 AMesaDestroyContext(_amesa.context); 00534 AMesaDestroyVisual(_amesa.visual); 00535 AMesaDestroyBuffer(_amesa.buffer); 00536 TRACE("** ERROR ** amesa_create_window: Unable to make context " 00537 "current\n"); 00538 return 1; 00539 } 00540 00541 saved_screen = screen; 00542 return 0; 00543 } 00544 00545 00546 00547 static BITMAP *allegro_gl_amesa_create_screen_bitmap (GFX_DRIVER *drv, 00548 int w, int h, int depth) 00549 { 00550 drv->w = w; 00551 drv->h = h; 00552 drv->linear = amesa_gfx_driver->linear; 00553 drv->bank_size = amesa_gfx_driver->bank_size; 00554 drv->bank_gran = amesa_gfx_driver->bank_gran; 00555 drv->vid_mem = amesa_gfx_driver->vid_mem; 00556 drv->vid_phys_base = amesa_gfx_driver->vid_phys_base; 00557 00558 return AMesaGetColorBuffer(_amesa.buffer, AMESA_ACTIVE); 00559 } 00560 00561 00562 00563 static void __allegro_gl_init_texture_read_format(void) 00564 { 00565 /* 8 bpp (true color mode) */ 00566 __allegro_gl_texture_read_format[0] = GL_UNSIGNED_BYTE_3_3_2; 00567 00568 /* 15 bpp */ 00569 if (_rgb_r_shift_15 > _rgb_b_shift_15) { 00570 __allegro_gl_texture_read_format[1] = GL_UNSIGNED_SHORT_5_5_5_1; 00571 if (_rgb_r_shift_15 == 10) { 00572 __allegro_gl_texture_components[1] = GL_BGRA; 00573 } 00574 } 00575 else { 00576 __allegro_gl_texture_read_format[1] = GL_UNSIGNED_SHORT_1_5_5_5_REV; 00577 } 00578 00579 /* 16 bpp */ 00580 if (_rgb_r_shift_16 > _rgb_b_shift_16) { 00581 __allegro_gl_texture_read_format[2] = GL_UNSIGNED_SHORT_5_6_5; 00582 } 00583 else { 00584 __allegro_gl_texture_read_format[2] = GL_UNSIGNED_SHORT_5_6_5_REV; 00585 } 00586 00587 /* 24 bpp */ 00588 __allegro_gl_texture_read_format[3] = GL_UNSIGNED_BYTE; 00589 00590 /* 32 bpp */ 00591 if (_rgb_r_shift_32 > _rgb_b_shift_32) { 00592 __allegro_gl_texture_read_format[4] = GL_UNSIGNED_INT_8_8_8_8_REV; 00593 if (_rgb_r_shift_32 == 16) { 00594 __allegro_gl_texture_components[4] = GL_BGRA; 00595 } 00596 } 00597 else { 00598 __allegro_gl_texture_read_format[4] = GL_UNSIGNED_BYTE; 00599 } 00600 } 00601 00602 00603 00604 /******************************/ 00605 /* AllegroGL driver functions */ 00606 /******************************/ 00607 00608 /* flip: 00609 * Does a page flip / double buffer copy / whatever it really is. 00610 */ 00611 static void amesa_flip (void) 00612 { 00613 AMesaSwapBuffers (_amesa.buffer); 00614 } 00615 00616 00617 00618 /* gl_on, gl_off: 00619 * Switches to/from GL mode. 00620 */ 00621 static void amesa_gl_on (void) 00622 { 00623 } 00624 00625 00626 00627 static void amesa_gl_off (void) 00628 { 00629 } 00630 00631 00632 00633 /*****************/ 00634 /* Driver struct */ 00635 /*****************/ 00636 00637 static struct allegro_gl_driver allegro_gl_amesa = { 00638 amesa_flip, 00639 amesa_gl_on, 00640 amesa_gl_off 00641 }; 00642