Add renderer info query API

This commit is contained in:
devshahofficial
2026-06-13 15:58:30 -07:00
parent c4c2cad503
commit d23ff84c59
15 changed files with 194 additions and 1 deletions
+7
View File
@@ -117,6 +117,13 @@ typedef struct mjrRect_ { // OpenGL rectangle
} mjrRect;
typedef struct mjrRendererInfo_ { // active renderer identity
const char* renderer; // renderer family: classic, filament, noop
const char* backend; // graphics backend: opengl, vulkan; empty if uninitialized
const char* backend_version; // backend version string, empty if unknown
} mjrRendererInfo;
typedef struct mjrVertexAttribute_ { // vertex attribute format specification
const void* bytes; // vertex data
int usage; // position, normal, etc [mjrVertexAttributeUsage]
+3
View File
@@ -104,6 +104,9 @@ mjrfContext* mjrf_createContext(const mjrfContextConfig* config);
// Destroys the filament rendering context.
void mjrf_destroyContext(mjrfContext* ctx);
// Gets active renderer information for the given filament context.
void mjrf_getRendererInfo(mjrfContext* ctx, mjrRendererInfo* info);
typedef enum mjrDrawMode_ { // how to draw objects in the scene
mjDRAW_MODE_DEFAULT, // default colors and lighting
mjDRAW_MODE_DEFAULT_NO_TEXTURES, // default, but without textures
+6
View File
@@ -855,6 +855,12 @@ MJAPI void mjv_cameraFrustum(float zver[2], float zhor[2], float zclip[2], cons
// Set default mjrContext.
MJAPI void mjr_defaultContext(mjrContext* con);
// Set default mjrRendererInfo.
MJAPI void mjr_defaultRendererInfo(mjrRendererInfo* info);
// Get active renderer information.
MJAPI void mjr_getRendererInfo(mjrRendererInfo* info);
// Allocate resources in custom OpenGL context; fontscale is mjtFontScale.
MJAPI void mjr_makeContext(const mjModel* m, mjrContext* con, int fontscale);
+8
View File
@@ -125,6 +125,14 @@ class MuJoCoBindingsTest(parameterized.TestCase):
self.model: mujoco.MjModel = mujoco.MjModel.from_xml_string(TEST_XML)
self.data = mujoco.MjData(self.model)
def test_renderer_info_binding(self):
info = mujoco.MjrRendererInfo()
mujoco.mjr_getRendererInfo(info)
self.assertIn(info.renderer, ('classic', 'filament', 'noop'))
self.assertIn(info.backend, ('', 'opengl', 'vulkan', 'unknown'))
self.assertIsInstance(info.backend_version, str)
def test_load_xml_can_handle_name_clash(self):
xml_1 = r"""
<mujoco>
+28
View File
@@ -5480,6 +5480,34 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
),
doc='Set default mjrContext.',
)),
('mjr_defaultRendererInfo',
FunctionDecl(
name='mjr_defaultRendererInfo',
return_type=ValueType(name='void'),
parameters=(
FunctionParameterDecl(
name='info',
type=PointerType(
inner_type=ValueType(name='mjrRendererInfo'),
),
),
),
doc='Set default mjrRendererInfo.',
)),
('mjr_getRendererInfo',
FunctionDecl(
name='mjr_getRendererInfo',
return_type=ValueType(name='void'),
parameters=(
FunctionParameterDecl(
name='info',
type=PointerType(
inner_type=ValueType(name='mjrRendererInfo'),
),
),
),
doc='Get active renderer information.',
)),
('mjr_makeContext',
FunctionDecl(
name='mjr_makeContext',
+28
View File
@@ -10995,6 +10995,34 @@ STRUCTS: Mapping[str, StructDecl] = dict([
),
),
)),
('mjrRendererInfo',
StructDecl(
name='mjrRendererInfo',
declname='struct mjrRendererInfo_',
fields=(
StructFieldDecl(
name='renderer',
type=PointerType(
inner_type=ValueType(name='char', is_const=True),
),
doc='renderer family: classic, filament, noop',
),
StructFieldDecl(
name='backend',
type=PointerType(
inner_type=ValueType(name='char', is_const=True),
),
doc='graphics backend: opengl, vulkan; empty if uninitialized',
),
StructFieldDecl(
name='backend_version',
type=PointerType(
inner_type=ValueType(name='char', is_const=True),
),
doc='backend version string, empty if unknown',
),
),
)),
('mjrVertexAttribute',
StructDecl(
name='mjrVertexAttribute',
+1
View File
@@ -79,6 +79,7 @@ using MjLogMessage = ::mjLogMessage;
// From mjrender.h
using MjrRect = ::mjrRect;
using MjrRendererInfo = ::mjrRendererInfo;
using MjrContext = ::mjrContext;
using MjrVertexAttribute = ::mjrVertexAttribute;
+2
View File
@@ -245,6 +245,8 @@ PYBIND11_MODULE(_render, pymodule, pybind11::mod_gil_not_used()) {
using EigenFloatVectorX = Eigen::Vector<float, Eigen::Dynamic>;
// Skipped: mjr_defaultContext (have MjrContext.__init__)
Def<traits::mjr_defaultRendererInfo>(pymodule);
Def<traits::mjr_getRendererInfo>(pymodule);
// Skipped: mjr_makeContext (have MjrContext.__init__)
Def<traits::mjr_changeFont>(pymodule);
Def<traits::mjr_addAux>(pymodule);
+30
View File
@@ -1049,6 +1049,36 @@ This is useful for example when the MJB is not available as a file on disk.)"));
X(height);
#undef X
// ==================== MJRRENDERERINFO ======================================
py::class_<raw::MjrRendererInfo> mjrRendererInfo(m, "MjrRendererInfo");
mjrRendererInfo.def(py::init([]() {
raw::MjrRendererInfo info;
mjr_defaultRendererInfo(&info);
return info;
}));
mjrRendererInfo.def("__copy__", [](const raw::MjrRendererInfo& other) {
return raw::MjrRendererInfo(other);
});
mjrRendererInfo.def("__deepcopy__",
[](const raw::MjrRendererInfo& other, py::dict) {
return raw::MjrRendererInfo(other);
});
DefineStructFunctions(mjrRendererInfo);
mjrRendererInfo.def_property_readonly("renderer",
[](const raw::MjrRendererInfo& info) {
return info.renderer ? info.renderer
: "";
});
mjrRendererInfo.def_property_readonly("backend",
[](const raw::MjrRendererInfo& info) {
return info.backend ? info.backend
: "";
});
mjrRendererInfo.def_property_readonly(
"backend_version", [](const raw::MjrRendererInfo& info) {
return info.backend_version ? info.backend_version : "";
});
// ==================== MJRVERTEXATTRIBUTE ===================================
py::class_<raw::MjrVertexAttribute> mjrVertexAttribute(m,
"MjrVertexAttribute");
+16
View File
@@ -57,6 +57,8 @@ class CompatContext {
scene_bridge_->UploadHeightField(model, id);
}
mjrfContext* Context() const { return context_.get(); }
private:
mjrDrawMode draw_mode_ = mjDRAW_MODE_DEFAULT;
UniquePtr<mjrfContext> context_{nullptr, nullptr};
@@ -189,6 +191,20 @@ void mjr_defaultContext(mjrContext* con) {
memset(con, 0, sizeof(mjrContext));
}
void mjr_defaultRendererInfo(mjrRendererInfo* info) {
memset(info, 0, sizeof(mjrRendererInfo));
info->renderer = "filament";
info->backend = "";
info->backend_version = "";
}
void mjr_getRendererInfo(mjrRendererInfo* info) {
mjr_defaultRendererInfo(info);
if (g_context) {
mjrf_getRendererInfo(g_context->Context(), info);
}
}
void mjr_makeFilamentContext(const mjModel* m, const mjrfContextConfig* cfg,
mjrContext* con) {
if (g_context != nullptr) {
+32
View File
@@ -55,6 +55,30 @@ void mjr_defaultContext(mjrContext* con) {
memset(con, 0, sizeof(mjrContext));
}
static int context_count = 0;
static int contextHasResources(const mjrContext* con) {
return con->ntexture || con->offColor || con->offDepthStencil || con->offFBO ||
con->shadowTex || con->shadowFBO || con->rangePlane || con->rangeMesh ||
con->rangeHField || con->rangeBuiltin || con->rangeFont || con->nskin;
}
// set default mjrRendererInfo
void mjr_defaultRendererInfo(mjrRendererInfo* info) {
memset(info, 0, sizeof(mjrRendererInfo));
info->renderer = "classic";
info->backend = "";
info->backend_version = "";
}
// get active renderer information
void mjr_getRendererInfo(mjrRendererInfo* info) {
mjr_defaultRendererInfo(info);
if (context_count > 0) {
info->backend = "opengl";
}
}
// allocate lists
@@ -1608,6 +1632,7 @@ void mjr_makeContext_offSize(const mjModel* m, mjrContext* con, int fontscale,
// try to bind window (bind offscreen if no window)
mjr_setBuffer(mjFB_WINDOW, con);
context_count++;
return;
}
@@ -1667,6 +1692,7 @@ void mjr_makeContext_offSize(const mjModel* m, mjrContext* con, int fontscale,
// set default depth mapping for mjr_readPixels
con->readDepthMap = mjDEPTH_ZERONEAR;
context_count++;
}
@@ -1811,6 +1837,8 @@ void mjr_addAux(int index, int width, int height, int samples, mjrContext* con)
// free resources in custom OpenGL context
void mjr_freeContext(mjrContext* con) {
int had_resources = contextHasResources(con);
// save flags
int glInitialized = con->glInitialized;
int windowAvailable = con->windowAvailable;
@@ -1867,6 +1895,10 @@ void mjr_freeContext(mjrContext* con) {
con->windowSamples = windowSamples;
con->windowStereo = windowStereo;
con->windowDoublebuffer = windowDoublebuffer;
if (had_resources && context_count > 0) {
context_count--;
}
}
+2 -1
View File
@@ -49,6 +49,7 @@ namespace mujoco {
FilamentContext::FilamentContext(const mjrfContextConfig* config)
: config_(*config) {
FilamentPlatformSetup setup = CreateFilamentPlatform(config_);
backend_ = setup.backend;
platform_ = std::move(setup.platform);
filament::Engine::Config engine_config;
@@ -58,7 +59,7 @@ FilamentContext::FilamentContext(const mjrfContextConfig* config)
filament::Engine::Builder engine_builder;
engine_builder.config(&engine_config);
engine_builder.backend(setup.backend);
engine_builder.backend(backend_);
engine_builder.platform(platform_.get());
engine_builder.feature("backend.disable_parallel_shader_compile",
setup.disable_parallel_shader_compile);
@@ -59,6 +59,8 @@ class FilamentContext : public mjrfContext {
filament::Engine* GetEngine() const { return engine_; }
filament::Engine::Backend GetBackend() const { return backend_; }
ObjectManager* GetObjectManager() const { return object_manager_.get(); }
MaterialManager* GetMaterialManager() const {
@@ -76,6 +78,7 @@ class FilamentContext : public mjrfContext {
void ValidateSwapChains(std::span<const mjrfRenderRequest> render_requests);
mjrfContextConfig config_;
filament::Engine::Backend backend_;
filament::Engine* engine_ = nullptr;
filament::Renderer* renderer_ = nullptr;
filament::SwapChain* window_swap_chain_ = nullptr;
+18
View File
@@ -37,6 +37,17 @@ static void setf(float (&arr)[N], const std::array<float, N>& values) {
}
}
static const char* BackendName(filament::Engine::Backend backend) {
switch (backend) {
case filament::Engine::Backend::OPENGL:
return "opengl";
case filament::Engine::Backend::VULKAN:
return "vulkan";
default:
return "unknown";
}
}
extern "C" {
void mjrf_defaultContextConfig(mjrfContextConfig* config) {
@@ -124,6 +135,13 @@ void mjrf_destroyContext(mjrfContext* ctx) {
delete mujoco::FilamentContext::downcast(ctx);
}
void mjrf_getRendererInfo(mjrfContext* ctx, mjrRendererInfo* info) {
memset(info, 0, sizeof(mjrRendererInfo));
info->renderer = "filament";
info->backend = ctx ? BackendName(mujoco::FilamentContext::downcast(ctx)->GetBackend()) : "";
info->backend_version = "";
}
mjrfTexture* mjrf_createTexture(mjrfContext* ctx,
const mjrfTextureConfig* config) {
return new mujoco::Texture(
+10
View File
@@ -13,6 +13,7 @@
// limitations under the License.
#include <mujoco/mujoco.h>
#include <string.h>
// This library implements the entirety of mujoco's mjr API as fast-fail stubs.
// You can link this library with your application (instead of standard renderer
@@ -22,6 +23,15 @@
void mjr_defaultContext(mjrContext* con) {
mju_error("mjr_defaultContext not implemented.");
}
void mjr_defaultRendererInfo(mjrRendererInfo* info) {
memset(info, 0, sizeof(mjrRendererInfo));
info->renderer = "noop";
info->backend = "";
info->backend_version = "";
}
void mjr_getRendererInfo(mjrRendererInfo* info) {
mjr_defaultRendererInfo(info);
}
void mjr_makeContext(const mjModel* m, mjrContext* con, int fontscale) {
mju_error("mjr_makeContext not implemented.");
}