Skip to content

Commit

Permalink
Version 2.1.4: Switch to GLAD, minor improvements to simulate.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 439277749
Change-Id: I741d1c499ae88753338fcc6d141a65e92e13023e
  • Loading branch information
saran-t committed Apr 4, 2022
1 parent 3c71720 commit 90dea1b
Show file tree
Hide file tree
Showing 23 changed files with 276 additions and 304 deletions.
2 changes: 1 addition & 1 deletion cmake/ShellTests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function(add_mujoco_shell_test TEST_NAME TARGET_BINARY)
set_property(
TEST "${TEST_NAME}"
APPEND
PROPERTY ENVIRONMENT "MUJOCO_DLL_DIR=$<TARGET_FILE_DIR:mujoco_nogl>"
PROPERTY ENVIRONMENT "MUJOCO_DLL_DIR=$<TARGET_FILE_DIR:mujoco>"
)
endif()
endif()
Expand Down
28 changes: 14 additions & 14 deletions doc/APIreference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2437,7 +2437,7 @@ mjrContext
int charHeightBig; // character heights: big
// capabilities
int glewInitialized; // is glew initialized
int glInitialized; // is OpenGL initialized
int windowAvailable; // is default/window framebuffer available
int windowSamples; // number of samples for default/window framebuffer
int windowStereo; // is stereo available for default/window framebuffer
Expand Down Expand Up @@ -2905,11 +2905,11 @@ mjcb_control
fields, their values do not correspond to the current time step.
| The control callback is called from within :ref:`mj_forward` and :ref:`mj_step`, just before the controls and applied
forces are needed. When using the RK integrator, it will be called 4 times per step. The alternative way of specifying
controls and applied forces is to set them before mj_step, or use mj_step1 and mj_step2. The latter approach allows
setting the controls after the position and velocity computations have been performed by mj_step1, allowing these
results to be utilized in computing the control (similar to using mjcb_control). However, the only way to change the
controls between sub-steps of the RK integrator is to define the control callback.
forces are needed. When using the RK integrator, it will be called 4 times per step. The alternative way of specifying
controls and applied forces is to set them before ``mj_step``, or use ``mj_step1`` and ``mj_step2``. The latter approach
allows setting the controls after the position and velocity computations have been performed by ``mj_step1``, allowing
these results to be utilized in computing the control (similar to using mjcb_control). However, the only way to change
the controls between sub-steps of the RK integrator is to define the control callback.

.. _mjcb_contactfilter:

