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 if (glxdisplay_cat.is_debug()) { 00270 glxdisplay_cat.debug() 00271 <<" No FBConfig supported; using XVisual only.\n"; 00272 00273 glxdisplay_cat.debug() 00274 << _fbprops << "\n"; 00275 00276 _context = _temp_context; 00277 _temp_context = (GLXContext)NULL; 00278 00279 // By convention, every indirect XVisual that can render to a 00280 // window can also render to a GLXPixmap. Direct visuals we're 00281 // not as sure about. 00282 _context_has_pixmap = !glXIsDirect(_display, _context); 00283 00284 // Pbuffers aren't supported at all with the XVisual interface. 00285 _context_has_pbuffer = false; 00286 } 00287 return; 00288 } 00289 00290 // The OpenGL context supports the FBConfig interface, so we can use 00291 // that more advanced interface to choose the actual window format 00292 // we'll use. FBConfig provides for more options than the older 00293 // XVisual interface, so we'd much rather use it if it's available. 00294 00295 int best_quality = 0; 00296 int best_result = 0; 00297 FrameBufferProperties best_props; 00298 00299 static const int max_attrib_list = 32; 00300 int attrib_list[max_attrib_list]; 00301 int n = 0; 00302 attrib_list[n++] = GLX_STEREO; 00303 attrib_list[n++] = GLX_DONT_CARE; 00304 attrib_list[n++] = GLX_RENDER_TYPE; 00305 attrib_list[n++] = GLX_DONT_CARE; 00306 attrib_list[n++] = GLX_DRAWABLE_TYPE; 00307 attrib_list[n++] = GLX_DONT_CARE; 00308 attrib_list[n] = (int)None; 00309 00310 int num_configs = 0; 00311 GLXFBConfig *configs = 00312 _glXChooseFBConfig(_display, _screen, attrib_list, &num_configs); 00313 00314 if (configs != 0) { 00315 bool context_has_pbuffer, context_has_pixmap, slow; 00316 int quality, i; 00317 for (i = 0; i < num_configs; ++i) { 00318 FrameBufferProperties fbprops; 00319 get_properties_advanced(fbprops, context_has_pbuffer, context_has_pixmap, 00320 slow, configs[i]); 00321 quality = fbprops.get_quality(properties); 00322 if ((quality > 0)&&(slow)) quality -= 10000000; 00323 if (glxdisplay_cat.is_debug()) { 00324 const char *pbuffertext = context_has_pbuffer ? " (pbuffer)" : ""; 00325 const char *pixmaptext = context_has_pixmap ? " (pixmap)" : ""; 00326 const char *slowtext = slow ? " (slow)" : ""; 00327 glxdisplay_cat.debug() 00328 << i << ": " << fbprops << " quality=" << quality << pbuffertext << pixmaptext << slowtext << "\n"; 00329 } 00330 if (need_pbuffer && !context_has_pbuffer) { 00331 continue; 00332 } 00333 if (need_pixmap && !context_has_pixmap) { 00334 continue; 00335 } 00336 00337 if (quality > best_quality) { 00338 best_quality = quality; 00339 best_result = i; 00340 best_props = fbprops; 00341 } 00342 } 00343 } 00344 00345 if (best_quality > 0) { 00346 _fbconfig = configs[best_result]; 00347 _context = 00348 _glXCreateNewContext(_display, _fbconfig, GLX_RGBA_TYPE, _share_context, 00349 GL_TRUE); 00350 if (_context) { 00351 if (_visuals != (XVisualInfo *)NULL) { 00352 XFree(_visuals); 00353 _visuals = NULL; 00354 } 00355 _visuals = _glXGetVisualFromFBConfig(_display, _fbconfig); 00356 _visual = _visuals; 00357 00358 if (_visual) { 00359 get_properties_advanced(_fbprops, _context_has_pbuffer, _context_has_pixmap, 00360 _slow, _fbconfig); 00361 00362 if (glxdisplay_cat.is_debug()) { 00363 glxdisplay_cat.debug() 00364 << "Selected context " << best_result << ": " << _fbprops << "\n"; 00365 glxdisplay_cat.debug() 00366 << "context_has_pbuffer = " << _context_has_pbuffer 00367 << ", context_has_pixmap = " << _context_has_pixmap << "\n"; 00368 } 00369 00370 return; 00371 } 00372 } 00373 // This really shouldn't happen, so I'm not too careful about cleanup. 00374 glxdisplay_cat.error() 00375 << "Could not create FBConfig context!\n"; 00376 _fbconfig = 0; 00377 _context = 0; 00378 _visual = 0; 00379 _visuals = 0; 00380 } 00381 00382 glxdisplay_cat.info() 00383 << "No suitable FBConfig contexts available.\n"; 00384 } 00385 00386 //////////////////////////////////////////////////////////////////// 00387 // Function: glxGraphicsStateGuardian::reset 00388 // Access: Public, Virtual 00389 // Description: Resets all internal state as if the gsg were newly 00390 // created. 00391 //////////////////////////////////////////////////////////////////// 00392 void glxGraphicsStateGuardian:: 00393 reset() { 00394 GLGraphicsStateGuardian::reset(); 00395 00396 _supports_swap_control = has_extension("GLX_SGI_swap_control"); 00397 00398 if (_supports_swap_control) { 00399 _glXSwapIntervalSGI = 00400 (PFNGLXSWAPINTERVALSGIPROC)get_extension_func("glX", "SwapIntervalSGI"); 00401 if (_glXSwapIntervalSGI == NULL) { 00402 glxdisplay_cat.error() 00403 << "Driver claims to support GLX_SGI_swap_control extension, but does not define all functions.\n"; 00404 _supports_swap_control = false; 00405 } 00406 } 00407 00408 if (_supports_swap_control) { 00409 // Set the video-sync setting up front, if we have the extension 00410 // that supports it. 00411 _glXSwapIntervalSGI(sync_video ? 1 : 0); 00412 } 00413 00414 if (glx_support_fbconfig) { 00415 if (glx_is_at_least_version(1, 3)) { 00416 // If we have glx 1.3 or better, we have the FBConfig interface. 00417 _supports_fbconfig = true; 00418 00419 _glXChooseFBConfig = 00420 (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfig"); 00421 _glXCreateNewContext = 00422 (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateNewContext"); 00423 _glXGetVisualFromFBConfig = 00424 (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfig"); 00425 _glXGetFBConfigAttrib = 00426 (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttrib"); 00427 _glXCreatePixmap = 00428 (PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreatePixmap"); 00429 00430 if (_glXChooseFBConfig == NULL || 00431 _glXCreateNewContext == NULL || 00432 _glXGetVisualFromFBConfig == NULL || 00433 _glXGetFBConfigAttrib == NULL || 00434 _glXCreatePixmap == NULL) { 00435 glxdisplay_cat.error() 00436 << "Driver claims to support GLX_fbconfig extension, but does not define all functions.\n"; 00437 _supports_fbconfig = false; 00438 } 00439 } else if (has_extension("GLX_SGIX_fbconfig")) { 00440 // Or maybe we have the old SGIX extension for FBConfig. This is 00441 // the same, but the function names are different--we just remap 00442 // them to the same function pointers. 00443 _supports_fbconfig = true; 00444 00445 _glXChooseFBConfig = 00446 (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfigSGIX"); 00447 _glXCreateNewContext = 00448 (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateContextWithConfigSGIX"); 00449 _glXGetVisualFromFBConfig = 00450 (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfigSGIX"); 00451 _glXGetFBConfigAttrib = 00452 (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttribSGIX"); 00453 _glXCreatePixmap = 00454 (PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreateGLXPixmapWithConfigSGIX"); 00455 00456 if (_glXChooseFBConfig == NULL || 00457 _glXCreateNewContext == NULL || 00458 _glXGetVisualFromFBConfig == NULL || 00459 _glXGetFBConfigAttrib == NULL || 00460 _glXCreatePixmap == NULL) { 00461 glxdisplay_cat.error() 00462 << "Driver claims to support GLX_SGIX_fbconfig extension, but does not define all functions.\n"; 00463 _supports_fbconfig = false; 00464 } 00465 } 00466 00467 if (glx_is_at_least_version(1, 3)) { 00468 // If we have glx 1.3 or better, we have the PBuffer interface. 00469 _supports_pbuffer = true; 00470 _uses_sgix_pbuffer = false; 00471 00472 _glXCreatePbuffer = 00473 (PFNGLXCREATEPBUFFERPROC)get_extension_func("glX", "CreatePbuffer"); 00474 _glXCreateGLXPbufferSGIX = NULL; 00475 _glXDestroyPbuffer = 00476 (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyPbuffer"); 00477 if (_glXCreatePbuffer == NULL || 00478 _glXDestroyPbuffer == NULL) { 00479 glxdisplay_cat.error() 00480 << "Driver claims to support GLX_pbuffer extension, but does not define all functions.\n"; 00481 _supports_pbuffer = false; 00482 } 00483 00484 } else if (has_extension("GLX_SGIX_pbuffer")) { 00485 // Or maybe we have the old SGIX extension for PBuffers. 00486 _uses_sgix_pbuffer = true; 00487 00488 // CreatePbuffer has a different form between SGIX and 1.3, 00489 // however, so we must treat it specially. But we can use the 00490 // same function pointer for DestroyPbuffer. 00491 _glXCreatePbuffer = NULL; 00492 _glXCreateGLXPbufferSGIX = 00493 (PFNGLXCREATEGLXPBUFFERSGIXPROC)get_extension_func("glX", "CreateGLXPbufferSGIX"); 00494 _glXDestroyPbuffer = 00495 (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyGLXPbufferSGIX"); 00496 if (_glXCreateGLXPbufferSGIX == NULL || 00497 _glXDestroyPbuffer == NULL) { 00498 glxdisplay_cat.error() 00499 << "Driver claims to support GLX_SGIX_pbuffer extension, but does not define all functions.\n"; 00500 _supports_pbuffer = false; 00501 } 00502 } 00503 } 00504 00505 00506 if (glxdisplay_cat.is_debug()) { 00507 glxdisplay_cat.debug() 00508 << "supports_swap_control = " << _supports_swap_control << "\n"; 00509 glxdisplay_cat.debug() 00510 << "supports_fbconfig = " << _supports_fbconfig << "\n"; 00511 glxdisplay_cat.debug() 00512 << "supports_pbuffer = " << _supports_pbuffer 00513 << " sgix = " << _uses_sgix_pbuffer << "\n"; 00514 } 00515 00516 // If "Mesa" is present, assume software. However, if "Mesa DRI" is 00517 // found, it's actually a Mesa-based OpenGL layer running over a 00518 // hardware driver. 00519 if (_gl_renderer.find("Mesa") != string::npos && 00520 _gl_renderer.find("Mesa DRI") == string::npos) { 00521 // It's Mesa, therefore probably a software context. 00522 _fbprops.set_force_software(1); 00523 _fbprops.set_force_hardware(0); 00524 } else { 00525 _fbprops.set_force_hardware(1); 00526 _fbprops.set_force_software(0); 00527 } 00528 } 00529 00530 //////////////////////////////////////////////////////////////////// 00531 // Function: glxGraphicsStateGuardian::glx_is_at_least_version 00532 // Access: Public 00533 // Description: Returns true if the runtime GLX version number is at 00534 // least the indicated value, false otherwise. 00535 //////////////////////////////////////////////////////////////////// 00536 bool glxGraphicsStateGuardian:: 00537 glx_is_at_least_version(int major_version, int minor_version) const { 00538 if (_glx_version_major < major_version) { 00539 return false; 00540 } 00541 if (_glx_version_major > major_version) { 00542 return true; 00543 } 00544 if (_glx_version_minor < minor_version) { 00545 return false; 00546 } 00547 return true; 00548 } 00549 00550 //////////////////////////////////////////////////////////////////// 00551 // Function: glxGraphicsStateGuardian::gl_flush 00552 // Access: Protected, Virtual 00553 // Description: Calls glFlush(). 00554 //////////////////////////////////////////////////////////////////// 00555 void glxGraphicsStateGuardian:: 00556 gl_flush() const { 00557 // This call requires synchronization with X. 00558 LightReMutexHolder holder(glxGraphicsPipe::_x_mutex); 00559 GLGraphicsStateGuardian::gl_flush(); 00560 } 00561 00562 //////////////////////////////////////////////////////////////////// 00563 // Function: glxGraphicsStateGuardian::gl_get_error 00564 // Access: Protected, Virtual 00565 // Description: Returns the result of glGetError(). 00566 //////////////////////////////////////////////////////////////////// 00567 GLenum glxGraphicsStateGuardian:: 00568 gl_get_error() const { 00569 // This call requires synchronization with X. 00570 LightReMutexHolder holder(glxGraphicsPipe::_x_mutex); 00571 return GLGraphicsStateGuardian::gl_get_error(); 00572 } 00573 00574 //////////////////////////////////////////////////////////////////// 00575 // Function: glxGraphicsStateGuardian::query_gl_version 00576 // Access: Protected, Virtual 00577 // Description: Queries the runtime version of OpenGL in use. 00578 //////////////////////////////////////////////////////////////////// 00579 void glxGraphicsStateGuardian:: 00580 query_gl_version() { 00581 GLGraphicsStateGuardian::query_gl_version(); 00582 00583 show_glx_client_string("GLX_VENDOR", GLX_VENDOR); 00584 show_glx_client_string("GLX_VERSION", GLX_VERSION); 00585 show_glx_server_string("GLX_VENDOR", GLX_VENDOR); 00586 show_glx_server_string("GLX_VERSION", GLX_VERSION); 00587 00588 glXQueryVersion(_display, &_glx_version_major, &_glx_version_minor); 00589 00590 // We output to glgsg_cat instead of glxdisplay_cat, since this is 00591 // where the GL version has been output, and it's nice to see the 00592 // two of these together. 00593 if (glgsg_cat.is_debug()) { 00594 glgsg_cat.debug() 00595 << "GLX_VERSION = " << _glx_version_major << "." << _glx_version_minor 00596 << "\n"; 00597 } 00598 } 00599 00600 //////////////////////////////////////////////////////////////////// 00601 // Function: glxGraphicsStateGuardian::get_extra_extensions 00602 // Access: Protected, Virtual 00603 // Description: This may be redefined by a derived class (e.g. glx or 00604 // wgl) to get whatever further extensions strings may 00605 // be appropriate to that interface, in addition to the 00606 // GL extension strings return by glGetString(). 00607 //////////////////////////////////////////////////////////////////// 00608 void glxGraphicsStateGuardian:: 00609 get_extra_extensions() { 00610 save_extensions(glXQueryExtensionsString(_display, _screen)); 00611 } 00612 00613 //////////////////////////////////////////////////////////////////// 00614 // Function: glxGraphicsStateGuardian::do_get_extension_func 00615 // Access: Public, Virtual 00616 // Description: Returns the pointer to the GL extension function with 00617 // the indicated name. It is the responsibility of the 00618 // caller to ensure that the required extension is 00619 // defined in the OpenGL runtime prior to calling this; 00620 // it is an error to call this for a function that is 00621 // not defined. 00622 //////////////////////////////////////////////////////////////////// 00623 void *glxGraphicsStateGuardian:: 00624 do_get_extension_func(const char *prefix, const char *name) { 00625 nassertr(prefix != NULL, NULL); 00626 nassertr(name != NULL, NULL); 00627 string fullname = string(prefix) + string(name); 00628 00629 if (glx_get_proc_address) { 00630 // First, check if we have glXGetProcAddress available. This will 00631 // be superior if we can get it. 00632 00633 #if defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESS) 00634 // If we are confident the system headers defined it, we can 00635 // call it directly. This is more reliable than trying to 00636 // determine its address dynamically, but it may make 00637 // libpandagl.so fail to load if the symbol isn't in the runtime 00638 // library. 00639 return (void *)glXGetProcAddress((const GLubyte *)fullname.c_str()); 00640 00641 #elif defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESSARB) 00642 // The ARB extension version is OK too. Sometimes the prototype 00643 // isn't supplied for some reason. 00644 return (void *)glXGetProcAddressARB((const GLubyte *)fullname.c_str()); 00645 00646 #else 00647 // Otherwise, we have to fiddle around with the dynamic runtime. 00648 00649 if (!_checked_get_proc_address) { 00650 const char *funcName = NULL; 00651 00652 if (glx_is_at_least_version(1, 4)) { 00653 funcName = "glXGetProcAddress"; 00654 00655 } else if (has_extension("GLX_ARB_get_proc_address")) { 00656 funcName = "glXGetProcAddressARB"; 00657 } 00658 00659 if (funcName != NULL) { 00660 _glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC)get_system_func(funcName); 00661 if (_glXGetProcAddress == NULL) { 00662 glxdisplay_cat.warning() 00663 << "Couldn't load function " << funcName 00664 << ", GL extensions may be unavailable.\n"; 00665 } 00666 } 00667 00668 _checked_get_proc_address = true; 00669 } 00670 00671 // Use glxGetProcAddress() if we've got it; it should be more robust. 00672 if (_glXGetProcAddress != NULL) { 00673 return (void *)_glXGetProcAddress((const GLubyte *)fullname.c_str()); 00674 } 00675 #endif // HAVE_GLXGETPROCADDRESS 00676 } 00677 00678 if (glx_get_os_address) { 00679 // Otherwise, fall back to the OS-provided calls. 00680 return get_system_func(fullname.c_str()); 00681 } 00682 00683 return NULL; 00684 } 00685 00686 //////////////////////////////////////////////////////////////////// 00687 // Function: glxGraphicsStateGuardian::get_system_func 00688 // Access: Private 00689 // Description: Support for get_extension_func(), above, that uses 00690 // system calls to find a GL or GLX function (in the 00691 // absence of a working glxGetProcAddress() function to 00692 // call). 00693 //////////////////////////////////////////////////////////////////// 00694 void *glxGraphicsStateGuardian:: 00695 get_system_func(const char *name) { 00696 if (_libgl_handle == (void *)NULL) { 00697 // We open the current executable, rather than naming a particular 00698 // library. Presumably libGL.so (or whatever the library should 00699 // be called) is already available in the current executable 00700 // address space, so this is more portable than insisting on a 00701 // particular shared library name. 00702 _libgl_handle = dlopen(NULL, RTLD_LAZY); 00703 nassertr(_libgl_handle != (void *)NULL, NULL); 00704 00705 // If that doesn't locate the symbol we expected, then fall back 00706 // to loading the GL library by its usual name. 00707 if (dlsym(_libgl_handle, name) == NULL) { 00708 dlclose(_libgl_handle); 00709 glxdisplay_cat.warning() 00710 << name << " not found in executable; looking in libGL.so instead.\n"; 00711 _libgl_handle = dlopen("libGL.so", RTLD_LAZY); 00712 nassertr(_libgl_handle != (void *)NULL, NULL); 00713 } 00714 } 00715 00716 return dlsym(_libgl_handle, name); 00717 } 00718 00719 //////////////////////////////////////////////////////////////////// 00720 // Function: glxGraphicsStateGuardian::show_glx_client_string 00721 // Access: Protected 00722 // Description: Outputs the result of glxGetClientString() on the 00723 // indicated tag. 00724 //////////////////////////////////////////////////////////////////// 00725 void glxGraphicsStateGuardian:: 00726 show_glx_client_string(const string &name, int id) { 00727 if (glgsg_cat.is_debug()) { 00728 const char *text = glXGetClientString(_display, id); 00729 if (text == (const char *)NULL) { 00730 glgsg_cat.debug() 00731 << "Unable to query " << name << " (client)\n"; 00732 } else { 00733 glgsg_cat.debug() 00734 << name << " (client) = " << (const char *)text << "\n"; 00735 } 00736 } 00737 } 00738 00739 //////////////////////////////////////////////////////////////////// 00740 // Function: glxGraphicsStateGuardian::show_glx_server_string 00741 // Access: Protected 00742 // Description: Outputs the result of glxQueryServerString() on the 00743 // indicated tag. 00744 //////////////////////////////////////////////////////////////////// 00745 void glxGraphicsStateGuardian:: 00746 show_glx_server_string(const string &name, int id) { 00747 if (glgsg_cat.is_debug()) { 00748 const char *text = glXQueryServerString(_display, _screen, id); 00749 if (text == (const char *)NULL) { 00750 glgsg_cat.debug() 00751 << "Unable to query " << name << " (server)\n"; 00752 } else { 00753 glgsg_cat.debug() 00754 << name << " (server) = " << (const char *)text << "\n"; 00755 } 00756 } 00757 } 00758 00759 //////////////////////////////////////////////////////////////////// 00760 // Function: glxGraphicsStateGuardian::choose_temp_visual 00761 // Access: Private 00762 // Description: Selects an XVisual for an initial OpenGL context. 00763 // This may be called initially, to create the first 00764 // context needed in order to create the fbconfig. On 00765 // successful return, _visual and _temp_context will be 00766 // filled in with a non-NULL value. 00767 //////////////////////////////////////////////////////////////////// 00768 void glxGraphicsStateGuardian:: 00769 choose_temp_visual(const FrameBufferProperties &properties) { 00770 nassertv(_temp_context == (GLXContext)NULL); 00771 00772 int best_quality = 0; 00773 int best_result = 0; 00774 FrameBufferProperties best_props; 00775 00776 // Scan available visuals. 00777 if (_visuals != (XVisualInfo *)NULL) { 00778 XFree(_visuals); 00779 _visuals = NULL; 00780 } 00781 int nvisuals = 0; 00782 _visuals = XGetVisualInfo(_display, 0, 0, &nvisuals); 00783 if (_visuals != 0) { 00784 for (int i = 0; i < nvisuals; i++) { 00785 FrameBufferProperties fbprops; 00786 get_properties(fbprops, _visuals + i); 00787 int quality = fbprops.get_quality(properties); 00788 if (quality > best_quality) { 00789 best_quality = quality; 00790 best_result = i; 00791 best_props = fbprops; 00792 } 00793 } 00794 } 00795 00796 if (best_quality > 0) { 00797 _visual = _visuals + best_result; 00798 _temp_context = glXCreateContext(_display, _visual, None, GL_TRUE); 00799 if (_temp_context) { 00800 _fbprops = best_props; 00801 return; 00802 } 00803 } 00804 00805 glxdisplay_cat.error() 00806 << "Could not find a usable pixel format.\n"; 00807 } 00808 00809 //////////////////////////////////////////////////////////////////// 00810 // Function: glxGraphicsStateGuardian::init_temp_context 00811 // Access: Private 00812 // Description: Initializes the context created in 00813 // choose_temp_visual() by creating a temporary window 00814 // and binding the context to that window. 00815 //////////////////////////////////////////////////////////////////// 00816 void glxGraphicsStateGuardian:: 00817 init_temp_context() { 00818 x11GraphicsPipe *x11_pipe; 00819 DCAST_INTO_V(x11_pipe, get_pipe()); 00820 Window root_window = x11_pipe->get_root(); 00821 00822 // Assume everyone uses TrueColor or DirectColor these days. 00823 Visual *visual = _visual->visual; 00824 nassertv(visual->c_class == DirectColor || visual->c_class == TrueColor); 00825 _temp_colormap = XCreateColormap(_display, root_window, 00826 visual, AllocNone); 00827 XSetWindowAttributes wa; 00828 wa.colormap = _temp_colormap; 00829 unsigned long attrib_mask = CWColormap; 00830 00831 _temp_xwindow = XCreateWindow 00832 (_display, root_window, 0, 0, 100, 100, 00833 0, _visual->depth, InputOutput, 00834 visual, attrib_mask, &wa); 00835 if (_temp_xwindow == (Window)NULL) { 00836 glxdisplay_cat.error() 00837 << "Could not create temporary window for context\n"; 00838 return; 00839 } 00840 00841 glXMakeCurrent(_display, _temp_xwindow, _temp_context); 00842 reset(); 00843 } 00844 00845 //////////////////////////////////////////////////////////////////// 00846 // Function: glxGraphicsStateGuardian::destroy_temp_xwindow 00847 // Access: Private 00848 // Description: Destroys the temporary unmapped window created by 00849 // init_temp_context(). 00850 //////////////////////////////////////////////////////////////////// 00851 void glxGraphicsStateGuardian:: 00852 destroy_temp_xwindow() { 00853 glXMakeCurrent(_display, None, NULL); 00854 00855 if (_temp_colormap != (Colormap)NULL) { 00856 XFreeColormap(_display, _temp_colormap); 00857 _temp_colormap = (Colormap)NULL; 00858 } 00859 if (_temp_xwindow != (Window)NULL) { 00860 XDestroyWindow(_display, _temp_xwindow); 00861 _temp_xwindow = (Window)NULL; 00862 } 00863 00864 if (_temp_context != (GLXContext)NULL){ 00865 glXDestroyContext(_display, _temp_context); 00866 _temp_context = (GLXContext)NULL; 00867 } 00868 }