00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "glxGraphicsPipe.h"
00020 #include "glxGraphicsWindow.h"
00021 #include "glxGraphicsStateGuardian.h"
00022 #include "config_glxdisplay.h"
00023 #include "frameBufferProperties.h"
00024 #include "mutexHolder.h"
00025
00026 #include <GL/glx.h>
00027
00028 TypeHandle glxGraphicsPipe::_type_handle;
00029
00030 bool glxGraphicsPipe::_error_handlers_installed = false;
00031 glxGraphicsPipe::ErrorHandlerFunc *glxGraphicsPipe::_prev_error_handler;
00032 glxGraphicsPipe::IOErrorHandlerFunc *glxGraphicsPipe::_prev_io_error_handler;
00033
00034
00035
00036
00037
00038
00039 glxGraphicsPipe::
00040 glxGraphicsPipe(const string &display) {
00041 string display_spec = display;
00042 if (display_spec.empty()) {
00043 display_spec = display_cfg;
00044 }
00045 if (display_spec.empty()) {
00046 display_spec = ExecutionEnvironment::get_environment_variable("DISPLAY");
00047 }
00048
00049 _is_valid = false;
00050 _supports_fullscreen = false;
00051 _display = NULL;
00052 _screen = 0;
00053 _root = (Window)NULL;
00054
00055 install_error_handlers();
00056
00057 _display = XOpenDisplay(display_spec.c_str());
00058 if (!_display) {
00059 glxdisplay_cat.error()
00060 << "Could not open display \"" << display_spec << "\".\n";
00061 return;
00062 }
00063
00064 int errorBase, eventBase;
00065 if (!glXQueryExtension(_display, &errorBase, &eventBase)) {
00066 glxdisplay_cat.error()
00067 << "OpenGL GLX extension not supported on display \"" << display_spec
00068 << "\".\n";
00069 return;
00070 }
00071
00072 _screen = DefaultScreen(_display);
00073 _root = RootWindow(_display, _screen);
00074 _display_width = DisplayWidth(_display, _screen);
00075 _display_height = DisplayHeight(_display, _screen);
00076 _is_valid = true;
00077
00078
00079 _wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", false);
00080 }
00081
00082
00083
00084
00085
00086
00087 glxGraphicsPipe::
00088 ~glxGraphicsPipe() {
00089 if (_display) {
00090 XCloseDisplay(_display);
00091 }
00092 }
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 string glxGraphicsPipe::
00105 get_interface_name() const {
00106 return "OpenGL";
00107 }
00108
00109
00110
00111
00112
00113
00114
00115
00116 PT(GraphicsPipe) glxGraphicsPipe::
00117 pipe_constructor() {
00118 return new glxGraphicsPipe;
00119 }
00120
00121
00122
00123
00124
00125
00126
00127
00128 PT(GraphicsStateGuardian) glxGraphicsPipe::
00129 make_gsg(const FrameBufferProperties &properties) {
00130 if (!_is_valid) {
00131 return NULL;
00132 }
00133
00134 FrameBufferProperties new_properties = properties;
00135 XVisualInfo *visual = choose_visual(new_properties);
00136
00137
00138 GLXContext context = glXCreateContext(_display, visual, None, GL_TRUE);
00139 if (context == NULL) {
00140 glxdisplay_cat.error()
00141 << "Could not create GL context.\n";
00142 XFree(visual);
00143 return NULL;
00144 }
00145
00146
00147 PT(glxGraphicsStateGuardian) gsg =
00148 new glxGraphicsStateGuardian(new_properties);
00149 gsg->_context = context;
00150 gsg->_visual = visual;
00151 gsg->_display = _display;
00152
00153 return gsg.p();
00154 }
00155
00156
00157
00158
00159
00160
00161 PT(GraphicsWindow) glxGraphicsPipe::
00162 make_window(GraphicsStateGuardian *gsg) {
00163 if (!_is_valid) {
00164 return NULL;
00165 }
00166
00167 return new glxGraphicsWindow(this, gsg);
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 XVisualInfo *glxGraphicsPipe::
00181 choose_visual(FrameBufferProperties &properties) const {
00182 int frame_buffer_mode = 0;
00183 int want_depth_bits = 0;
00184 int want_color_bits = 0;
00185
00186 if (properties.has_frame_buffer_mode()) {
00187 frame_buffer_mode = properties.get_frame_buffer_mode();
00188 }
00189
00190 if (properties.has_depth_bits()) {
00191 want_depth_bits = properties.get_depth_bits();
00192 }
00193
00194 if (properties.has_color_bits()) {
00195 want_color_bits = properties.get_color_bits();
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 XVisualInfo *visual =
00209 try_for_visual(frame_buffer_mode, want_depth_bits, want_color_bits);
00210
00211
00212
00213
00214 NotifySeverity show_visual_severity = NS_debug;
00215
00216 if (visual == NULL) {
00217 glxdisplay_cat.info()
00218 << "glxGraphicsWindow::choose_visual() - visual with requested\n"
00219 << " capabilities not found; trying for lesser visual.\n";
00220
00221
00222
00223
00224
00225 show_visual_severity = NS_info;
00226
00227 bool special_size_request =
00228 (want_depth_bits != 1 || want_color_bits != 1);
00229
00230
00231
00232
00233
00234
00235 if (special_size_request) {
00236
00237
00238
00239 visual = try_for_visual(frame_buffer_mode, 1, 1);
00240 }
00241
00242 if (visual == NULL) {
00243
00244
00245
00246
00247
00248
00249 static const int strip_properties[] = {
00250
00251 FrameBufferProperties::FM_multisample,
00252 FrameBufferProperties::FM_stencil,
00253 FrameBufferProperties::FM_accum,
00254 FrameBufferProperties::FM_alpha,
00255 FrameBufferProperties::FM_stereo,
00256
00257
00258 FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_multisample,
00259 FrameBufferProperties::FM_accum | FrameBufferProperties::FM_multisample,
00260 FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_multisample,
00261 FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
00262 FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum,
00263 FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo,
00264 FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_multisample,
00265 FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
00266
00267
00268 FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
00269
00270
00271
00272 FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample | FrameBufferProperties::FM_double_buffer,
00273
00274
00275 0
00276 };
00277
00278 pset<int> tried_masks;
00279 tried_masks.insert(frame_buffer_mode);
00280
00281 int i;
00282 for (i = 0; visual == NULL && strip_properties[i] != 0; i++) {
00283 int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
00284 if (tried_masks.insert(new_frame_buffer_mode).second) {
00285 visual = try_for_visual(new_frame_buffer_mode, want_depth_bits,
00286 want_color_bits);
00287 }
00288 }
00289
00290 if (special_size_request) {
00291 tried_masks.clear();
00292 tried_masks.insert(frame_buffer_mode);
00293
00294 if (visual == NULL) {
00295
00296
00297 for (i = 0; visual == NULL && strip_properties[i] != 0; i++) {
00298 int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
00299 if (tried_masks.insert(new_frame_buffer_mode).second) {
00300 visual = try_for_visual(new_frame_buffer_mode, 1, 1);
00301 }
00302 }
00303 }
00304 }
00305
00306 if (visual == NULL) {
00307
00308
00309 visual = try_for_visual(0, 1, 1);
00310 }
00311
00312 if (visual == NULL) {
00313 glxdisplay_cat.error()
00314 << "Could not get any GLX visual.\n";
00315 return NULL;
00316 }
00317 }
00318 }
00319
00320 glxdisplay_cat.info()
00321 << "Got visual 0x" << hex << (int)visual->visualid << dec << ".\n";
00322
00323
00324 int render_mode, double_buffer, stereo, red_size, green_size, blue_size,
00325 alpha_size, ared_size, agreen_size, ablue_size, aalpha_size,
00326 depth_size, stencil_size;
00327
00328 glXGetConfig(_display, visual, GLX_RGBA, &render_mode);
00329 glXGetConfig(_display, visual, GLX_DOUBLEBUFFER, &double_buffer);
00330 glXGetConfig(_display, visual, GLX_STEREO, &stereo);
00331 glXGetConfig(_display, visual, GLX_RED_SIZE, &red_size);
00332 glXGetConfig(_display, visual, GLX_GREEN_SIZE, &green_size);
00333 glXGetConfig(_display, visual, GLX_BLUE_SIZE, &blue_size);
00334 glXGetConfig(_display, visual, GLX_ALPHA_SIZE, &alpha_size);
00335 glXGetConfig(_display, visual, GLX_ACCUM_RED_SIZE, &ared_size);
00336 glXGetConfig(_display, visual, GLX_ACCUM_GREEN_SIZE, &agreen_size);
00337 glXGetConfig(_display, visual, GLX_ACCUM_BLUE_SIZE, &ablue_size);
00338 glXGetConfig(_display, visual, GLX_ACCUM_ALPHA_SIZE, &aalpha_size);
00339 glXGetConfig(_display, visual, GLX_DEPTH_SIZE, &depth_size);
00340 glXGetConfig(_display, visual, GLX_STENCIL_SIZE, &stencil_size);
00341
00342 frame_buffer_mode = 0;
00343 if (double_buffer) {
00344 frame_buffer_mode |= FrameBufferProperties::FM_double_buffer;
00345 }
00346 if (stereo) {
00347 frame_buffer_mode |= FrameBufferProperties::FM_stereo;
00348 }
00349 if (!render_mode) {
00350 frame_buffer_mode |= FrameBufferProperties::FM_index;
00351 }
00352 if (stencil_size != 0) {
00353 frame_buffer_mode |= FrameBufferProperties::FM_stencil;
00354 }
00355 if (depth_size != 0) {
00356 frame_buffer_mode |= FrameBufferProperties::FM_depth;
00357 }
00358 if (alpha_size != 0) {
00359 frame_buffer_mode |= FrameBufferProperties::FM_alpha;
00360 }
00361 if (ared_size + agreen_size + ablue_size != 0) {
00362 frame_buffer_mode |= FrameBufferProperties::FM_accum;
00363 }
00364
00365 properties.set_frame_buffer_mode(frame_buffer_mode);
00366 properties.set_color_bits(red_size + green_size + blue_size + alpha_size);
00367 properties.set_depth_bits(depth_size);
00368
00369 if (glxdisplay_cat.is_on(show_visual_severity)) {
00370 glxdisplay_cat.out(show_visual_severity)
00371 << "GLX Visual Info (# bits of each):" << endl
00372 << " RGBA: " << red_size << " " << green_size << " " << blue_size
00373 << " " << alpha_size << endl
00374 << " Accum RGBA: " << ared_size << " " << agreen_size << " "
00375 << ablue_size << " " << aalpha_size << endl
00376 << " Depth: " << depth_size << endl
00377 << " Stencil: " << stencil_size << endl
00378 << " DoubleBuffer? " << double_buffer << endl
00379 << " Stereo? " << stereo << endl;
00380 }
00381
00382 return visual;
00383 }
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 XVisualInfo *glxGraphicsPipe::
00394 try_for_visual(int framebuffer_mode,
00395 int want_depth_bits, int want_color_bits) const {
00396 static const int max_attrib_list = 32;
00397 int attrib_list[max_attrib_list];
00398 int n=0;
00399
00400 glxdisplay_cat.debug()
00401 << "Trying for visual with: RGB(" << want_color_bits << ")";
00402
00403 int want_color_component_bits;
00404 if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
00405 want_color_component_bits = max(want_color_bits / 4, 1);
00406 } else {
00407 want_color_component_bits = max(want_color_bits / 3, 1);
00408 }
00409
00410 attrib_list[n++] = GLX_RGBA;
00411 attrib_list[n++] = GLX_RED_SIZE;
00412 attrib_list[n++] = want_color_component_bits;
00413 attrib_list[n++] = GLX_GREEN_SIZE;
00414 attrib_list[n++] = want_color_component_bits;
00415 attrib_list[n++] = GLX_BLUE_SIZE;
00416 attrib_list[n++] = want_color_component_bits;
00417
00418 if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
00419 glxdisplay_cat.debug(false) << " ALPHA";
00420 attrib_list[n++] = GLX_ALPHA_SIZE;
00421 attrib_list[n++] = want_color_component_bits;
00422 }
00423 if (framebuffer_mode & FrameBufferProperties::FM_double_buffer) {
00424 glxdisplay_cat.debug(false) << " DOUBLEBUFFER";
00425 attrib_list[n++] = GLX_DOUBLEBUFFER;
00426 }
00427 if (framebuffer_mode & FrameBufferProperties::FM_stereo) {
00428 glxdisplay_cat.debug(false) << " STEREO";
00429 attrib_list[n++] = GLX_STEREO;
00430 }
00431 if (framebuffer_mode & FrameBufferProperties::FM_depth) {
00432 glxdisplay_cat.debug(false) << " DEPTH(" << want_depth_bits << ")";
00433 attrib_list[n++] = GLX_DEPTH_SIZE;
00434 attrib_list[n++] = want_depth_bits;
00435 }
00436 if (framebuffer_mode & FrameBufferProperties::FM_stencil) {
00437 glxdisplay_cat.debug(false) << " STENCIL";
00438 attrib_list[n++] = GLX_STENCIL_SIZE;
00439 attrib_list[n++] = 1;
00440 }
00441 if (framebuffer_mode & FrameBufferProperties::FM_accum) {
00442 glxdisplay_cat.debug(false) << " ACCUM";
00443 attrib_list[n++] = GLX_ACCUM_RED_SIZE;
00444 attrib_list[n++] = want_color_component_bits;
00445 attrib_list[n++] = GLX_ACCUM_GREEN_SIZE;
00446 attrib_list[n++] = want_color_component_bits;
00447 attrib_list[n++] = GLX_ACCUM_BLUE_SIZE;
00448 attrib_list[n++] = want_color_component_bits;
00449 if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
00450 attrib_list[n++] = GLX_ACCUM_ALPHA_SIZE;
00451 attrib_list[n++] = want_color_component_bits;
00452 }
00453 }
00454 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
00455 if (framebuffer_mode & FrameBufferProperties::FM_multisample) {
00456 glxdisplay_cat.debug(false) << " MULTISAMPLE";
00457 attrib_list[n++] = GLX_SAMPLES_SGIS;
00458
00459 attrib_list[n++] = 4;
00460 }
00461 #endif
00462
00463
00464 nassertr(n < max_attrib_list, NULL);
00465 attrib_list[n] = (int)None;
00466
00467 XVisualInfo *vinfo = glXChooseVisual(_display, _screen, attrib_list);
00468
00469 if (glxdisplay_cat.is_debug()) {
00470 if (vinfo != NULL) {
00471 glxdisplay_cat.debug(false) << ", match found!\n";
00472 } else {
00473 glxdisplay_cat.debug(false) << ", no match.\n";
00474 }
00475 }
00476
00477 return vinfo;
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491 void glxGraphicsPipe::
00492 install_error_handlers() {
00493 if (_error_handlers_installed) {
00494 return;
00495 }
00496
00497 _prev_error_handler = (ErrorHandlerFunc *)XSetErrorHandler(error_handler);
00498 _prev_io_error_handler = (IOErrorHandlerFunc *)XSetIOErrorHandler(io_error_handler);
00499 _error_handlers_installed = true;
00500 }
00501
00502
00503
00504
00505
00506
00507
00508 int glxGraphicsPipe::
00509 error_handler(Display *display, XErrorEvent *error) {
00510 static const int msg_len = 80;
00511 char msg[msg_len];
00512 XGetErrorText(display, error->error_code, msg, msg_len);
00513 glxdisplay_cat.error()
00514 << msg << "\n";
00515
00516
00517
00518 return 0;
00519 }
00520
00521
00522
00523
00524
00525
00526
00527 int glxGraphicsPipe::
00528 io_error_handler(Display *display) {
00529 glxdisplay_cat.fatal()
00530 << "X fatal error on display " << (void *)display << "\n";
00531
00532
00533
00534
00535
00536 return 0;
00537 }