Expand Down Expand Up @@ -3411,15 +3411,15 @@ Print internal XML schema as plain text or HTML, with style-padding or ``&nbsp;`
Main simulation
^^^^^^^^^^^^^^^

| These are the main entry points to the simulator. Most users will only need to call mj_step, which computes everything
and advanced the simulation state by one time step. Controls and applied forces must either be set in advance (in
mjData.ctrl, qfrc_applied and xfrc_applied), or a control callback mjcb_control must be installed which will be called
just before the controls and applied forces are needed. Alternatively, one can use mj_step1 and mj_step2 which break
down the simulation pipeline into computations that are executed before and after the controls are needed; in this way
one can set controls that depend on the results from mj_step1. Keep in mind though that the RK4 solver does not work
with mj_step1/2.
| These are the main entry points to the simulator. Most users will only need to call ``mj_step``, which computes
everything and advanced the simulation state by one time step. Controls and applied forces must either be set in advance
(in mjData.ctrl, qfrc_applied and xfrc_applied), or a control callback mjcb_control must be installed which will be
called just before the controls and applied forces are needed. Alternatively, one can use ``mj_step1`` and ``mj_step2``
which break down the simulation pipeline into computations that are executed before and after the controls are needed;
in this way one can set controls that depend on the results from ``mj_step1``. Keep in mind though that the RK4 solver
does not work with mj_step1/2.

| mj_forward performs the same computations as mj_step but without the integration. It is useful after loading or
| mj_forward performs the same computations as ``mj_step`` but without the integration. It is useful after loading or
resetting a model (to put the entire mjData in a valid state), and also for out-of-order computations that involve
sampling or finite-difference approximations.
Expand Down
43 changes: 43 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,49 @@
Changelog
=========

Version 2.1.4 (Apr. 4, 2022)
-----------------------------

General
^^^^^^^

1. MuJoCo now uses GLAD to manage OpenGL API access instead of GLEW. On Linux, there is no longer a need to link against
different GL wrangling libraries depending on whether GLX, EGL, or OSMesa is being used. Instead, users can simply
use GLX, EGL, or OSMesa to create a GL context and ``mjr_makeContext`` will detect which one is being used.

#. Add visualisation for contact frames. This is useful when writing or modifying collision functions, when the actual
direction of the x and y axes of a contact can be important.

Binary build
^^^^^^^^^^^^

3. The ``_nogl`` dynamic library is no longer provided on Linux and Windows. The switch to GLAD allows us to resolve
OpenGL symbols when ``mjr_makeContext`` is called rather than when the library is loaded. As a result, the MuJoCo
library no longer has an explicit dynamic dependency on OpenGL, and can be used on system where OpenGL is not
present.

Simulate
^^^^^^^^

4. Fix a bug in simulate where pressing '[' or ']' when a model is not loaded causes a crash.

#. Contact frame visualisation is added to the Simulate GUI.

#. Rename "set key", "reset to key" to "save key" and "load key", respectively.

#. Change bindings of F6 and F7 from the not very useful "vertical sync" and "busy wait" to the more useful cycling of
frames and labels.

Bug fixes
^^^^^^^^^

8. ``mj_resetData`` zeroes out the ``solver_nnz`` field.

#. Remove a special branch in ``mju_quat2mat`` for unit quaternions. Previously, ``mju_quat2mat`` skipped all
computation if the real part of the quaternion equals 1.0. For very small angles (e.g. when finite differencing), the
cosine can evaluate to exactly 1.0 at double precision while the sine is still nonzero.


Version 2.1.3 (Mar. 23, 2022)
-----------------------------

Expand Down
93 changes: 21 additions & 72 deletions doc/programming.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,16 @@ be used in C++ programs.

MuJoCo is a free product currently distributed as a pre-built dynamic library and will soon be made available as an
open-source project. The software distribution contains a compiled version of GLFW which is used in the code samples to
create an OpenGL window and direct user input to it. The Linux distribution also contains compiled versions of GLEW
which is used for OpenGL symbol loading and allow the user to choose between X11, EGL or MESA. For projects where
rendering is not needed, there is a smaller "nogl" library which does not have a dependence on OpenGL. This is suitable
for running on headless servers without video drivers installed. The distribution for each platform contains the
following dynamic libraries:
create an OpenGL window and direct user input to it. The distribution for each platform contains the following dynamic
library:

.. code-block:: Text
Windows: mujoco210.dll (stub library: mujoco210.lib)
mujoco210nogl.dll (stub library: mujoco210nogl.lib)
glfw3.dll (stub library: glfw3.lib)
Windows: mujoco.dll (stub library: mujoco.lib)
Linux: mujoco210.so
mujoco210nogl.so
glewXXX.so
glfw.so.3
Linux: mujoco.so.2.1.4
macOS: mujoco210.dylib
mujoco210nogl.dylib
glfw.3.dylib
Note that the software :ref:`version <inVersion>` number is contained in the library name (and obviously changes with
every release), so for example ``mujoco210`` means version 2.1.
macOS: mujoco.2.1.4.dylib
Even though MuJoCo is a single dynamic library with unified C API, it contains several modules, some of which are
implemented in C++. We have taken advantage of the convenience of C++ for functionality that is used before the
Expand Down Expand Up @@ -154,11 +141,6 @@ API. While we encourage users to upgrade to the latest version, we recognize tha
especially when other developers release software that relies on MuJoCo. Therefore we have introduced simple
mechanisms to help avoid version conflicts, as follows.

As noted above, the version number is contained in the name of the dynamic library, e.g. mujoco210.dll for version 2.1.
Thus if an executable was compiled and linked with version 2.1 and the currently installed MuJoCo version is different,
the dynamic library will not be found. Please avoid the temptation to rename the library so as to fool the dynamic
linker; this is never a good idea. Instead you should obtain the required version of the library.

The situation is more subtle if existing code was developed with a certain version of MuJoCo, and is now being
compiled and linked with a different version. If the definitions of the API functions used in that code have changed,
either the compiler or the linker will generate errors. But even if the function definitions have not changed, it may
Expand Down Expand Up @@ -224,55 +206,22 @@ mjcb\_
Using OpenGL
~~~~~~~~~~~~

The use of MuJoCo's native OpenGL renderer will be explained in :ref:`Rendering`. Here we only cover issues
related to external libraries and resolving dependencies. For projects that do not need rendering, one can use the
"nogl" version of the MuJoCo library.

For rendering MuJoCo uses OpenGL 1.5 with the ARB_framebuffer_object extension (provided by all modern drivers.) It
also uses GLEW 2.0.0 for loading OpenGL symbols. On Windows and macOS, both GLEW and the OpenGL library (OpenGL32.lib
or OpenGL.framework respectively) are linked with MuJoCo. On these platforms the user does not have to take additional
steps to resolve dependencies.

On Linux the situation is more complex, because there are multiple OpenGL implementations and ways to load symbols.
The renderer and linking process are organized so as to allow multiple use cases shown below. libmujoco210.so calls
GLEW and OpenGL functions without linking the corresponding libraries. Users must resolve the dependencies by linking
whatever flavor of GLEW and OpenGL are suitable for their needs. For illustration, see how
:ref:`record.cc <saRecord>` on Linux is compiled and linked in three different ways (makefile in the sample
directory).

No OpenGL: link with **libmujoco210nogl**.so
This version of the MuJoCo library is compiled without the renderer, so it does not make any calls to OpenGL or GLEW.
It can be used on compute servers where graphics drivers are not installed. The main header file mujoco.h still
declares the rendering functions (mjr_XXX), but the library does not implement them, therefore calling these
functions from user code will result in unresolved symbols at link time. In the code samples, we use this version of
the library in text-only applications.
X11 OpenGL: link with **libmujoco210**.so, **libglew**.so, **libGL**.so
This is the most common way of using OpenGL on Linux desktop, with X11 for context creation and symbol loading.
OSMESA OpenGL: link with **libmujoco210**.so, **libglewosmesa**.so, **libOSMesa**.so
This can be used for software rendering with the OSMesa library. Note that we are linking a different version of GLEW
here, built with OSMesa support instead of the standard GLX. Ideally users will find a way to avoid software
rendering and use hardware acceleration. But OSMesa is a convenient fall-back option when all else fails.
EGL OpenGL: link with **libmujoco210**.so, **libEGL**.so, **libglewegl**.so, **libOpenGL**.so
This is the key feature for headless rendering. It enables hardware-accelerated OpenGL on servers without X11. User
code must use EGL for context creation, as illustrated in :ref:`record.cc <saRecord>`. libglewegl.so uses EGL to
load OpenGL symbols instead of using GLX. libOpenGL.so is the vendor-independent library which exposes only OpenGL
functionality without introducing a dependence on X11 (as opposed to libGL.so which depends on libGLX.so). NVidia's
drivers provide libOpenGL.so when installed with the "--install-libglvnd" option. libEGL.so can be obtained from Mesa
and is driver-independent (sudo apt-get install libegl1-mesa-dev).

Finally, instead of using the compiled libglew we have provided, users can compile their own, or link glew.c statically
in their project (it is a single C file). Static linking requires the GLEW_STATIC symbol to be defined. In addition, the
following symbols must be defined when building GLEW 2.0.0 for different use cases:

::
The use of MuJoCo's native OpenGL renderer will be explained in :ref:`Rendering`. For rendering, MuJoCo uses OpenGL 1.5
in the compatibility profile with the ``ARB_framebuffer_object`` and ``ARB_vertex_buffer_object`` extensions. OpenGL
symbols are loaded via `GLAD <https://github.com/Dav1dde/glad>`_ the first time the :ref:`mjr_makeContext` function
is called. This means that the MuJoCo library itself does not have an explicit dependency on OpenGL and can be used
on systems without OpenGL support, as long as ``mjr_`` functions are not called.

