Skip to content

Commit f409be3

Browse files
committed
build: adds option to build w/ GLFW, EGL or OSMesa
Default build tries the following: If GLFW is found, it will be used for GUI and offscreen rendering. Otherwise GUI functionality is not provided. As fallback for offscreen rendering first GLE is searched, otherwise osmesa. In case neither can be found, offscreen rendering is disabled, too.
1 parent bb0a13a commit f409be3

13 files changed

+354
-52
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Loading and reset times are reported in the server debug log. All plugin stats c
2727
* Increased test coverage of `mujoco_ros_sensors` plugin.
2828
* Split monolithic ros interface tests into more individual tests.
2929
* Added sleeping at least until the next lowerbound GUI refresh when paused to reduce cpu load.
30+
* deprecated `no_x` launchparameter in favor of using `no_render`, as offscreen rendering now is also available without X.
3031

3132
Contributors: @DavidPL1
3233

mujoco_ros/CMakeLists.txt

+33-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
2121
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
2222
include(ProjectOption)
2323

24+
option(NO_GLFW "Disable GLFW3 support and try finding OpenGL EGL or OSMESA for offscreen rendering" OFF)
25+
option(USE_EGL "Build with EGL enabled offscreen rendering. Entails `NO_GLFW`" OFF)
26+
option(USE_OSMESA "Build with OSMESA enabled offscreen rendering. Entails `NO_GLFW`" OFF)
27+
2428
# Find catkin macros and libraries
2529
# if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
2630
# is used, also find other catkin packages
@@ -60,7 +64,35 @@ configure_project_option(
6064

6165
# Find MuJoCo
6266
find_package(mujoco 3.2.0 REQUIRED)
63-
find_library(GLFW libglfw.so.3)
67+
find_library(GLFW libglfw.so.3) # Find GLFW3 for GUI
68+
69+
70+
if (NO_GLFW OR USE_EGL OR USE_OSMESA OR ${GLFW} STREQUAL "GLFW-NOTFOUND")
71+
message(WARNING "GLFW3 not found or disabled. GUI will not be available.")
72+
73+
find_package(OpenGL COMPONENTS OpenGL EGL) # Find OpenGL (EGL) for offscreen rendering
74+
if (USE_OSMESA OR ${OpenGL_EGL_FOUND} STREQUAL "FALSE")
75+
message(WARNING "EGL not found or disabled. Falling back to OSMESA.")
76+
77+
find_package(OSMesa)
78+
79+
if (!OSMesa_FOUND)
80+
message(WARNING "EGL disabled or not found and OSMesa could not be found. Offscreen rendering will not be available!")
81+
else() # OSMesa found
82+
set(RENDERING_BACKEND "USE_OSMESA")
83+
message(STATUS "OSMesa found. Offscreen rendering available.")
84+
endif()
85+
86+
else() # EGL found
87+
set(RENDERING_BACKEND "USE_EGL")
88+
message(STATUS "EGL found. Offscreen rendering available.")
89+
endif()
90+
91+
else() # GLFW found
92+
set(RENDERING_BACKEND "USE_GLFW")
93+
message(STATUS "GLFW3 found. GUI and offscreen rendering available.")
94+
endif()
95+
6496

6597
# ###############################################
6698
# # Declare ROS dynamic reconfigure parameters ##

mujoco_ros/cmake/FindOSMesa.cmake

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#########
2+
# Taken from https://github.com/Kitware/VTK/blob/master/CMake/FindOSMesa.cmake
3+
#########
4+
5+
# Try to find Mesa off-screen library and include dir.
6+
# Once done this will define
7+
#
8+
# OSMesa_FOUND - true if OSMesa has been found
9+
# OSMesa_INCLUDE_DIRS - where the GL/osmesa.h can be found
10+
# OSMesa_LIBRARIES - Link this to use OSMesa
11+
# OSMesa_VERSION - Version of OSMesa found
12+
# OSMesa::OSMesa - Imported target
13+
14+
find_path(OSMESA_INCLUDE_DIR
15+
NAMES GL/osmesa.h
16+
PATHS "${OSMESA_ROOT}/include"
17+
"$ENV{OSMESA_ROOT}/include"
18+
/usr/openwin/share/include
19+
/opt/graphics/OpenGL/include
20+
DOC "OSMesa include directory")
21+
mark_as_advanced(OSMESA_INCLUDE_DIR)
22+
23+
find_library(OSMESA_LIBRARY
24+
NAMES OSMesa OSMesa16 OSMesa32
25+
PATHS "${OSMESA_ROOT}/lib"
26+
"$ENV{OSMESA_ROOT}/lib"
27+
/opt/graphics/OpenGL/lib
28+
/usr/openwin/lib
29+
DOC "OSMesa library")
30+
mark_as_advanced(OSMESA_LIBRARY)
31+
32+
if (OSMESA_INCLUDE_DIR AND EXISTS "${OSMESA_INCLUDE_DIR}/GL/osmesa.h")
33+
file(STRINGS "${OSMESA_INCLUDE_DIR}/GL/osmesa.h" _OSMesa_version_lines
34+
REGEX "OSMESA_[A-Z]+_VERSION")
35+
string(REGEX REPLACE ".*# *define +OSMESA_MAJOR_VERSION +([0-9]+).*" "\\1" _OSMesa_version_major "${_OSMesa_version_lines}")
36+
string(REGEX REPLACE ".*# *define +OSMESA_MINOR_VERSION +([0-9]+).*" "\\1" _OSMesa_version_minor "${_OSMesa_version_lines}")
37+
string(REGEX REPLACE ".*# *define +OSMESA_PATCH_VERSION +([0-9]+).*" "\\1" _OSMesa_version_patch "${_OSMesa_version_lines}")
38+
set(OSMesa_VERSION "${_OSMesa_version_major}.${_OSMesa_version_minor}.${_OSMesa_version_patch}")
39+
unset(_OSMesa_version_major)
40+
unset(_OSMesa_version_minor)
41+
unset(_OSMesa_version_patch)
42+
unset(_OSMesa_version_lines)
43+
endif ()
44+
45+
include(FindPackageHandleStandardArgs)
46+
find_package_handle_standard_args(OSMesa
47+
REQUIRED_VARS OSMESA_INCLUDE_DIR OSMESA_LIBRARY
48+
VERSION_VAR OSMesa_VERSION)
49+
50+
if (OSMesa_FOUND)
51+
set(OSMesa_INCLUDE_DIRS "${OSMESA_INCLUDE_DIR}")
52+
set(OSMesa_LIBRARIES "${OSMESA_LIBRARY}")
53+
54+
if (NOT TARGET OSMesa::OSMesa)
55+
add_library(OSMesa::OSMesa UNKNOWN IMPORTED)
56+
set_target_properties(OSMesa::OSMesa PROPERTIES
57+
IMPORTED_LOCATION "${OSMESA_LIBRARY}"
58+
INTERFACE_INCLUDE_DIRECTORIES "${OSMESA_INCLUDE_DIR}")
59+
endif ()
60+
endif ()

mujoco_ros/cmake/Findmujoco.cmake

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ if(NOT mujoco_FOUND)
2626
# Find dependencies
2727
cmake_policy(SET CMP0072 NEW)
2828
include(CMakeFindDependencyMacro)
29-
find_dependency(OpenGL REQUIRED)
29+
find_package(OpenGL)
3030

3131
if(mujoco_INCLUDE_DIRS AND mujoco_LIBRARIES)
3232
set(mujoco_FOUND TRUE)

mujoco_ros/include/mujoco_ros/common_types.h

-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@
4141
#include <ros/ros.h>
4242
#include <image_transport/image_transport.h>
4343

44-
#include <GLFW/glfw3.h>
45-
4644
namespace mujoco_ros {
4745

4846
using Clock = std::chrono::steady_clock;

mujoco_ros/include/mujoco_ros/mujoco_env.h

+18
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,12 @@
9090

9191
#include <rosgraph_msgs/Clock.h>
9292

93+
#if defined(USE_GLFW)
9394
#include <mujoco_ros/glfw_adapter.h>
9495
#include <mujoco_ros/glfw_dispatch.h>
96+
#elif defined(USE_OSMESA)
97+
#include <GL/osmesa.h>
98+
#endif
9599

96100
namespace mujoco_ros {
97101

@@ -116,7 +120,15 @@ struct OffscreenRenderContext
116120
mjvCamera cam;
117121
std::unique_ptr<unsigned char[]> rgb;
118122
std::unique_ptr<float[]> depth;
123+
#ifdef USE_GLFW
119124
std::shared_ptr<GLFWwindow> window;
125+
#elif defined(USE_OSMESA)
126+
struct
127+
{
128+
OSMesaContext ctx;
129+
unsigned char buffer[10000000]; // TODO: size necessary or resize later?
130+
} osmesa;
131+
#endif
120132
mjrContext con = {};
121133
mjvScene scn = {};
122134

@@ -268,7 +280,13 @@ class MujocoEnv
268280

269281
bool togglePaused(bool paused, const std::string &admin_hash = std::string());
270282

283+
#if defined(USE_GLFW)
271284
GlfwAdapter *gui_adapter_ = nullptr;
285+
#endif
286+
287+
#if defined(USE_EGL) || defined(USE_OSMESA)
288+
bool InitGL();
289+
#endif
272290

273291
void runRenderCbs(mjvScene *scene);
274292
bool step(int num_steps = 1, bool blocking = true);

mujoco_ros/launch/launch_server.launch

+6-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
<arg name="unpause" default="false" doc="Whether the simulation should be unpaused on start." />
88
<arg name="headless" default="false" />
99
<arg name="render_offscreen" default="true" doc="Whether offscreen rendering should be enabled." />
10-
<arg name="no_x" default="false" doc="Set to true to enable running on a server without X, disabling everything related to OpenGL rendering."/>
10+
<arg name="no_x" default="" doc="Set to true to enable running on a server without X, disabling everything related to OpenGL rendering. (deprecated)"/>
11+
<arg name="no_render" default="false" doc="Set to true to disabling rendering on- and off screen. (shorthand for render_offscreen:=false headless:=true)"/>
1112
<arg name="eval_mode" default="false" doc="Whether to run mujoco_ros in evaluation mode." />
1213
<arg name="admin_hash" default="''" doc="Hash to verify critical operations in evaluation mode." />
1314
<arg name="debug" default="false" doc="Whether to run with gdb." />
@@ -45,6 +46,7 @@
4546
<param name="headless" value="$(arg headless)" />
4647
<param name="render_offscreen" value="$(arg render_offscreen)" />
4748
<param name="no_x" value="$(arg no_x)" />
49+
<param name="no_render" value="$(arg no_render)" />
4850
<param name="num_steps" value="$(arg num_sim_steps)" />
4951
<param name="eval_mode" value="$(arg eval_mode)" />
5052
<param name="modelfile" value="$(arg modelfile)" />
@@ -61,6 +63,7 @@
6163
<param name="headless" value="$(arg headless)" />
6264
<param name="render_offscreen" value="$(arg render_offscreen)" />
6365
<param name="no_x" value="$(arg no_x)" />
66+
<param name="no_render" value="$(arg no_render)" />
6467
<param name="num_steps" value="$(arg num_sim_steps)" />
6568
<param name="eval_mode" value="$(arg eval_mode)" />
6669
<param name="modelfile" value="$(arg modelfile)" />
@@ -80,6 +83,7 @@
8083
<param name="headless" value="$(arg headless)" />
8184
<param name="render_offscreen" value="$(arg render_offscreen)" />
8285
<param name="no_x" value="$(arg no_x)" />
86+
<param name="no_render" value="$(arg no_render)" />
8387
<param name="num_steps" value="$(arg num_sim_steps)" />
8488
<param name="eval_mode" value="$(arg eval_mode)" />
8589
<param name="modelfile" value="$(arg modelfile)" />
@@ -99,6 +103,7 @@
99103
<param name="headless" value="$(arg headless)" />
100104
<param name="render_offscreen" value="$(arg render_offscreen)" />
101105
<param name="no_x" value="$(arg no_x)" />
106+
<param name="no_render" value="$(arg no_render)" />
102107
<param name="num_steps" value="$(arg num_sim_steps)" />
103108
<param name="eval_mode" value="$(arg eval_mode)" />
104109
<param name="modelfile" value="$(arg modelfile)" />

mujoco_ros/src/CMakeLists.txt

+40-24
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,32 @@ target_include_directories(lodepng PRIVATE
99
target_link_libraries(lodepng PRIVATE project_option)
1010
add_library(mujoco_ros::lodepng ALIAS lodepng)
1111

12-
add_library(platform_ui_adapter OBJECT
13-
$<TARGET_OBJECTS:lodepng>
14-
glfw_adapter.cc
15-
glfw_dispatch.cc
16-
platform_ui_adapter.cc
17-
)
18-
set_property(TARGET platform_ui_adapter PROPERTY POSITION_INDEPENDENT_CODE ON)
19-
target_include_directories(platform_ui_adapter PUBLIC
20-
${PROJECT_SOURCE_DIR}/include
21-
${GLFW_INTERFACE_INCLUDE_DIRECTORIES}
22-
)
23-
target_link_libraries(platform_ui_adapter
24-
PUBLIC
25-
mujoco::mujoco
26-
${GLFW}
27-
PRIVATE
28-
mujoco_ros::lodepng
29-
project_option
30-
project_warning
31-
)
32-
add_library(mujoco_ros::platform_ui_adapter ALIAS platform_ui_adapter)
12+
if(RENDERING_BACKEND STREQUAL "USE_GLFW")
13+
add_library(platform_ui_adapter OBJECT
14+
$<TARGET_OBJECTS:lodepng>
15+
glfw_adapter.cc
16+
glfw_dispatch.cc
17+
platform_ui_adapter.cc
18+
)
19+
set_property(TARGET platform_ui_adapter PROPERTY POSITION_INDEPENDENT_CODE ON)
20+
target_include_directories(platform_ui_adapter PUBLIC
21+
${PROJECT_SOURCE_DIR}/include
22+
${GLFW_INTERFACE_INCLUDE_DIRECTORIES}
23+
)
24+
target_link_libraries(platform_ui_adapter
25+
PUBLIC
26+
mujoco::mujoco
27+
${GLFW}
28+
PRIVATE
29+
mujoco_ros::lodepng
30+
project_option
31+
project_warning
32+
)
33+
add_library(mujoco_ros::platform_ui_adapter ALIAS platform_ui_adapter)
34+
endif()
3335

3436
add_library(${PROJECT_NAME}
35-
$<TARGET_OBJECTS:platform_ui_adapter>
37+
$<TARGET_OBJECTS:lodepng>
3638
mujoco_env.cpp
3739
viewer.cpp
3840
plugin_utils.cpp
@@ -42,6 +44,14 @@ add_library(${PROJECT_NAME}
4244
physics.cpp
4345
)
4446

47+
if(RENDERING_BACKEND STREQUAL "USE_GLFW")
48+
target_sources(${PROJECT_NAME} PRIVATE $<TARGET_OBJECTS:platform_ui_adapter>)
49+
endif()
50+
51+
if (RENDERING_BACKEND)
52+
target_compile_definitions(${PROJECT_NAME} PUBLIC ${RENDERING_BACKEND}=1)
53+
endif()
54+
4555
target_include_directories(${PROJECT_NAME}
4656
PUBLIC ${PROJECT_SOURCE_DIR}/include
4757
${mujoco_include_DIRS}
@@ -53,14 +63,20 @@ target_include_directories(${PROJECT_NAME}
5363
target_link_libraries(${PROJECT_NAME}
5464
PUBLIC
5565
mujoco::mujoco
56-
mujoco_ros::platform_ui_adapter
5766
catkin_pkg
5867
PRIVATE
59-
mujoco_ros::lodepng
6068
project_option
6169
project_warning
6270
)
6371

72+
if(RENDERING_BACKEND STREQUAL "USE_GLFW")
73+
target_link_libraries(${PROJECT_NAME} PUBLIC mujoco_ros::platform_ui_adapter)
74+
elseif(RENDERING_BACKEND STREQUAL "USE_EGL")
75+
target_link_libraries(${PROJECT_NAME} PUBLIC OpenGL::EGL)
76+
elseif(RENDERING_BACKEND STREQUAL "USE_OSMESA")
77+
target_link_libraries(${PROJECT_NAME} PUBLIC OSMesa::OSMesa)
78+
endif()
79+
6480
# Node Executable
6581
add_executable(mujoco_node
6682
main.cpp

mujoco_ros/src/main.cpp

+14-11
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434

3535
/* Authors: David P. Leins */
3636

37-
#include <mujoco_ros/glfw_adapter.h>
3837
#include <mujoco_ros/viewer.h>
3938
#include <mujoco_ros/mujoco_env.h>
4039

@@ -45,6 +44,10 @@
4544
#include <csignal>
4645
#include <thread>
4746

47+
#if defined(USE_GLFW)
48+
#include <mujoco_ros/glfw_adapter.h>
49+
#endif
50+
4851
namespace {
4952

5053
std::unique_ptr<mujoco_ros::MujocoEnv> env;
@@ -147,19 +150,19 @@ int main(int argc, char **argv)
147150
env->startPhysicsLoop();
148151
env->startEventLoop();
149152

153+
#ifdef USE_GLFW
150154
if (!env->settings_.headless) {
151-
// mjvCamera cam;
152-
// mjvOption opt;
153-
// mjv_defaultCamera(&cam);
154-
// mjv_defaultOption(&opt);
155155
ROS_INFO("Launching viewer");
156-
auto viewer =
157-
// std::make_unique<mujoco_ros::Viewer>(std::unique_ptr<mujoco_ros::PlatformUIAdapter>(env->gui_adapter_),
158-
// env.get(), &cam, &opt, /* is_passive = */ false);
159-
std::make_unique<mujoco_ros::Viewer>(std::unique_ptr<mujoco_ros::PlatformUIAdapter>(env->gui_adapter_),
160-
env.get(), /* is_passive = */ false);
156+
auto viewer = std::make_unique<mujoco_ros::Viewer>(
157+
std::unique_ptr<mujoco_ros::PlatformUIAdapter>(env->gui_adapter_), env.get(), /* is_passive = */ false);
161158
viewer->RenderLoop();
162-
} else {
159+
}
160+
#else
161+
if (!env->settings_.headless) {
162+
ROS_ERROR("GLFW backend not available. Cannot launch viewer");
163+
}
164+
#endif
165+
else {
163166
ROS_INFO("Running headless");
164167
}
165168

0 commit comments

Comments
 (0)