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