Remove `mjWARN_VGEOMFULL, handle visual geom buffer full warnings in mjvScene`.

PiperOrigin-RevId: 896483023
Change-Id: I6dde2c20d8e8e229cf95e1f002dd10525d3376e6
This commit is contained in:
Yuval Tassa
2026-04-08 07:15:59 -07:00
committed by Copybara-Service
parent 5a2cc6cee3
commit 0e04436d51
17 changed files with 47 additions and 53 deletions
+2
View File
@@ -44,6 +44,8 @@ General
- The ``vertcollide`` field in :ref:`mjsFlex` has been removed. It is no longer required since
:doc:`MuJoCo Warp <mjwarp/index>` supports native flex collisions.
- The :ref:`mjtWarning` enum value ``mjWARN_VGEOMFULL`` is removed. Exhaustion of visual geoms is now handled
internally by the :ref:`mjvScene`.
Bug fixes
^^^^^^^^^
+3 -2
View File
@@ -63,7 +63,6 @@ typedef enum mjtWarning_ { // warning types
mjWARN_INERTIA = 0, // (near) singular inertia matrix
mjWARN_CONTACTFULL, // too many contacts in contact list
mjWARN_CNSTRFULL, // too many constraints
mjWARN_VGEOMFULL, // too many visual geoms
mjWARN_BADQPOS, // bad number in qpos
mjWARN_BADQVEL, // bad number in qvel
mjWARN_BADQACC, // bad number in qacc
@@ -3096,7 +3095,9 @@ struct mjvScene_ { // abstract scene passed to OpenGL renderer
// framing
int framewidth; // frame pixel width; 0: disable framing
float framergb[3]; // frame color
int status; // status; 0: ok, 1: geoms exhausted
// geom buffer status
int status; // 0: ok, 1: geoms exhausted, warning issued
};
typedef struct mjvScene_ mjvScene;
struct mjvFigure_ { // abstract 2D figure passed to OpenGL renderer
-1
View File
@@ -77,7 +77,6 @@ typedef enum mjtWarning_ { // warning types
mjWARN_INERTIA = 0, // (near) singular inertia matrix
mjWARN_CONTACTFULL, // too many contacts in contact list
mjWARN_CNSTRFULL, // too many constraints
mjWARN_VGEOMFULL, // too many visual geoms
mjWARN_BADQPOS, // bad number in qpos
mjWARN_BADQVEL, // bad number in qvel
mjWARN_BADQACC, // bad number in qacc
+3 -1
View File
@@ -355,7 +355,9 @@ struct mjvScene_ { // abstract scene passed to OpenGL renderer
// framing
int framewidth; // frame pixel width; 0: disable framing
float framergb[3]; // frame color
int status; // status; 0: ok, 1: geoms exhausted
// geom buffer status
int status; // 0: ok, 1: geoms exhausted, warning issued
};
typedef struct mjvScene_ mjvScene;
+5 -1
View File
@@ -91,7 +91,11 @@ void SdfVisualizer::Visualize(const mjModel* m, const mjData* d,
for (int k = 0; k < 2; k++) {
for (int j = 0; j < (k == 0 ? 2 : n-1); j++) {
if (scn->ngeom >= scn->maxgeom) {
mj_warning((mjData*)d, mjWARN_VGEOMFULL, scn->maxgeom);
if (!scn->status) {
mju_warning("Pre-allocated visual geom buffer is full. "
"Increase maxgeom above %d.", scn->maxgeom);
scn->status = 1;
}
return;
}
mjvGeom* thisgeom = scn->geoms + scn->ngeom;
+5 -1
View File
@@ -427,7 +427,11 @@ void TouchGrid::Visualize(const mjModel* m, mjData* d, const mjvOption* opt,
continue;
}
if (scn->ngeom >= scn->maxgeom) {
mj_warning(d, mjWARN_VGEOMFULL, scn->maxgeom);
if (!scn->status) {
mju_warning("Pre-allocated visual geom buffer is full. "
"Increase maxgeom above %d.", scn->maxgeom);
scn->status = 1;
}
mj_freeStack(d);
return;
} else {
+5 -6
View File
@@ -578,12 +578,11 @@ ENUMS: Mapping[str, EnumDecl] = dict([
('mjWARN_INERTIA', 0),
('mjWARN_CONTACTFULL', 1),
('mjWARN_CNSTRFULL', 2),
('mjWARN_VGEOMFULL', 3),
('mjWARN_BADQPOS', 4),
('mjWARN_BADQVEL', 5),
('mjWARN_BADQACC', 6),
('mjWARN_BADCTRL', 7),
('mjNWARNING', 8),
('mjWARN_BADQPOS', 3),
('mjWARN_BADQVEL', 4),
('mjWARN_BADQACC', 5),
('mjWARN_BADCTRL', 6),
('mjNWARNING', 7),
]),
)),
('mjtTimer',
+2 -2
View File
@@ -5416,7 +5416,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([
name='warning',
type=ArrayType(
inner_type=ValueType(name='mjWarningStat'),
extents=(8,),
extents=(7,),
),
doc='warning statistics (mutable)',
),
@@ -10524,7 +10524,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([
StructFieldDecl(
name='status',
type=ValueType(name='int'),
doc='status; 0: ok, 1: geoms exhausted',
doc='0: ok, 1: geoms exhausted, warning issued',
),
),
)),
+1 -3
View File
@@ -14,8 +14,6 @@
# ==============================================================================
"""Tests for structs.py."""
import re
from absl.testing import absltest
from . import ast_nodes
@@ -36,7 +34,7 @@ class StructsTest(absltest.TestCase):
field_names.add(field.name)
if field.name == 'warning':
self.assertEqual(field.type,
type_parsing.parse_type('mjWarningStat[8]'))
type_parsing.parse_type('mjWarningStat[7]'))
self.assertEqual(field.doc, 'warning statistics (mutable)')
elif field.name == 'qpos':
self.assertEqual(field.type, type_parsing.parse_type('mjtNum*'))
+8 -8
View File
@@ -2142,11 +2142,7 @@ void Simulate::Sync(bool state_only) {
m_->stat = m_passive_->stat;
}
// synchronize number of mjWARN_VGEOMFULL warnings
if (d_passive_->warning[mjWARN_VGEOMFULL].number > warn_vgeomfull_prev_) {
d_->warning[mjWARN_VGEOMFULL].number +=
d_passive_->warning[mjWARN_VGEOMFULL].number - warn_vgeomfull_prev_;
}
}
if (pending_.save_xml) {
@@ -2334,7 +2330,7 @@ void Simulate::Sync(bool state_only) {
mjopt_prev_ = m_passive_->opt;
mjvis_prev_ = m_passive_->vis;
mjstat_prev_ = m_passive_->stat;
warn_vgeomfull_prev_ = d_passive_->warning[mjWARN_VGEOMFULL].number;
}
// update settings
@@ -2550,7 +2546,7 @@ void Simulate::LoadOnRenderThread() {
mjopt_prev_ = m_->opt;
opt_prev_ = opt;
cam_prev_ = cam;
warn_vgeomfull_prev_ = d_->warning[mjWARN_VGEOMFULL].number;
// full copy on init
m_passive_ = mj_copyModel(nullptr, m_);
@@ -3022,7 +3018,11 @@ void Simulate::RenderLoop() {
int nusergeom = user_scn_geoms_.size();
int ngeom = std::min(nusergeom, this->scn.maxgeom - this->scn.ngeom);
if (ngeom < nusergeom) {
mj_warning(d_passive_, mjWARN_VGEOMFULL, this->scn.maxgeom);
if (!this->scn.status) {
mju_warning("Pre-allocated visual geom buffer is full. "
"Increase maxgeom above %d.", this->scn.maxgeom);
this->scn.status = 1;
}
}
std::memcpy(this->scn.geoms + this->scn.ngeom, user_scn_geoms_.data(),
ngeom * sizeof(mjvGeom));
-2
View File
@@ -147,8 +147,6 @@ class Simulate {
mjvOption opt_prev_;
mjvCamera cam_prev_;
int warn_vgeomfull_prev_;
// pending GUI-driven actions, to be applied at the next call to Sync
struct {
std::optional<std::string> save_xml;
-4
View File
@@ -1595,10 +1595,6 @@ const char* mju_warningText(int warning, size_t info) {
"Increase arena memory allocation above %s bytes.", mju_writeNumBytes(info));
break;
case mjWARN_VGEOMFULL:
mjSNPRINTF(str, "Pre-allocated visual geom buffer is full. Increase maxgeom above %zu.", info);
break;
case mjWARN_BADQPOS:
mjSNPRINTF(str, "Nan, Inf or huge value in QPOS at DOF %zu. The simulation is unstable.", info);
break;
+5 -6
View File
@@ -169,7 +169,11 @@ static int bodycategory(const mjModel* m, int bodyid) {
mjvGeom* acquireGeom(mjvScene* scn, int objid, int category, int objtype) {
// check for overflow, SHOULD NOT OCCUR
if (scn->ngeom >= scn->maxgeom) {
scn->status = 1;
if (!scn->status) {
mju_warning("Pre-allocated visual geom buffer is full. "
"Increase maxgeom above %d.", scn->maxgeom);
scn->status = 1;
}
return NULL;
}
@@ -3379,7 +3383,6 @@ void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt,
const mjvPerturb* pert, mjvCamera* cam, int catmask, mjvScene* scn) {
// clear geoms
scn->ngeom = 0;
scn->status = 0;
// trigger plugin visualization hooks
if (m->nplugin) {
@@ -3416,10 +3419,6 @@ void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt,
if (opt->flags[mjVIS_SKIN]) {
mjv_updateActiveSkin(m, d, scn, opt);
}
if (scn->status) {
mj_warning(d, mjWARN_VGEOMFULL, scn->maxgeom);
}
}
-1
View File
@@ -101,7 +101,6 @@ TEST_F(MjvSceneTest, UpdateSceneGeomsExhausted) {
mjv_updateScene(model, data, &opt_, &pert_, &cam_, mjCAT_ALL, &scn_);
EXPECT_EQ(scn_.status, 1);
EXPECT_EQ(scn_.ngeom, maxgeoms);
EXPECT_EQ(data->warning[mjWARN_VGEOMFULL].number, 1);
mj_deleteData(data);
FreeSceneObjects();
+5 -7
View File
@@ -489,12 +489,11 @@ public enum mjtWarning : int{
mjWARN_INERTIA = 0,
mjWARN_CONTACTFULL = 1,
mjWARN_CNSTRFULL = 2,
mjWARN_VGEOMFULL = 3,
mjWARN_BADQPOS = 4,
mjWARN_BADQVEL = 5,
mjWARN_BADQACC = 6,
mjWARN_BADCTRL = 7,
mjNWARNING = 8,
mjWARN_BADQPOS = 3,
mjWARN_BADQVEL = 4,
mjWARN_BADQACC = 5,
mjWARN_BADCTRL = 6,
mjNWARNING = 7,
}
public enum mjtTimer : int{
mjTIMER_STEP = 0,
@@ -5699,7 +5698,6 @@ public unsafe struct mjData_ {
public mjWarningStat_ warning4;
public mjWarningStat_ warning5;
public mjWarningStat_ warning6;
public mjWarningStat_ warning7;
public mjTimerStat_ timer0;
public mjTimerStat_ timer1;
public mjTimerStat_ timer2;
+3 -7
View File
@@ -359,22 +359,18 @@ public class MjScene : MonoBehaviour {
}
if (Data->warning3.number > 0) {
Data->warning3.number = 0;
throw new PhysicsRuntimeException("VGEOMFULL: who constructed a mjvScene?!");
throw new PhysicsRuntimeException("BADQPOS: NaN/inf in qpos.");
}
if (Data->warning4.number > 0) {
Data->warning4.number = 0;
throw new PhysicsRuntimeException("BADQPOS: NaN/inf in qpos.");
throw new PhysicsRuntimeException("BADQVEL: NaN/inf in qvel.");
}
if (Data->warning5.number > 0) {
Data->warning5.number = 0;
throw new PhysicsRuntimeException("BADQVEL: NaN/inf in qvel.");
throw new PhysicsRuntimeException("BADQACC: NaN/inf in qacc.");
}
if (Data->warning6.number > 0) {
Data->warning6.number = 0;
throw new PhysicsRuntimeException("BADQACC: NaN/inf in qacc.");
}
if (Data->warning7.number > 0) {
Data->warning7.number = 0;
throw new PhysicsRuntimeException("BADCTRL: NaN/inf in ctrl.");
}
}
-1
View File
@@ -11380,7 +11380,6 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
.value("mjWARN_INERTIA", mjWARN_INERTIA)
.value("mjWARN_CONTACTFULL", mjWARN_CONTACTFULL)
.value("mjWARN_CNSTRFULL", mjWARN_CNSTRFULL)
.value("mjWARN_VGEOMFULL", mjWARN_VGEOMFULL)
.value("mjWARN_BADQPOS", mjWARN_BADQPOS)
.value("mjWARN_BADQVEL", mjWARN_BADQVEL)
.value("mjWARN_BADQACC", mjWARN_BADQACC)