render_system.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <QMetaType>
31 
32 // This is required for QT_MAC_USE_COCOA to be set
33 #include <QtCore/qglobal.h>
34 
35 #include <QMoveEvent>
36 
37 #ifndef Q_OS_MAC
38 #include <X11/Xlib.h>
39 #include <X11/Xutil.h>
40 #include <GL/glx.h>
41 #endif
42 
43 // X.h #defines CursorShape to be "0". Qt uses CursorShape in normal
44 // C++ way. This wasn't an issue until ogre_logging.h (below)
45 // introduced a #include of <QString>.
46 #ifdef CursorShape
47 #undef CursorShape
48 #endif
49 
50 #include <ros/package.h> // This dependency should be moved out of here, it is just used for a search path.
51 #include <ros/console.h>
52 
53 #include <OgreRenderWindow.h>
54 #include <OgreSceneManager.h>
55 #if ((OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 9) || OGRE_VERSION_MAJOR >= 2 )
56 #include <OgreOverlaySystem.h>
57 #endif
58 
59 #include "rviz/env_config.h"
61 
63 
64 #include <QMessageBox>
65 
66 namespace rviz
67 {
68 
69 RenderSystem* RenderSystem::instance_ = 0;
73 
75 {
76  if( instance_ == 0 )
77  {
78  instance_ = new RenderSystem();
79  }
80  return instance_;
81 }
82 
83 void RenderSystem::forceGlVersion( int version )
84 {
85  force_gl_version_ = version;
86  ROS_INFO_STREAM( "Forcing OpenGl version " << (float)version / 100.0 << "." );
87 }
88 
90 {
91  use_anti_aliasing_ = false;
92  ROS_INFO("Disabling Anti-Aliasing");
93 }
94 
96 {
97  force_no_stereo_ = true;
98  ROS_INFO("Forcing Stereo OFF");
99 }
100 
103 , stereo_supported_(false)
104 {
106 
107  std::string rviz_path = ros::package::getPath(ROS_PACKAGE_NAME);
108 
110  ogre_root_ = new Ogre::Root( rviz_path+"/ogre_media/plugins.cfg" );
111 #if ((OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 9) || OGRE_VERSION_MAJOR >= 2 )
112  ogre_overlay_system_ = new Ogre::OverlaySystem();
113 #endif
114  loadOgrePlugins();
116  ogre_root_->initialise(false);
118  detectGlVersion();
119  setupResources();
120  Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
121 }
122 
123 void RenderSystem::prepareOverlays(Ogre::SceneManager* scene_manager)
124 {
125 #if ((OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 9) || OGRE_VERSION_MAJOR >= 2 )
127  scene_manager->addRenderQueueListener(ogre_overlay_system_);
128 #endif
129 }
130 
132 {
133 #ifdef Q_OS_MAC
134  dummy_window_id_ = 0;
135 #else
136  Display *display = XOpenDisplay(0);
137 
138  if (display == NULL) {
139 
140  ROS_WARN("$DISPLAY is invalid, falling back on default :0");
141  display = XOpenDisplay(":0");
142 
143  if (display == NULL) {
144  ROS_FATAL("Can't open default or :0 display. Try setting DISPLAY environment variable.");
145  throw std::runtime_error("Can't open default or :0 display!\n");
146  }
147 
148  }
149 
150  int screen = DefaultScreen( display );
151 
152  int attribList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16,
153  GLX_STENCIL_SIZE, 8, None };
154 
155  XVisualInfo *visual = glXChooseVisual( display, screen, (int*)attribList );
156 
157  dummy_window_id_ = XCreateSimpleWindow( display,
158  RootWindow( display, screen ),
159  0, 0, 1, 1, 0, 0, 0 );
160 
161  GLXContext context = glXCreateContext( display, visual, NULL, 1 );
162 
163  glXMakeCurrent( display, dummy_window_id_, context );
164 #endif
165 }
166 
168 {
169  std::string plugin_prefix = get_ogre_plugin_path() + "/";
170 #ifdef Q_OS_MAC
171  plugin_prefix += "lib";
172 #endif
173  ogre_root_->loadPlugin( plugin_prefix + "RenderSystem_GL" );
174  ogre_root_->loadPlugin( plugin_prefix + "Plugin_OctreeSceneManager" );
175  ogre_root_->loadPlugin( plugin_prefix + "Plugin_ParticleFX" );
176 }
177 
179 {
180  if ( force_gl_version_ )
181  {
183  }
184  else
185  {
186  Ogre::RenderSystem *renderSys = ogre_root_->getRenderSystem();
187  renderSys->createRenderSystemCapabilities();
188  const Ogre::RenderSystemCapabilities* caps = renderSys->getCapabilities();
189  int major = caps->getDriverVersion().major;
190  int minor = caps->getDriverVersion().minor;
191  gl_version_ = major * 100 + minor*10;
192  }
193 
194  switch ( gl_version_ )
195  {
196  case 200:
197  glsl_version_ = 110;
198  break;
199  case 210:
200  glsl_version_ = 120;
201  break;
202  case 300:
203  glsl_version_ = 130;
204  break;
205  case 310:
206  glsl_version_ = 140;
207  break;
208  case 320:
209  glsl_version_ = 150;
210  break;
211  default:
212  if ( gl_version_ > 320 )
213  {
215  }
216  else
217  {
218  glsl_version_ = 0;
219  }
220  break;
221  }
222  ROS_INFO_STREAM( "OpenGl version: " << (float)gl_version_ / 100.0 << " (GLSL " << (float)glsl_version_ / 100.0 << ")." );
223 }
224 
226 {
227  Ogre::RenderSystem *renderSys;
228  const Ogre::RenderSystemList *rsList;
229 
230  // Get the list of available renderers.
231 #if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR == 6
232  rsList = ogre_root_->getAvailableRenderers();
233 #else
234  rsList = &(ogre_root_->getAvailableRenderers());
235 #endif
236 
237  // Look for the OpenGL one, which we require.
238  renderSys = NULL;
239  for( unsigned int i = 0; i < rsList->size(); i++ )
240  {
241  renderSys = rsList->at( i );
242  if( renderSys->getName().compare("OpenGL Rendering Subsystem")== 0 )
243  {
244  break;
245  }
246  }
247 
248  if( renderSys == NULL )
249  {
250  throw std::runtime_error( "Could not find the opengl rendering subsystem!\n" );
251  }
252 
253  // We operate in windowed mode
254  renderSys->setConfigOption("Full Screen","No");
255 
261  // renderSys->setConfigOption("RTT Preferred Mode", "FBO");
262 
263  // Set the Full Screen Anti-Aliasing factor.
264  if (use_anti_aliasing_) {
265  renderSys->setConfigOption("FSAA", "4");
266  }
267 
268  ogre_root_->setRenderSystem(renderSys);
269 }
270 
272 {
273  std::string rviz_path = ros::package::getPath(ROS_PACKAGE_NAME);
274  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media", "FileSystem", ROS_PACKAGE_NAME );
275  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/textures", "FileSystem", ROS_PACKAGE_NAME );
276  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/fonts", "FileSystem", ROS_PACKAGE_NAME );
277  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/models", "FileSystem", ROS_PACKAGE_NAME );
278  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials", "FileSystem", ROS_PACKAGE_NAME );
279  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/scripts", "FileSystem", ROS_PACKAGE_NAME );
280  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/glsl120", "FileSystem", ROS_PACKAGE_NAME );
281  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/glsl120/nogp", "FileSystem", ROS_PACKAGE_NAME );
282  // Add resources that depend on a specific glsl version.
283  // Unfortunately, Ogre doesn't have a notion of glsl versions so we can't go
284  // the 'official' way of defining multiple schemes per material and let Ogre decide which one to use.
285  if ( getGlslVersion() >= 150 )
286  {
287  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/glsl150", "FileSystem", ROS_PACKAGE_NAME );
288  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/scripts150", "FileSystem", ROS_PACKAGE_NAME );
289  }
290  else if ( getGlslVersion() >= 120 )
291  {
292  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( rviz_path + "/ogre_media/materials/scripts120", "FileSystem", ROS_PACKAGE_NAME );
293  }
294  else
295  {
296  std::string s = "Your graphics driver does not support OpenGL 2.1. Please enable software rendering before running RViz (e.g. type 'export LIBGL_ALWAYS_SOFTWARE=1').";
297  QMessageBox msgBox;
298  msgBox.setText(s.c_str());
299  msgBox.exec();
300  throw std::runtime_error( s );
301  }
302 
303  // Add paths exported to the "media_export" package.
304  std::vector<std::string> media_paths;
305  ros::package::getPlugins( "media_export", "ogre_media_path", media_paths );
306  std::string delim(":");
307  for( std::vector<std::string>::iterator iter = media_paths.begin(); iter != media_paths.end(); ++iter )
308  {
309  if( !iter->empty() )
310  {
311  std::string path;
312  int pos1 = 0;
313  int pos2 = iter->find(delim);
314  while( pos2 != (int)std::string::npos )
315  {
316  path = iter->substr( pos1, pos2 - pos1 );
317  ROS_DEBUG("adding resource location: '%s'\n", path.c_str());
318  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( path, "FileSystem", ROS_PACKAGE_NAME );
319  pos1 = pos2 + 1;
320  pos2 = iter->find( delim, pos2 + 1 );
321  }
322  path = iter->substr( pos1, iter->size() - pos1 );
323  ROS_DEBUG("adding resource location: '%s'\n", path.c_str());
324  Ogre::ResourceGroupManager::getSingleton().addResourceLocation( path, "FileSystem", ROS_PACKAGE_NAME );
325  }
326  }
327 }
328 
329 // On Intel graphics chips under X11, there sometimes comes a
330 // BadDrawable error during Ogre render window creation. It is not
331 // consistent, happens sometimes but not always. Underlying problem
332 // seems to be a driver bug. My workaround here is to notice when
333 // that specific BadDrawable error happens on request 136 minor 3
334 // (which is what the problem looks like when it happens) and just try
335 // over and over again until it works (or until 100 failures, which
336 // makes it seem like it is a different bug).
337 static bool x_baddrawable_error = false;
338 #ifdef Q_WS_X11
339 static int (*old_error_handler)( Display*, XErrorEvent* );
340 int checkBadDrawable( Display* display, XErrorEvent* error )
341 {
342  if( error->error_code == BadDrawable &&
343  error->request_code == 136 &&
344  error->minor_code == 3 )
345  {
346  x_baddrawable_error = true;
347  return 0;
348  }
349  else
350  {
351  // If the error does not exactly match the one from the driver bug,
352  // handle it the normal way so we see it.
353  return old_error_handler( display, error );
354  }
355 }
356 #endif // Q_WS_X11
357 
358 Ogre::RenderWindow* RenderSystem::makeRenderWindow(
359  WindowIDType window_id,
360  unsigned int width,
361  unsigned int height,
362  double pixel_ratio)
363 {
364  static int windowCounter = 0; // Every RenderWindow needs a unique name, oy.
365 
366  Ogre::NameValuePairList params;
367  Ogre::RenderWindow *window = NULL;
368 
369  params["externalWindowHandle"] = Ogre::StringConverter::toString(window_id);
370  params["parentWindowHandle"] = Ogre::StringConverter::toString(window_id);
371 
372  params["externalGLControl"] = true;
373 
374  // Enable antialiasing
375  if (use_anti_aliasing_) {
376  params["FSAA"] = "4";
377  }
378 
379 // Set the macAPI for Ogre based on the Qt implementation
380 #if defined(Q_OS_MAC)
381  params["macAPI"] = "cocoa";
382  params["macAPICocoaUseNSView"] = "true";
383 #endif
384  params["contentScalingFactor"] = std::to_string(pixel_ratio);
385 
386  std::ostringstream stream;
387  stream << "OgreWindow(" << windowCounter++ << ")";
388 
389 
390  // don't bother trying stereo if Ogre does not support it.
391 #if !OGRE_STEREO_ENABLE
392  force_no_stereo_ = true;
393 #endif
394 
395  // attempt to create a stereo window
396  bool is_stereo = false;
397  if (!force_no_stereo_)
398  {
399  params["stereoMode"] = "Frame Sequential";
400  window = tryMakeRenderWindow( stream.str(), width, height, &params, 100);
401  params.erase("stereoMode");
402 
403  if (window)
404  {
405 #if OGRE_STEREO_ENABLE
406  is_stereo = window->isStereoEnabled();
407 #endif
408  if (!is_stereo)
409  {
410  // Created a non-stereo window. Discard it and try again (below)
411  // without the stereo parameter.
412  ogre_root_->detachRenderTarget(window);
413  window->destroy();
414  window = NULL;
415  stream << "x";
416  is_stereo = false;
417  }
418  }
419  }
420 
421  if ( window == NULL )
422  {
423  window = tryMakeRenderWindow( stream.str(), width, height, &params, 100);
424  }
425 
426  if( window == NULL )
427  {
428  ROS_ERROR( "Unable to create the rendering window after 100 tries." );
429  assert(false);
430  }
431 
432  if (window)
433  {
434  window->setActive(true);
435  //window->setVisible(true);
436  window->setAutoUpdated(false);
437  }
438 
439  stereo_supported_ = is_stereo;
440 
441  ROS_INFO_ONCE("Stereo is %s", stereo_supported_ ? "SUPPORTED" : "NOT SUPPORTED");
442 
443  return window;
444 }
445 
447  const std::string& name,
448  unsigned int width,
449  unsigned int height,
450  const Ogre::NameValuePairList* params,
451  int max_attempts )
452 {
453  Ogre::RenderWindow *window = NULL;
454  int attempts = 0;
455 
456 #ifdef Q_WS_X11
457  old_error_handler = XSetErrorHandler( &checkBadDrawable );
458 #endif
459 
460  while (window == NULL && (attempts++) < max_attempts)
461  {
462  try
463  {
464  window = ogre_root_->createRenderWindow( name, width, height, false, params );
465 
466  // If the driver bug happened, tell Ogre we are done with that
467  // window and then try again.
468  if( x_baddrawable_error )
469  {
470  ogre_root_->detachRenderTarget( window );
471  window = NULL;
472  x_baddrawable_error = false;
473  }
474  }
475  catch( const std::exception & ex )
476  {
477  std::cerr << "rviz::RenderSystem: error creating render window: "
478  << ex.what() << std::endl;
479  window = NULL;
480  }
481  }
482 
483 #ifdef Q_WS_X11
484  XSetErrorHandler( old_error_handler );
485 #endif
486 
487  if( window && attempts > 1 )
488  {
489  ROS_INFO( "Created render window after %d attempts.", attempts );
490  }
491 
492  return window;
493 }
494 
495 
496 } // end namespace rviz
#define NULL
Definition: global.h:37
#define ROS_FATAL(...)
static void configureLogging()
Configure the Ogre::LogManager to give the currently selected behavior. This must be called before Og...
#define ROS_INFO_ONCE(...)
static RenderSystem * instance_
std::string get_ogre_plugin_path()
static RenderSystem * get()
static int force_gl_version_
Ogre::RenderWindow * makeRenderWindow(WindowIDType window_id, unsigned int width, unsigned int height, double pixel_ratio=1.0)
XmlRpcServer s
static void forceGlVersion(int version)
Ogre::RenderWindow * tryMakeRenderWindow(const std::string &name, unsigned int width, unsigned int height, const Ogre::NameValuePairList *params, int max_attempts)
WindowIDType dummy_window_id_
unsigned long WindowIDType
Definition: render_system.h:51
Ogre::Root * ogre_root_
static void disableAntiAliasing()
#define ROS_WARN(...)
None
#define ROS_INFO(...)
void prepareOverlays(Ogre::SceneManager *scene_manager)
ROSLIB_DECL std::string getPath(const std::string &package_name)
ROSLIB_DECL void getPlugins(const std::string &package, const std::string &attribute, V_string &plugins, bool force_recrawl=false)
static bool force_no_stereo_
#define ROS_INFO_STREAM(args)
static bool x_baddrawable_error
Ogre::OverlaySystem * ogre_overlay_system_
static void forceNoStereo()
static bool use_anti_aliasing_
#define ROS_ERROR(...)
#define ROS_DEBUG(...)


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust
autogenerated on Wed Aug 28 2019 04:01:51