libglew.so: GLEW_NO_GLU
libglewegl.so: GLEW_NO_GLU GLEW_EGL
libgleweomesa.so: GLEW_NO_GLU GLEW_OSMESA
Applications that use MuJoCo's built-in rendering functionalities are responsible for linking against an appropriate
OpenGL context creation library and for ensuring that there is an OpenGL context that is made current on the running
thread. On Windows and macOS, there is a canonical OpenGL library provided by the operating system. On Linux, MuJoCo
currently supports GLX for rendering to an X11 window, OSMesa for headless software rendering, and EGL for hardware
accelerated headless rendering.

For headless rendering to work, it is essential to eliminate the dependence on GLU, because otherwise a dependence on
X11 will be introduced via libGLU.so. Note that GLEW can also be built for Mir and Wayland. We have not tested these,
but in theory they should work.
Before version 2.1.4, MuJoCo used GLEW rather than GLAD to manage OpenGL symbols, which required linking against
different GLEW libraries at build time depending on the GL implementation used. In order to avoid having manage OpenGL
dependency when no rendering was required, "nogl" builds of the library was made available. Since OpenGL symbols are
now lazily resolved at runtime after the switch to GLAD, the "nogl" libraries are no longer provided.

.. _Sample:

Expand Down Expand Up @@ -641,7 +590,7 @@ but these are finer points).

