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 #if !defined(Q_OS_MAC) && !defined(Q_OS_WIN)
38 #include <X11/Xlib.h>
39 #include <X11/Xutil.h>
40 #include <GL/glx.h>
41 #endif
42 
43 #if defined(Q_OS_MAC)
44 #include <OpenGL/gl.h>
45 #endif
46 
47 // X.h #defines CursorShape to be "0". Qt uses CursorShape in normal
48 // C++ way. This wasn't an issue until ogre_logging.h (below)
49 // introduced a #include of <QString>.
50 #ifdef CursorShape
51 #undef CursorShape
52 #endif
53 
54 #include <ros/package.h> // This dependency should be moved out of here, it is just used for a search path.
55 #include <ros/console.h>
56 
58 #include <OgreRenderWindow.h>
59 #include <OgreSceneManager.h>
60 #include <Overlay/OgreOverlaySystem.h>
61 
62 #include <rviz/env_config.h>
64 
66 
67 #include <QMessageBox>
68 
69 namespace rviz
70 {
71 RenderSystem* RenderSystem::instance_ = nullptr;
75 
77 {
78  if (instance_ == nullptr)
79  {
80  instance_ = new RenderSystem();
81  }
82  return instance_;
83 }
84 
86 {
87  force_gl_version_ = version;
88  ROS_INFO_STREAM("Forcing OpenGl version " << (float)version / 100.0 << ".");
89 }
90 
92 {
93  use_anti_aliasing_ = false;
94  ROS_INFO("Disabling Anti-Aliasing");
95 }
96 
98 {
99  force_no_stereo_ = true;
100  ROS_INFO("Forcing Stereo OFF");
101 }
102 
103 RenderSystem::RenderSystem() : ogre_overlay_system_(nullptr), 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  ogre_overlay_system_ = new Ogre::OverlaySystem();
112  loadOgrePlugins();
114  ogre_root_->initialise(false);
116  detectGlVersion();
117  setupResources();
118  Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
119 }
120 
121 void RenderSystem::prepareOverlays(Ogre::SceneManager* scene_manager)
122 {
124  scene_manager->addRenderQueueListener(ogre_overlay_system_);
125 }
126 
128 {
129 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
130  dummy_window_id_ = 0;
131 #else
132  Display* display = XOpenDisplay(nullptr);
133 
134  if (display == nullptr)
135  {
136  ROS_WARN("$DISPLAY is invalid, falling back on default :0");
137  display = XOpenDisplay(":0");
138 
139  if (display == nullptr)
140  {
141  ROS_FATAL("Can't open default or :0 display. Try setting DISPLAY environment variable.");
142  throw std::runtime_error("Can't open default or :0 display!\n");
143  }
144  }
145 
146  int screen = DefaultScreen(display);
147 
148  int attribList[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16, GLX_STENCIL_SIZE, 8, None};
149 
150  XVisualInfo* visual = glXChooseVisual(display, screen, (int*)attribList);
151 
152  dummy_window_id_ = XCreateSimpleWindow(display, RootWindow(display, screen), 0, 0, 1, 1, 0, 0, 0);
153 
154  GLXContext context = glXCreateContext(display, visual, nullptr, 1);
155 
156  glXMakeCurrent(display, dummy_window_id_, context);
157 #endif
158 }
159 
161 {
162  std::string plugin_prefix = get_ogre_plugin_path() + "/";
163 #ifdef Q_OS_MAC
164  plugin_prefix += "lib";
165 #endif
166  ogre_root_->loadPlugin(plugin_prefix + "RenderSystem_GL");
167  ogre_root_->loadPlugin(plugin_prefix + "Plugin_OctreeSceneManager");
168  ogre_root_->loadPlugin(plugin_prefix + "Plugin_ParticleFX");
169 #if OGRE_VERSION >= OGRE_VERSION_CHECK(1, 11, 0)
170  ogre_root_->loadPlugin(plugin_prefix + "Codec_FreeImage");
171 #endif
172 }
173 
175 {
176  bool mesa_workaround = false;
177  if (force_gl_version_)
178  {
180  }
181  else
182  {
183  Ogre::RenderSystem* renderSys = ogre_root_->getRenderSystem();
184  const Ogre::RenderSystemCapabilities* caps = renderSys->createRenderSystemCapabilities();
185  ROS_INFO("OpenGL device: %s", caps->getDeviceName().c_str());
186  int major = caps->getDriverVersion().major;
187  int minor = caps->getDriverVersion().minor;
188  gl_version_ = major * 100 + minor * 10;
189 
190 #ifdef __linux__
191  std::string gl_version_string = (const char*)glGetString(GL_VERSION);
192  // The "Mesa 2" string is intended to match "Mesa 20.", "Mesa 21." and so on
193  mesa_workaround = gl_version_string.find("Mesa 2") != std::string::npos && gl_version_ >= 320;
194 #else
195  mesa_workaround = false;
196 #endif
197  }
198 
199  switch (gl_version_)
200  {
201  case 200:
202  glsl_version_ = 110;
203  break;
204  case 210:
205  glsl_version_ = 120;
206  break;
207  case 300:
208  glsl_version_ = 130;
209  break;
210  case 310:
211  glsl_version_ = 140;
212  break;
213  case 320:
214  glsl_version_ = 150;
215  break;
216  default:
217  if (gl_version_ > 320)
218  {
220  }
221  else
222  {
223  glsl_version_ = 0;
224  }
225  break;
226  }
227  if (mesa_workaround)
228  { // https://github.com/ros-visualization/rviz/issues/1508
229  ROS_INFO("OpenGl version: %.1f (GLSL %.1f) limited to GLSL 1.4 on Mesa system.",
230  (float)gl_version_ / 100.0, (float)glsl_version_ / 100.0);
231 
232  gl_version_ = 310;
233  glsl_version_ = 140;
234  return;
235  }
236  ROS_INFO("OpenGl version: %.1f (GLSL %.1f).", (float)gl_version_ / 100.0, (float)glsl_version_ / 100.0);
237 }
238 
240 {
241  Ogre::RenderSystem* renderSys;
242  // Get the list of available renderers.
243  const Ogre::RenderSystemList* rsList = &(ogre_root_->getAvailableRenderers());
244 
245  // Look for the OpenGL one, which we require.
246  renderSys = nullptr;
247  for (unsigned int i = 0; i < rsList->size(); i++)
248  {
249  renderSys = rsList->at(i);
250  if (renderSys->getName().compare("OpenGL Rendering Subsystem") == 0)
251  {
252  break;
253  }
254  }
255 
256  if (renderSys == nullptr)
257  {
258  throw std::runtime_error("Could not find the opengl rendering subsystem!\n");
259  }
260 
261  // We operate in windowed mode
262  renderSys->setConfigOption("Full Screen", "No");
263 
269  // renderSys->setConfigOption("RTT Preferred Mode", "FBO");
270 
271  // Set the Full Screen Anti-Aliasing factor.
272  if (use_anti_aliasing_)
273  {
274  renderSys->setConfigOption("FSAA", "4");
275  }
276 
277  ogre_root_->setRenderSystem(renderSys);
278 }
279 
281 {
282  std::string rviz_path = ros::package::getPath(ROS_PACKAGE_NAME);
283  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
284  rviz_path + "/ogre_media", "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
285  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
286  rviz_path + "/ogre_media/textures", "FileSystem",
287  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
288  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
289  rviz_path + "/ogre_media/fonts", "FileSystem",
290  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true);
291  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
292  rviz_path + "/ogre_media/models", "FileSystem",
293  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
294  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
295  rviz_path + "/ogre_media/materials", "FileSystem",
296  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
297  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
298  rviz_path + "/ogre_media/materials/scripts", "FileSystem",
299  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
300  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
301  rviz_path + "/ogre_media/materials/glsl120", "FileSystem",
302  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
303  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
304  rviz_path + "/ogre_media/materials/glsl120/nogp", "FileSystem",
305  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
306  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
307  rviz_path + "/ogre_media/materials/glsl120/include", "FileSystem",
308  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
309  // Add resources that depend on a specific glsl version.
310  // Unfortunately, Ogre doesn't have a notion of glsl versions so we can't go
311  // the 'official' way of defining multiple schemes per material and let Ogre decide which one to use.
312  if (getGlslVersion() >= 150)
313  {
314  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
315  rviz_path + "/ogre_media/materials/glsl150", "FileSystem",
316  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
317  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
318  rviz_path + "/ogre_media/materials/scripts150", "FileSystem",
319  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
320  }
321  else if (getGlslVersion() >= 120)
322  {
323  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
324  rviz_path + "/ogre_media/materials/scripts120", "FileSystem",
325  Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
326  }
327  else
328  {
329  std::string s = "Your graphics driver does not support OpenGL 2.1. Please enable software rendering "
330  "before running RViz (e.g. type 'export LIBGL_ALWAYS_SOFTWARE=1').";
331  QMessageBox msgBox;
332  msgBox.setText(s.c_str());
333  msgBox.exec();
334  throw std::runtime_error(s);
335  }
336 
337  // Add paths exported to the "media_export" package.
338  std::vector<std::string> media_paths;
339  ros::package::getPlugins("media_export", "ogre_media_path", media_paths);
340  std::string delim(":");
341  for (std::vector<std::string>::iterator iter = media_paths.begin(); iter != media_paths.end(); ++iter)
342  {
343  if (!iter->empty())
344  {
345  std::string path;
346  int pos1 = 0;
347  int pos2 = iter->find(delim);
348  while (pos2 != (int)std::string::npos)
349  {
350  path = iter->substr(pos1, pos2 - pos1);
351  ROS_DEBUG("adding resource location: '%s'\n", path.c_str());
352  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
353  path, "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
354  pos1 = pos2 + 1;
355  pos2 = iter->find(delim, pos2 + 1);
356  }
357  path = iter->substr(pos1, iter->size() - pos1);
358  ROS_DEBUG("adding resource location: '%s'\n", path.c_str());
359  Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
360  path, "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
361  }
362  }
363 }
364 
365 // On Intel graphics chips under X11, there sometimes comes a
366 // BadDrawable error during Ogre render window creation. It is not
367 // consistent, happens sometimes but not always. Underlying problem
368 // seems to be a driver bug. My workaround here is to notice when
369 // that specific BadDrawable error happens on request 136 minor 3
370 // (which is what the problem looks like when it happens) and just try
371 // over and over again until it works (or until 100 failures, which
372 // makes it seem like it is a different bug).
373 static bool x_baddrawable_error = false;
374 #ifdef Q_WS_X11
375 static int (*old_error_handler)(Display*, XErrorEvent*);
376 int checkBadDrawable(Display* display, XErrorEvent* error)
377 {
378  if (error->error_code == BadDrawable && error->request_code == 136 && error->minor_code == 3)
379  {
380  x_baddrawable_error = true;
381  return 0;
382  }
383  else
384  {
385  // If the error does not exactly match the one from the driver bug,
386  // handle it the normal way so we see it.
387  return old_error_handler(display, error);
388  }
389 }
390 #endif // Q_WS_X11
391 
392 Ogre::RenderWindow* RenderSystem::makeRenderWindow(WindowIDType window_id,
393  unsigned int width,
394  unsigned int height,
395  double pixel_ratio)
396 {
397  static int windowCounter = 0; // Every RenderWindow needs a unique name, oy.
398 
399  Ogre::NameValuePairList params;
400  Ogre::RenderWindow* window = nullptr;
401 
402  params["externalWindowHandle"] = Ogre::StringConverter::toString(window_id);
403  params["parentWindowHandle"] = Ogre::StringConverter::toString(window_id);
404 
405  params["externalGLControl"] = true;
406 
407  // Enable antialiasing
408  if (use_anti_aliasing_)
409  {
410  params["FSAA"] = "4";
411  }
412 
413 // Set the macAPI for Ogre based on the Qt implementation
414 #if defined(Q_OS_MAC)
415  params["macAPI"] = "cocoa";
416  params["macAPICocoaUseNSView"] = "true";
417 #endif
418  params["contentScalingFactor"] = std::to_string(pixel_ratio);
419 
420  std::ostringstream stream;
421  stream << "OgreWindow(" << windowCounter++ << ")";
422 
423 
424 // don't bother trying stereo if Ogre does not support it.
425 #if !OGRE_STEREO_ENABLE
426  force_no_stereo_ = true;
427 #endif
428 
429  // attempt to create a stereo window
430  bool is_stereo = false;
431  if (!force_no_stereo_)
432  {
433  params["stereoMode"] = "Frame Sequential";
434  window = tryMakeRenderWindow(stream.str(), width, height, &params, 100);
435  params.erase("stereoMode");
436 
437  if (window)
438  {
439 #if OGRE_STEREO_ENABLE
440  is_stereo = window->isStereoEnabled();
441 #endif
442  if (!is_stereo)
443  {
444  // Created a non-stereo window. Discard it and try again (below)
445  // without the stereo parameter.
446  ogre_root_->detachRenderTarget(window);
447  window->destroy();
448  window = nullptr;
449  stream << "x";
450  is_stereo = false;
451  }
452  }
453  }
454 
455  if (window == nullptr)
456  {
457  window = tryMakeRenderWindow(stream.str(), width, height, &params, 100);
458  }
459 
460  if (window == nullptr)
461  {
462  ROS_ERROR("Unable to create the rendering window after 100 tries.");
463  assert(false);
464  }
465 
466  if (window)
467  {
468  window->setActive(true);
469  // window->setVisible(true);
470  window->setAutoUpdated(false);
471  }
472 
473  stereo_supported_ = is_stereo;
474 
475  ROS_INFO_ONCE("Stereo is %s", stereo_supported_ ? "SUPPORTED" : "NOT SUPPORTED");
476 
477  return window;
478 }
479 
480 Ogre::RenderWindow* RenderSystem::tryMakeRenderWindow(const std::string& name,
481  unsigned int width,
482  unsigned int height,
483  const Ogre::NameValuePairList* params,
484  int max_attempts)
485 {
486  Ogre::RenderWindow* window = nullptr;
487  int attempts = 0;
488 
489 #ifdef Q_WS_X11
490  old_error_handler = XSetErrorHandler(&checkBadDrawable);
491 #endif
492 
493  while (window == nullptr && (attempts++) < max_attempts)
494  {
495  try
496  {
497  window = ogre_root_->createRenderWindow(name, width, height, false, params);
498 
499  // If the driver bug happened, tell Ogre we are done with that
500  // window and then try again.
502  {
503  ogre_root_->detachRenderTarget(window);
504  window = nullptr;
505  x_baddrawable_error = false;
506  }
507  }
508  catch (const std::exception& ex)
509  {
510  std::cerr << "rviz::RenderSystem: error creating render window: " << ex.what() << std::endl;
511  window = nullptr;
512  }
513  }
514 
515 #ifdef Q_WS_X11
516  XSetErrorHandler(old_error_handler);
517 #endif
518 
519  if (window && attempts > 1)
520  {
521  ROS_INFO("Created render window after %d attempts.", attempts);
522  }
523 
524  return window;
525 }
526 
527 
528 } // end namespace rviz
rviz::RenderSystem::glsl_version_
int glsl_version_
Definition: render_system.h:123
render_system.h
rviz::RenderSystem::use_anti_aliasing_
static bool use_anti_aliasing_
Definition: render_system.h:124
rviz::RenderSystem::tryMakeRenderWindow
Ogre::RenderWindow * tryMakeRenderWindow(const std::string &name, unsigned int width, unsigned int height, const Ogre::NameValuePairList *params, int max_attempts)
Definition: render_system.cpp:480
env_config.h
ros::package::getPath
ROSLIB_DECL std::string getPath(const std::string &package_name)
rviz::RenderSystem::detectGlVersion
void detectGlVersion()
Definition: render_system.cpp:174
rviz::RenderSystem::force_gl_version_
static int force_gl_version_
Definition: render_system.h:125
rviz::RenderSystem::get
static RenderSystem * get()
Definition: render_system.cpp:76
s
XmlRpcServer s
version_check.h
rviz::RenderSystem::stereo_supported_
bool stereo_supported_
Definition: render_system.h:126
rviz::RenderSystem::ogre_root_
Ogre::Root * ogre_root_
Definition: render_system.h:119
rviz::RenderSystem::forceGlVersion
static void forceGlVersion(int version)
Definition: render_system.cpp:85
None
None
ogre_logging.h
rviz::OgreLogging::configureLogging
static void configureLogging()
Configure the Ogre::LogManager to give the currently selected behavior. This must be called before Og...
Definition: ogre_logging.cpp:95
rviz::RenderSystem::WindowIDType
unsigned long WindowIDType
Definition: render_system.h:51
rviz::Display
Definition: display.h:63
rviz::RenderSystem::makeRenderWindow
Ogre::RenderWindow * makeRenderWindow(WindowIDType window_id, unsigned int width, unsigned int height, double pixel_ratio=1.0)
Definition: render_system.cpp:392
console.h
rviz::x_baddrawable_error
static bool x_baddrawable_error
Definition: render_system.cpp:373
rviz::RenderSystem::ogre_overlay_system_
Ogre::OverlaySystem * ogre_overlay_system_
Definition: render_system.h:120
ROS_DEBUG
#define ROS_DEBUG(...)
ros::package::getPlugins
ROSLIB_DECL void getPlugins(const std::string &name, const std::string &attribute, std::vector< std::pair< std::string, std::string > > &exports, bool force_recrawl=false)
rviz
Definition: add_display_dialog.cpp:54
rviz::get_ogre_plugin_path
std::string get_ogre_plugin_path()
rviz::RenderSystem::loadOgrePlugins
void loadOgrePlugins()
Definition: render_system.cpp:160
rviz::RenderSystem::force_no_stereo_
static bool force_no_stereo_
Definition: render_system.h:127
ROS_INFO_ONCE
#define ROS_INFO_ONCE(...)
rviz::RenderSystem::setupResources
void setupResources()
Definition: render_system.cpp:280
rviz::RenderSystem
Definition: render_system.h:45
ROS_WARN
#define ROS_WARN(...)
ROS_INFO_STREAM
#define ROS_INFO_STREAM(args)
rviz::RenderSystem::dummy_window_id_
WindowIDType dummy_window_id_
Definition: render_system.h:117
package.h
ROS_FATAL
#define ROS_FATAL(...)
rviz::RenderSystem::prepareOverlays
void prepareOverlays(Ogre::SceneManager *scene_manager)
Definition: render_system.cpp:121
rviz::RenderSystem::RenderSystem
RenderSystem()
Definition: render_system.cpp:103
rviz::RenderSystem::disableAntiAliasing
static void disableAntiAliasing()
Definition: render_system.cpp:91
ROS_ERROR
#define ROS_ERROR(...)
rviz::RenderSystem::setupRenderSystem
void setupRenderSystem()
Definition: render_system.cpp:239
rviz::RenderSystem::setupDummyWindowId
void setupDummyWindowId()
Definition: render_system.cpp:127
rviz::RenderSystem::forceNoStereo
static void forceNoStereo()
Definition: render_system.cpp:97
ROS_INFO
#define ROS_INFO(...)
rviz::RenderSystem::getGlslVersion
int getGlslVersion()
Definition: render_system.h:77
rviz::RenderSystem::instance_
static RenderSystem * instance_
Definition: render_system.h:114
rviz::RenderSystem::gl_version_
int gl_version_
Definition: render_system.h:122


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust, William Woodall
autogenerated on Fri Aug 2 2024 08:43:10