Panda3D
|
00001 // Filename: glxGraphicsStateGuardian.cxx 00002 // Created by: drose (27Jan03) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "glxGraphicsStateGuardian.h" 00016 #include "config_glxdisplay.h" 00017 #include "config_glgsg.h" 00018 #include "lightReMutexHolder.h" 00019 00020 #include <dlfcn.h> 00021 00022 00023 TypeHandle glxGraphicsStateGuardian::_type_handle; 00024 00025 //////////////////////////////////////////////////////////////////// 00026 // Function: glxGraphicsStateGuardian::Constructor 00027 // Access: Public 00028 // Description: 00029 //////////////////////////////////////////////////////////////////// 00030 glxGraphicsStateGuardian:: 00031 glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe, 00032 glxGraphicsStateGuardian *share_with) : 00033 GLGraphicsStateGuardian(engine, pipe) 00034 { 00035 _share_context=0; 00036 _context=0; 00037 _display=0; 00038 _screen=0; 00039 _visual=0; 00040 _visuals=0; 00041 _fbconfig=0; 00042 _context_has_pbuffer = false; 00043 _context_has_pixmap = false; 00044 _slow = false; 00045 00046 _supports_swap_control = false; 00047 _supports_fbconfig = false; 00048 _supports_pbuffer = false; 00049 _uses_sgix_pbuffer = false; 00050 00051 if (share_with != (glxGraphicsStateGuardian *)NULL) { 00052 _prepared_objects = share_with->get_prepared_objects(); 00053 _share_context = share_with->_context; 00054 } 00055 00056 _libgl_handle = NULL; 00057 _checked_get_proc_address = false; 00058 _glXGetProcAddress = NULL; 00059 _temp_context = (GLXContext)NULL; 00060 _temp_xwindow = (Window)NULL; 00061 _temp_colormap = (Colormap)NULL; 00062 } 00063 00064 //////////////////////////////////////////////////////////////////// 00065 // Function: glxGraphicsStateGuardian::Destructor 00066 // Access: Public 00067 // Description: 00068 //////////////////////////////////////////////////////////////////// 00069 glxGraphicsStateGuardian:: 00070 ~glxGraphicsStateGuardian() { 00071 destroy_temp_xwindow(); 00072 if (_visuals != (XVisualInfo *)NULL) { 00073 XFree(_visuals); 00074 } 00075 if (_context != (GLXContext)NULL) { 00076 glXDestroyContext(_display, _context); 00077 _context = (GLXContext)NULL; 00078 } 00079 if (_libgl_handle != (void *)NULL) { 00080 dlclose(_libgl_handle); 00081 } 00082 } 00083 00084 //////////////////////////////////////////////////////////////////// 00085 // Function: glxGraphicsStateGuardian::get_properties 00086 // Access: Public 00087 // Description: Gets the FrameBufferProperties to match the 00088 // indicated visual. 00089 //////////////////////////////////////////////////////////////////// 00090 void glxGraphicsStateGuardian:: 00091 get_properties(FrameBufferProperties &properties, XVisualInfo *visual) { 00092 00093 int use_gl, render_mode, double_buffer, stereo, 00094 red_size, green_size, blue_size, 00095 alpha_size, ared_size, agreen_size, ablue_size, aalpha_size, 00096 depth_size, stencil_size; 00097 00098 glXGetConfig(_display, visual, GLX_USE_GL, &use_gl); 00099 glXGetConfig(_display, visual, GLX_RGBA, &render_mode); 00100 glXGetConfig(_display, visual, GLX_DOUBLEBUFFER, &double_buffer); 00101 glXGetConfig(_display, visual, GLX_STEREO, &stereo); 00102 glXGetConfig(_display, visual, GLX_RED_SIZE, &red_size); 00103 glXGetConfig(_display, visual, GLX_GREEN_SIZE, &green_size); 00104 glXGetConfig(_display, visual, GLX_BLUE_SIZE, &blue_size); 00105 glXGetConfig(_display, visual, GLX_ALPHA_SIZE, &alpha_size); 00106 glXGetConfig(_display, visual, GLX_ACCUM_RED_SIZE, &ared_size); 00107 glXGetConfig(_display, visual, GLX_ACCUM_GREEN_SIZE, &agreen_size); 00108 glXGetConfig(_display, visual, GLX_ACCUM_BLUE_SIZE, &ablue_size); 00109 glXGetConfig(_display, visual, GLX_ACCUM_ALPHA_SIZE, &aalpha_size); 00110 glXGetConfig(_display, visual, GLX_DEPTH_SIZE, &depth_size); 00111 glXGetConfig(_display, visual, GLX_STENCIL_SIZE, &stencil_size); 00112 00113 properties.clear(); 00114 00115 if (use_gl == 0) { 00116 // If we return a set of properties without setting either 00117 // rgb_color or indexed_color, then this indicates a visual 00118 // that's no good for any kind of rendering. 00119 return; 00120 } 00121 00122 if (double_buffer) { 00123 properties.set_back_buffers(1); 00124 } 00125 if (stereo) { 00126 properties.set_stereo(1); 00127 } 00128 if (render_mode) { 00129 properties.set_rgb_color(1); 00130 } else { 00131 properties.set_indexed_color(1); 00132 } 00133 properties.set_color_bits(red_size+green_size+blue_size); 00134 properties.set_stencil_bits(stencil_size); 00135 properties.set_depth_bits(depth_size); 00136 properties.set_alpha_bits(alpha_size); 00137 properties.set_accum_bits(ared_size+agreen_size+ablue_size+aalpha_size); 00138 00139 // Set both hardware and software bits, indicating not-yet-known. 00140 properties.set_force_software(1); 00141 properties.set_force_hardware(1); 00142 } 00143 00144 //////////////////////////////////////////////////////////////////// 00145 // Function: glxGraphicsStateGuardian::get_properties_advanced 00146 // Access: Public 00147 // Description: Gets the FrameBufferProperties to match the 00148 // indicated GLXFBConfig 00149 //////////////////////////////////////////////////////////////////// 00150 void glxGraphicsStateGuardian:: 00151 get_properties_advanced(FrameBufferProperties &properties, 00152 bool &context_has_pbuffer, bool &context_has_pixmap, 00153 bool &slow, GLXFBConfig config) { 00154 properties.clear(); 00155 00156 if (_supports_fbconfig) { 00157 // Now update our framebuffer_mode and bit depth appropriately. 00158 int render_type, double_buffer, stereo, red_size, green_size, blue_size, 00159 alpha_size, ared_size, agreen_size, ablue_size, aalpha_size, 00160 depth_size, stencil_size, samples, drawable_type, caveat; 00161 00162 _glXGetFBConfigAttrib(_display, config, GLX_RENDER_TYPE, &render_type); 00163 _glXGetFBConfigAttrib(_display, config, GLX_DOUBLEBUFFER, &double_buffer); 00164 _glXGetFBConfigAttrib(_display, config, GLX_STEREO, &stereo); 00165 _glXGetFBConfigAttrib(_display, config, GLX_RED_SIZE, &red_size); 00166 _glXGetFBConfigAttrib(_display, config, GLX_GREEN_SIZE, &green_size); 00167 _glXGetFBConfigAttrib(_display, config, GLX_BLUE_SIZE, &blue_size); 00168 _glXGetFBConfigAttrib(_display, config, GLX_ALPHA_SIZE, &alpha_size); 00169 _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_RED_SIZE, &ared_size); 00170 _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_GREEN_SIZE, &agreen_size); 00171 _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_BLUE_SIZE, &ablue_size); 00172 _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_ALPHA_SIZE, &aalpha_size); 00173 _glXGetFBConfigAttrib(_display, config, GLX_DEPTH_SIZE, &depth_size); 00174 _glXGetFBConfigAttrib(_display, config, GLX_STENCIL_SIZE, &stencil_size); 00175 _glXGetFBConfigAttrib(_display, config, GLX_SAMPLES, &samples); 00176 _glXGetFBConfigAttrib(_display, config, GLX_DRAWABLE_TYPE, &drawable_type); 00177 _glXGetFBConfigAttrib(_display, config, GLX_CONFIG_CAVEAT, &caveat); 00178 00179 context_has_pbuffer = false; 00180 if ((drawable_type & GLX_PBUFFER_BIT)!=0) { 00181 context_has_pbuffer = true; 00182 } 00183 00184 context_has_pixmap = false; 00185 if ((drawable_type & GLX_PIXMAP_BIT)!=0) { 00186 context_has_pixmap = true; 00187 } 00188 00189 slow = false; 00190 if (caveat == GLX_SLOW_CONFIG) { 00191 slow = true; 00192 } 00193 00194 if ((drawable_type & GLX_WINDOW_BIT)==0) { 00195 // We insist on having a context that will support an onscreen window. 00196 return; 00197 } 00198 00199 if (double_buffer) { 00200 properties.set_back_buffers(1); 00201 } 00202 if (stereo) { 00203 properties.set_stereo(1); 00204 } 00205 00206 if ((render_type & GLX_RGBA_BIT)!=0) { 00207 properties.set_rgb_color(1); 00208 } 00209 if ((render_type & GLX_COLOR_INDEX_BIT)!=0) { 00210 properties.set_indexed_color(1); 00211 } 00212 properties.set_color_bits(red_size+green_size+blue_size); 00213 properties.set_stencil_bits(stencil_size); 00214 properties.set_depth_bits(depth_size); 00215 properties.set_alpha_bits(alpha_size); 00216 properties.set_accum_bits(ared_size+agreen_size+ablue_size+aalpha_size); 00217 properties.set_multisamples(samples); 00218 00219 // Set both hardware and software bits, indicating not-yet-known. 00220 properties.set_force_software(1); 00221 properties.set_force_hardware(1); 00222 } 00223 } 00224 00225 //////////////////////////////////////////////////////////////////// 00226 // Function: glxGraphicsStateGuardian::choose_pixel_format 00227 // Access: Public 00228 // Description: Selects a visual or fbconfig for all the windows 00229 // and buffers that use this gsg. Also creates the GL 00230 // context and obtains the visual. 00231 //////////////////////////////////////////////////////////////////// 00232 void glxGraphicsStateGuardian:: 00233 choose_pixel_format(const FrameBufferProperties &properties, 00234 Display *display, 00235 int screen, bool need_pbuffer, bool need_pixmap) { 00236 00237 _display = display; 00238 _screen = screen; 00239 _context = 0; 00240 _fbconfig = 0; 00241 _visual = 0; 00242 if (_visuals != (XVisualInfo *)NULL) { 00243 XFree(_visuals); 00244 _visuals = NULL; 00245 } 00246 00247 _fbprops.clear(); 00248 00249 // First, attempt to create a context using the XVisual interface. 00250 // We need this before we can query the FBConfig interface, because 00251 // we need an OpenGL context to get the required extension function 00252 // pointers. 00253 destroy_temp_xwindow(); 00254 choose_temp_visual(properties); 00255 if (_temp_context == NULL) { 00256 // No good. 00257 return; 00258 } 00259 00260 // Now we have to initialize the context so we can query its 00261 // capabilities and extensions. This also means creating a 00262 // temporary window, so we have something to bind the context to and 00263 // make it current. 00264 init_temp_context(); 00265 00266 if (!_supports_fbconfig) { 00267 // We have a good OpenGL context, but it doesn't support the 00268 // FBConfig interface, so we'll stop there. 00269 glxdisplay_cat.debug() 00270 <<" No FBConfig supported; using XVisual only.\n" 00271 << _fbprops << "\n"; 00272 00273 _context = _temp_context; 00274 _temp_context = (GLXContext)NULL; 00275 00276 // By convention, every indirect XVisual that can render to a 00277 // window can also render to a GLXPixmap. Direct visuals we're 00278 // not as sure about. 00279 _context_has_pixmap = !glXIsDirect(_display, _context); 00280 00281 // Pbuffers aren't supported at all with the XVisual interface. 00282 _context_has_pbuffer = false; 00283 return; 00284 } 00285 00286 // The OpenGL context supports the FBConfig interface, so we can use 00287 // that more advanced interface to choose the actual window format 00288 // we'll use. FBConfig provides for more options than the older 00289 // XVisual interface, so we'd much rather use it if it's available. 00290 00291 int best_quality = 0; 00292 int best_result = 0; 00293 FrameBufferProperties best_props; 00294 00295 static const int max_attrib_list = 32; 00296 int attrib_list[max_attrib_list]; 00297 int n = 0; 00298 attrib_list[n++] = GLX_STEREO; 00299 attrib_list[n++] = GLX_DONT_CARE; 00300 attrib_list[n++] = GLX_RENDER_TYPE; 00301 attrib_list[n++] = GLX_DONT_CARE; 00302 attrib_list[n++] = GLX_DRAWABLE_TYPE; 00303 attrib_list[n++] = GLX_DONT_CARE; 00304 attrib_list[n] = (int)None; 00305 00306 int num_configs = 0; 00307 GLXFBConfig *configs = 00308 _glXChooseFBConfig(_display, _screen, attrib_list, &num_configs); 00309 00310 if (configs != 0) { 00311 bool context_has_pbuffer, context_has_pixmap, slow; 00312 int quality, i; 00313 for (i = 0; i < num_configs; ++i) { 00314 FrameBufferProperties fbprops; 00315 get_properties_advanced(fbprops, context_has_pbuffer, context_has_pixmap, 00316 slow, configs[i]); 00317 quality = fbprops.get_quality(properties); 00318 if ((quality > 0)&&(slow)) quality -= 10000000; 00319 if (glxdisplay_cat.is_debug()) { 00320 const char *pbuffertext = context_has_pbuffer ? " (pbuffer)" : ""; 00321 const char *pixmaptext = context_has_pixmap ? " (pixmap)" : ""; 00322 const char *slowtext = slow ? " (slow)" : ""; 00323 glxdisplay_cat.debug() 00324 << i << ": " << fbprops << " quality=" << quality << pbuffertext << pixmaptext << slowtext << "\n"; 00325 } 00326 if (need_pbuffer && !context_has_pbuffer) { 00327 continue; 00328 } 00329 if (need_pixmap && !context_has_pixmap) { 00330 continue; 00331 } 00332 00333 if (quality > best_quality) { 00334 best_quality = quality; 00335 best_result = i; 00336 best_props = fbprops; 00337 } 00338 } 00339 } 00340 00341 if (best_quality > 0) { 00342 _fbconfig = configs[best_result]; 00343 _context = 00344 _glXCreateNewContext(_display, _fbconfig, GLX_RGBA_TYPE, _share_context, 00345 GL_TRUE); 00346 if (_context) { 00347 if (_visuals != (XVisualInfo *)NULL) { 00348 XFree(_visuals); 00349 _visuals = NULL; 00350 } 00351 _visuals = _glXGetVisualFromFBConfig(_display, _fbconfig); 00352 _visual = _visuals; 00353 00354 if (_visual) { 00355 get_properties_advanced(_fbprops, _context_has_pbuffer, _context_has_pixmap, 00356 _slow, _fbconfig); 00357 00358 if (glxdisplay_cat.is_debug()) { 00359 glxdisplay_cat.debug() 00360 << "Selected context " << best_result << ": " << _fbprops << "\n"; 00361 glxdisplay_cat.debug() 00362 << "context_has_pbuffer = " << _context_has_pbuffer 00363 << ", context_has_pixmap = " << _context_has_pixmap << "\n"; 00364 } 00365 00366 return; 00367 } 00368 } 00369 // This really shouldn't happen, so I'm not too careful about cleanup. 00370 glxdisplay_cat.error() 00371 << "Could not create FBConfig context!\n"; 00372 _fbconfig = 0; 00373 _context = 0; 00374 _visual = 0; 00375 _visuals = 0; 00376 } 00377 00378 glxdisplay_cat.warning() 00379 << "No suitable FBConfig contexts available; using XVisual only.\n" 00380 << _fbprops << "\n"; 00381 00382 _context = _temp_context; 00383 _temp_context = (GLXContext)NULL; 00384 00385 // By convention, every indirect XVisual that can render to a 00386 // window can also render to a GLXPixmap. Direct visuals we're 00387 // not as sure about. 00388 _context_has_pixmap = !glXIsDirect(_display, _context); 00389 00390 // Pbuffers aren't supported at all with the XVisual interface. 00391 _context_has_pbuffer = false; 00392 } 00393 00394 //////////////////////////////////////////////////////////////////// 00395 // Function: glxGraphicsStateGuardian::reset 00396 // Access: Public, Virtual 00397 // Description: Resets all internal state as if the gsg were newly 00398 // created. 00399 //////////////////////////////////////////////////////////////////// 00400 void glxGraphicsStateGuardian:: 00401 reset() { 00402 GLGraphicsStateGuardian::reset(); 00403 00404 _supports_swap_control = has_extension("GLX_SGI_swap_control"); 00405 00406 if (_supports_swap_control) { 00407 _glXSwapIntervalSGI = 00408 (PFNGLXSWAPINTERVALSGIPROC)get_extension_func("glX", "SwapIntervalSGI"); 00409 if (_glXSwapIntervalSGI == NULL) { 00410 glxdisplay_cat.error() 00411 << "Driver claims to support GLX_SGI_swap_control extension, but does not define all functions.\n"; 00412 _supports_swap_control = false; 00413 } 00414 } 00415 00416 if (_supports_swap_control) { 00417 // Set the video-sync setting up front, if we have the extension 00418 // that supports it. 00419 _glXSwapIntervalSGI(sync_video ? 1 : 0); 00420 } 00421 00422 if (glx_support_fbconfig) { 00423 if (glx_is_at_least_version(1, 3)) { 00424 // If we have glx 1.3 or better, we have the FBConfig interface. 00425 _supports_fbconfig = true; 00426 00427 _glXChooseFBConfig = 00428 (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfig"); 00429 _glXCreateNewContext = 00430 (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateNewContext"); 00431 _glXGetVisualFromFBConfig = 00432 (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfig"); 00433 _glXGetFBConfigAttrib = 00434 (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttrib"); 00435 _glXCreatePixmap = 00436 (PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreatePixmap"); 00437 00438 if (_glXChooseFBConfig == NULL || 00439 _glXCreateNewContext == NULL || 00440 _glXGetVisualFromFBConfig == NULL || 00441 _glXGetFBConfigAttrib == NULL || 00442 _glXCreatePixmap == NULL) { 00443 glxdisplay_cat.error() 00444 << "Driver claims to support GLX_fbconfig extension, but does not define all functions.\n"; 00445 _supports_fbconfig = false; 00446 } 00447 } else if (has_extension("GLX_SGIX_fbconfig")) { 00448 // Or maybe we have the old SGIX extension for FBConfig. This is 00449 // the same, but the function names are different--we just remap 00450 // them to the same function pointers. 00451 _supports_fbconfig = true; 00452 00453 _glXChooseFBConfig = 00454 (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfigSGIX"); 00455 _glXCreateNewContext = 00456 (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateContextWithConfigSGIX"); 00457 _glXGetVisualFromFBConfig = 00458 (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfigSGIX"); 00459 _glXGetFBConfigAttrib = 00460 (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttribSGIX"); 00461 _glXCreatePixmap = 00462 (PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreateGLXPixmapWithConfigSGIX"); 00463 00464 if (_glXChooseFBConfig == NULL || 00465 _glXCreateNewContext == NULL || 00466 _glXGetVisualFromFBConfig == NULL || 00467 _glXGetFBConfigAttrib == NULL || 00468 _glXCreatePixmap == NULL) { 00469 glxdisplay_cat.error() 00470 << "Driver claims to support GLX_SGIX_fbconfig extension, but does not define all functions.\n"; 00471 _supports_fbconfig = false; 00472 } 00473 } 00474 00475 if (glx_is_at_least_version(1, 3)) { 00476 // If we have glx 1.3 or better, we have the PBuffer interface. 00477 _supports_pbuffer = true; 00478 _uses_sgix_pbuffer = false; 00479 00480 _glXCreatePbuffer = 00481 (PFNGLXCREATEPBUFFERPROC)get_extension_func("glX", "CreatePbuffer"); 00482 _glXCreateGLXPbufferSGIX = NULL; 00483 _glXDestroyPbuffer = 00484 (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyPbuffer"); 00485 if (_glXCreatePbuffer == NULL || 00486 _glXDestroyPbuffer == NULL) { 00487 glxdisplay_cat.error() 00488 << "Driver claims to support GLX_pbuffer extension, but does not define all functions.\n"; 00489 _supports_pbuffer = false; 00490 } 00491 00492 } else if (has_extension("GLX_SGIX_pbuffer")) { 00493 // Or maybe we have the old SGIX extension for PBuffers. 00494 _uses_sgix_pbuffer = true; 00495 00496 // CreatePbuffer has a different form between SGIX and 1.3, 00497 // however, so we must treat it specially. But we can use the 00498 // same function pointer for DestroyPbuffer. 00499 _glXCreatePbuffer = NULL; 00500 _glXCreateGLXPbufferSGIX = 00501 (PFNGLXCREATEGLXPBUFFERSGIXPROC)get_extension_func("glX", "CreateGLXPbufferSGIX"); 00502 _glXDestroyPbuffer = 00503 (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyGLXPbufferSGIX"); 00504 if (_glXCreateGLXPbufferSGIX == NULL || 00505 _glXDestroyPbuffer == NULL) { 00506 glxdisplay_cat.error() 00507 << "Driver claims to support GLX_SGIX_pbuffer extension, but does not define all functions.\n"; 00508 _supports_pbuffer = false; 00509 } 00510 } 00511 } 00512 00513 00514 if (glxdisplay_cat.is_debug()) { 00515 glxdisplay_cat.debug() 00516 << "supports_swap_control = " << _supports_swap_control << "\n"; 00517 glxdisplay_cat.debug() 00518 << "supports_fbconfig = " << _supports_fbconfig << "\n"; 00519 glxdisplay_cat.debug() 00520 << "supports_pbuffer = " << _supports_pbuffer 00521 << " sgix = " << _uses_sgix_pbuffer << "\n"; 00522 } 00523 00524 // If "Mesa" is present, assume software. However, if "Mesa DRI" is 00525 // found, it's actually a Mesa-based OpenGL layer running over a 00526 // hardware driver. 00527 if (_gl_renderer.find("Mesa") != string::npos && 00528 _gl_renderer.find("Mesa DRI") == string::npos) { 00529 // It's Mesa, therefore probably a software context. 00530 _fbprops.set_force_software(1); 00531 _fbprops.set_force_hardware(0); 00532 } else { 00533 _fbprops.set_force_hardware(1); 00534 _fbprops.set_force_software(0); 00535 } 00536 } 00537 00538 //////////////////////////////////////////////////////////////////// 00539 // Function: glxGraphicsStateGuardian::glx_is_at_least_version 00540 // Access: Public 00541 // Description: Returns true if the runtime GLX version number is at 00542 // least the indicated value, false otherwise. 00543 //////////////////////////////////////////////////////////////////// 00544 bool glxGraphicsStateGuardian:: 00545 glx_is_at_least_version(int major_version, int minor_version) const { 00546 if (_glx_version_major < major_version) { 00547 return false; 00548 } 00549 if (_glx_version_major > major_version) { 00550 return true; 00551 } 00552 if (_glx_version_minor < minor_version) { 00553 return false; 00554 } 00555 return true; 00556 } 00557 00558 //////////////////////////////////////////////////////////////////// 00559 // Function: glxGraphicsStateGuardian::gl_flush 00560 // Access: Protected, Virtual 00561 // Description: Calls glFlush(). 00562 //////////////////////////////////////////////////////////////////// 00563 void glxGraphicsStateGuardian:: 00564 gl_flush() const { 00565 // This call requires synchronization with X. 00566 LightReMutexHolder holder(glxGraphicsPipe::_x_mutex); 00567 GLGraphicsStateGuardian::gl_flush(); 00568 } 00569 00570 //////////////////////////////////////////////////////////////////// 00571 // Function: glxGraphicsStateGuardian::gl_get_error 00572 // Access: Protected, Virtual 00573 // Description: Returns the result of glGetError(). 00574 //////////////////////////////////////////////////////////////////// 00575 GLenum glxGraphicsStateGuardian:: 00576 gl_get_error() const { 00577 // This call requires synchronization with X. 00578 LightReMutexHolder holder(glxGraphicsPipe::_x_mutex); 00579 return GLGraphicsStateGuardian::gl_get_error(); 00580 } 00581 00582 //////////////////////////////////////////////////////////////////// 00583 // Function: glxGraphicsStateGuardian::query_gl_version 00584 // Access: Protected, Virtual 00585 // Description: Queries the runtime version of OpenGL in use. 00586 //////////////////////////////////////////////////////////////////// 00587 void glxGraphicsStateGuardian:: 00588 query_gl_version() { 00589 GLGraphicsStateGuardian::query_gl_version(); 00590 00591 show_glx_client_string("GLX_VENDOR", GLX_VENDOR); 00592 show_glx_client_string("GLX_VERSION", GLX_VERSION); 00593 show_glx_server_string("GLX_VENDOR", GLX_VENDOR); 00594 show_glx_server_string("GLX_VERSION", GLX_VERSION); 00595 00596 glXQueryVersion(_display, &_glx_version_major, &_glx_version_minor); 00597 00598 // We output to glgsg_cat instead of glxdisplay_cat, since this is 00599 // where the GL version has been output, and it's nice to see the 00600 // two of these together. 00601 if (glgsg_cat.is_debug()) { 00602 glgsg_cat.debug() 00603 << "GLX_VERSION = " << _glx_version_major << "." << _glx_version_minor 00604 << "\n"; 00605 } 00606 } 00607 00608 //////////////////////////////////////////////////////////////////// 00609 // Function: glxGraphicsStateGuardian::get_extra_extensions 00610 // Access: Protected, Virtual 00611 // Description: This may be redefined by a derived class (e.g. glx or 00612 // wgl) to get whatever further extensions strings may 00613 // be appropriate to that interface, in addition to the 00614 // GL extension strings return by glGetString(). 00615 //////////////////////////////////////////////////////////////////// 00616 void glxGraphicsStateGuardian:: 00617 get_extra_extensions() { 00618 save_extensions(glXQueryExtensionsString(_display, _screen)); 00619 } 00620 00621 //////////////////////////////////////////////////////////////////// 00622 // Function: glxGraphicsStateGuardian::do_get_extension_func 00623 // Access: Public, Virtual 00624 // Description: Returns the pointer to the GL extension function with 00625 // the indicated name. It is the responsibility of the 00626 // caller to ensure that the required extension is 00627 // defined in the OpenGL runtime prior to calling this; 00628 // it is an error to call this for a function that is 00629 // not defined. 00630 //////////////////////////////////////////////////////////////////// 00631 void *glxGraphicsStateGuardian:: 00632 do_get_extension_func(const char *prefix, const char *name) { 00633 nassertr(prefix != NULL, NULL); 00634 nassertr(name != NULL, NULL); 00635 string fullname = string(prefix) + string(name); 00636 00637 if (glx_get_proc_address) { 00638 // First, check if we have glXGetProcAddress available. This will 00639 // be superior if we can get it. 00640 00641 #if defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESS) 00642 // If we are confident the system headers defined it, we can 00643 // call it directly. This is more reliable than trying to 00644 // determine its address dynamically, but it may make 00645 // libpandagl.so fail to load if the symbol isn't in the runtime 00646 // library. 00647 return (void *)glXGetProcAddress((const GLubyte *)fullname.c_str()); 00648 00649 #elif defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESSARB) 00650 // The ARB extension version is OK too. Sometimes the prototype 00651 // isn't supplied for some reason. 00652 return (void *)glXGetProcAddressARB((const GLubyte *)fullname.c_str()); 00653 00654 #else 00655 // Otherwise, we have to fiddle around with the dynamic runtime. 00656 00657 if (!_checked_get_proc_address) { 00658 const char *funcName = NULL; 00659 00660 if (glx_is_at_least_version(1, 4)) { 00661 funcName = "glXGetProcAddress"; 00662 00663 } else if (has_extension("GLX_ARB_get_proc_address")) { 00664 funcName = "glXGetProcAddressARB"; 00665 } 00666 00667 if (funcName != NULL) { 00668 _glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC)get_system_func(funcName); 00669 if (_glXGetProcAddress == NULL) { 00670 glxdisplay_cat.warning() 00671 << "Couldn't load function " << funcName 00672 << ", GL extensions may be unavailable.\n"; 00673 } 00674 } 00675 00676 _checked_get_proc_address = true; 00677 } 00678 00679 // Use glxGetProcAddress() if we've got it; it should be more robust. 00680 if (_glXGetProcAddress != NULL) { 00681 return (void *)_glXGetProcAddress((const GLubyte *)fullname.c_str()); 00682 } 00683 #endif // HAVE_GLXGETPROCADDRESS 00684 } 00685 00686 if (glx_get_os_address) { 00687 // Otherwise, fall back to the OS-provided calls. 00688 return get_system_func(fullname.c_str()); 00689 } 00690 00691 return NULL; 00692 } 00693 00694 //////////////////////////////////////////////////////////////////// 00695 // Function: glxGraphicsStateGuardian::get_system_func 00696 // Access: Private 00697 // Description: Support for get_extension_func(), above, that uses 00698 // system calls to find a GL or GLX function (in the 00699 // absence of a working glxGetProcAddress() function to 00700 // call). 00701 //////////////////////////////////////////////////////////////////// 00702 void *glxGraphicsStateGuardian:: 00703 get_system_func(const char *name) { 00704 if (_libgl_handle == (void *)NULL) { 00705 // We open the current executable, rather than naming a particular 00706 // library. Presumably libGL.so (or whatever the library should 00707 // be called) is already available in the current executable 00708 // address space, so this is more portable than insisting on a 00709 // particular shared library name. 00710 _libgl_handle = dlopen(NULL, RTLD_LAZY); 00711 nassertr(_libgl_handle != (void *)NULL, NULL); 00712 00713 // If that doesn't locate the symbol we expected, then fall back 00714 // to loading the GL library by its usual name. 00715 if (dlsym(_libgl_handle, name) == NULL) { 00716 dlclose(_libgl_handle); 00717 glxdisplay_cat.warning() 00718 << name << " not found in executable; looking in libGL.so instead.\n"; 00719 _libgl_handle = dlopen("libGL.so", RTLD_LAZY); 00720 nassertr(_libgl_handle != (void *)NULL, NULL); 00721 } 00722 } 00723 00724 return dlsym(_libgl_handle, name); 00725 } 00726 00727 //////////////////////////////////////////////////////////////////// 00728 // Function: glxGraphicsStateGuardian::show_glx_client_string 00729 // Access: Protected 00730 // Description: Outputs the result of glxGetClientString() on the 00731 // indicated tag. 00732 //////////////////////////////////////////////////////////////////// 00733 void glxGraphicsStateGuardian:: 00734 show_glx_client_string(const string &name, int id) { 00735 if (glgsg_cat.is_debug()) { 00736 const char *text = glXGetClientString(_display, id); 00737 if (text == (const char *)NULL) { 00738 glgsg_cat.debug() 00739 << "Unable to query " << name << " (client)\n"; 00740 } else { 00741 glgsg_cat.debug() 00742 << name << " (client) = " << (const char *)text << "\n"; 00743 } 00744 } 00745 } 00746 00747 //////////////////////////////////////////////////////////////////// 00748 // Function: glxGraphicsStateGuardian::show_glx_server_string 00749 // Access: Protected 00750 // Description: Outputs the result of glxQueryServerString() on the 00751 // indicated tag. 00752 //////////////////////////////////////////////////////////////////// 00753 void glxGraphicsStateGuardian:: 00754 show_glx_server_string(const string &name, int id) { 00755 if (glgsg_cat.is_debug()) { 00756 const char *text = glXQueryServerString(_display, _screen, id); 00757 if (text == (const char *)NULL) { 00758 glgsg_cat.debug() 00759 << "Unable to query " << name << " (server)\n"; 00760 } else { 00761 glgsg_cat.debug() 00762 << name << " (server) = " << (const char *)text << "\n"; 00763 } 00764 } 00765 } 00766 00767 //////////////////////////////////////////////////////////////////// 00768 // Function: glxGraphicsStateGuardian::choose_temp_visual 00769 // Access: Private 00770 // Description: Selects an XVisual for an initial OpenGL context. 00771 // This may be called initially, to create the first 00772 // context needed in order to create the fbconfig. On 00773 // successful return, _visual and _temp_context will be 00774 // filled in with a non-NULL value. 00775 //////////////////////////////////////////////////////////////////// 00776 void glxGraphicsStateGuardian:: 00777 choose_temp_visual(const FrameBufferProperties &properties) { 00778 nassertv(_temp_context == (GLXContext)NULL); 00779 00780 int best_quality = 0; 00781 int best_result = 0; 00782 FrameBufferProperties best_props; 00783 00784 // Scan available visuals. 00785 if (_visuals != (XVisualInfo *)NULL) { 00786 XFree(_visuals); 00787 _visuals = NULL; 00788 } 00789 int nvisuals = 0; 00790 _visuals = XGetVisualInfo(_display, 0, 0, &nvisuals); 00791 if (_visuals != 0) { 00792 for (int i = 0; i < nvisuals; i++) { 00793 FrameBufferProperties fbprops; 00794 get_properties(fbprops, _visuals + i); 00795 int quality = fbprops.get_quality(properties); 00796 if (quality > best_quality) { 00797 best_quality = quality; 00798 best_result = i; 00799 best_props = fbprops; 00800 } 00801 } 00802 } 00803 00804 if (best_quality > 0) { 00805 _visual = _visuals + best_result; 00806 _temp_context = glXCreateContext(_display, _visual, None, GL_TRUE); 00807 if (_temp_context) { 00808 _fbprops = best_props; 00809 return; 00810 } 00811 } 00812 00813 glxdisplay_cat.error() 00814 << "Could not find a usable pixel format.\n"; 00815 } 00816 00817 //////////////////////////////////////////////////////////////////// 00818 // Function: glxGraphicsStateGuardian::init_temp_context 00819 // Access: Private 00820 // Description: Initializes the context created in 00821 // choose_temp_visual() by creating a temporary window 00822 // and binding the context to that window. 00823 //////////////////////////////////////////////////////////////////// 00824 void glxGraphicsStateGuardian:: 00825 init_temp_context() { 00826 x11GraphicsPipe *x11_pipe; 00827 DCAST_INTO_V(x11_pipe, get_pipe()); 00828 Window root_window = x11_pipe->get_root(); 00829 00830 // Assume everyone uses TrueColor or DirectColor these days. 00831 Visual *visual = _visual->visual; 00832 nassertv(visual->c_class == DirectColor || visual->c_class == TrueColor); 00833 _temp_colormap = XCreateColormap(_display, root_window, 00834 visual, AllocNone); 00835 XSetWindowAttributes wa; 00836 wa.colormap = _temp_colormap; 00837 unsigned long attrib_mask = CWColormap; 00838 00839 _temp_xwindow = XCreateWindow 00840 (_display, root_window, 0, 0, 100, 100, 00841 0, _visual->depth, InputOutput, 00842 visual, attrib_mask, &wa); 00843 if (_temp_xwindow == (Window)NULL) { 00844 glxdisplay_cat.error() 00845 << "Could not create temporary window for context\n"; 00846 return; 00847 } 00848 00849 glXMakeCurrent(_display, _temp_xwindow, _temp_context); 00850 reset(); 00851 } 00852 00853 //////////////////////////////////////////////////////////////////// 00854 // Function: glxGraphicsStateGuardian::destroy_temp_xwindow 00855 // Access: Private 00856 // Description: Destroys the temporary unmapped window created by 00857 // init_temp_context(). 00858 //////////////////////////////////////////////////////////////////// 00859 void glxGraphicsStateGuardian:: 00860 destroy_temp_xwindow() { 00861 glXMakeCurrent(_display, None, NULL); 00862 00863 if (_temp_colormap != (Colormap)NULL) { 00864 XFreeColormap(_display, _temp_colormap); 00865 _temp_colormap = (Colormap)NULL; 00866 } 00867 if (_temp_xwindow != (Window)NULL) { 00868 XDestroyWindow(_display, _temp_xwindow); 00869 _temp_xwindow = (Window)NULL; 00870 } 00871 00872 if (_temp_context != (GLXContext)NULL){ 00873 glXDestroyContext(_display, _temp_context); 00874 _temp_context = (GLXContext)NULL; 00875 } 00876 }