Instead of relying on a control callback, we could set the control vector ``mjData.ctrl`` directly. Alternatively we
could set applied forces as explained in :ref:`state and control <siStateControl>`. If we could compute these control-
related quantities before mj_step is called, then the simulation loop for the controlled dynamics (without using a
related quantities before ``mj_step`` is called, then the simulation loop for the controlled dynamics (without using a
control callback) would become

.. code-block:: C
Expand All @@ -652,7 +601,7 @@ control callback) would become
mj_step(m, d);
}
Why would we not be able to compute the controls before mj_step is called? After all, isn't this what causality means?
Why would we not be able to compute the controls before ``mj_step`` is called? After all, isn't this what causality means?
The answer is subtle but important, and has to do with the fact that we are simulating in discrete time. The top-level
simulation function ``mj_step`` basically does two things: compute the :ref:`forward dynamics <siForward>` in continuous
time, and then integrate over a time period specified by ``mjModel.opt.timestep``. Forward dynamics computes the
Expand Down
17 changes: 17 additions & 0 deletions doc/python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,23 @@ Functions
This allows for some thread-based parallelism, however users should bear in mind that the GIL is only released for the
duration of the MuJoCo C function itself, and not during the execution of any other Python code.

.. note::
One place where the bindings do offer added functionality is the top-level :ref:`mj_step` function. Since it is
often called in a loop, we have added an additional ``nstep`` argument, indicating how many times the underlying
:ref:`mj_step` should be called. If not specified, ``nstep`` takes the default value of 1. The following two code
snippets perform the same computation, but the first one does so without acquiring the GIL in between subsequent
physics steps:

.. code-block:: python
mj_step(model, data, nstep=20)
.. code-block:: python
for _ in range(20):
mj_step(model, data)
Enums and constants
===================

Expand Down
4 changes: 2 additions & 2 deletions doc/unity.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ _____

The MuJoCo app needs to be run at least once before the native library can be used, in order to register the library as
a trusted binary. Then, copy the dynamic library file from
``/Applications/MuJoCo.app/Contents/Frameworks/MuJoCo.framework/Versions/Current/libmujoco.2.1.1.dylib`` (it can be
``/Applications/MuJoCo.app/Contents/Frameworks/MuJoCo.framework/Versions/Current/libmujoco.2.1.4.dylib`` (it can be
found by browsing the contents of ``MuJoCo.app``) and rename it as ``mujoco.dylib``.

Linux
_____

Expand the ``tar.gz`` archive to ``~/.mujoco``. Then copy the dynamic library from
``~/.mujoco/mujoco-2.1.1/lib/libmujoco_nogl.so.2.1.1`` (note the ``_nogl`` suffix) and rename it as ``libmujoco.so``.
``~/.mujoco/mujoco-2.1.4/lib/libmujoco.so.2.1.4`` and rename it as ``libmujoco.so``.

Windows
_______
Expand Down
2 changes: 1 addition & 1 deletion include/mjrender.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ struct mjrContext_ { // custom OpenGL context
int charHeightBig; // character heights: big

// capabilities
int glewInitialized; // is glew initialized
int glInitialized; // is OpenGL initialized
int windowAvailable; // is default/window framebuffer available
int windowSamples; // number of samples for default/window framebuffer
int windowStereo; // is stereo available for default/window framebuffer
Expand Down
1 change: 1 addition & 0 deletions include/mjvisualize.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ typedef enum mjtFrame_ { // frame visualization
mjFRAME_SITE, // site frames
mjFRAME_CAMERA, // camera frames
mjFRAME_LIGHT, // light frames
mjFRAME_CONTACT, // contact frames
mjFRAME_WORLD, // world frame

mjNFRAME // number of visualization frames
Expand Down
22 changes: 11 additions & 11 deletions include/mujoco.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ extern "C" {
#endif

// header version; should match the library version as returned by mj_version()
#define mjVERSION_HEADER 213
#define mjVERSION_HEADER 214

// needed to define size_t, fabs and log10
#include "stdlib.h"
Expand Down Expand Up @@ -79,21 +79,12 @@ MJAPI extern const char* mjVISSTRING[mjNVISFLAG][3];
MJAPI extern const char* mjRNDSTRING[mjNRNDFLAG][3];


//---------------------------------- Activation ----------------------------------------------------

// Return 1 (for backward compatibility).
MJAPI int mj_activate(const char* filename);

// Do nothing (for backward compatibility).
MJAPI void mj_deactivate(void);


//---------------------------------- Virtual file system -------------------------------------------

// Initialize VFS to empty (no deallocation).
MJAPI void mj_defaultVFS(mjVFS* vfs);

// Add file to VFS, return 0: success, 1: full, 2: repeated name, -1: not found on disk.
// Add file to VFS, return 0: success, 1: full, 2: repeated name, -1: failed to load.
MJAPI int mj_addFileVFS(mjVFS* vfs, const char* directory, const char* filename);

// Make empty file in VFS, return 0: success, 1: full, 2: repeated name.
Expand Down Expand Up @@ -768,6 +759,15 @@ MJAPI void mj_warning(mjData* d, int warning, int info);
MJAPI void mju_writeLog(const char* type, const char* msg);


//---------------------------------- Activation ----------------------------------------------------

// Return 1 (for backward compatibility).
MJAPI int mj_activate(const char* filename);

// Do nothing (for backward compatibility).
MJAPI void mj_deactivate(void);


//---------------------------------- Standard math -------------------------------------------------

#define mjMAX(a,b) (((a) > (b)) ? (a) : (b))
Expand Down
Loading

0 comments on commit 90dea1b

Please sign in to comment.