Move EGL initialization into a separate class.
Initialize the EGL context in the Renderer when using the classic rendering engine with no window. PiperOrigin-RevId: 864884976 Change-Id: Ic6cc4637855a361e41f3bfb4b738c012ec93711f
This commit is contained in:
committed by
Copybara-Service
parent
7ec8b6e341
commit
ef8e6802ef
@@ -37,6 +37,8 @@ target_compile_definitions(${MUJOCO_PLATFORM_TARGET_NAME}
|
|||||||
|
|
||||||
target_sources(${MUJOCO_PLATFORM_TARGET_NAME}
|
target_sources(${MUJOCO_PLATFORM_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
egl_utils.cc
|
||||||
|
egl_utils.h
|
||||||
file_dialog.h
|
file_dialog.h
|
||||||
gui.cc
|
gui.cc
|
||||||
gui.h
|
gui.h
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
// Copyright 2026 DeepMind Technologies Limited
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "experimental/platform/egl_utils.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "third_party/GL/gl/include/EGL/egl.h"
|
||||||
|
#include "third_party/GL/gl/include/EGL/eglext.h"
|
||||||
|
#include <mujoco/mujoco.h>
|
||||||
|
|
||||||
|
namespace mujoco::platform {
|
||||||
|
|
||||||
|
static EGLDisplay CreateInitializedEglDisplay() {
|
||||||
|
auto eglQueryDevicesEXT =
|
||||||
|
(PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
|
||||||
|
auto eglGetPlatformDisplayEXT =
|
||||||
|
(PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress(
|
||||||
|
"eglGetPlatformDisplayEXT");
|
||||||
|
|
||||||
|
if (!eglQueryDevicesEXT || !eglGetPlatformDisplayEXT) {
|
||||||
|
mju_error("Failed to load EGL functions");
|
||||||
|
return EGL_NO_DISPLAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query all available EGL devices.
|
||||||
|
constexpr int kMaxDevices = 32;
|
||||||
|
EGLDeviceEXT devices[kMaxDevices];
|
||||||
|
int ndevice = 0;
|
||||||
|
if (!eglQueryDevicesEXT(kMaxDevices, devices, &ndevice)) {
|
||||||
|
mju_error("eglQueryDevices error: 0x%x", eglGetError());
|
||||||
|
return EGL_NO_DISPLAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the first valid EGL display.
|
||||||
|
for (int i = 0; i < ndevice; ++i) {
|
||||||
|
EGLDisplay display =
|
||||||
|
eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, devices[i], nullptr);
|
||||||
|
if (display != EGL_NO_DISPLAY) {
|
||||||
|
int major, minor;
|
||||||
|
EGLBoolean initialized = eglInitialize(display, &major, &minor);
|
||||||
|
if (initialized) {
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mju_error("Failed to create and initialize a valid EGL display!");
|
||||||
|
return EGL_NO_DISPLAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EGLContext InitializeEglContext(EGLDisplay display) {
|
||||||
|
constexpr EGLint config_attribs[] = {EGL_RED_SIZE,
|
||||||
|
8,
|
||||||
|
EGL_GREEN_SIZE,
|
||||||
|
8,
|
||||||
|
EGL_BLUE_SIZE,
|
||||||
|
8,
|
||||||
|
EGL_ALPHA_SIZE,
|
||||||
|
8,
|
||||||
|
EGL_DEPTH_SIZE,
|
||||||
|
24,
|
||||||
|
EGL_STENCIL_SIZE,
|
||||||
|
8,
|
||||||
|
EGL_COLOR_BUFFER_TYPE,
|
||||||
|
EGL_RGB_BUFFER,
|
||||||
|
EGL_SURFACE_TYPE,
|
||||||
|
EGL_PBUFFER_BIT,
|
||||||
|
EGL_RENDERABLE_TYPE,
|
||||||
|
EGL_OPENGL_BIT,
|
||||||
|
EGL_NONE};
|
||||||
|
EGLint nconfig;
|
||||||
|
EGLConfig config;
|
||||||
|
if (!eglChooseConfig(display, config_attribs, &config, 1, &nconfig)) {
|
||||||
|
mju_error("eglChooseConfig error: 0x%x", eglGetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind the OpenGL API to the EGL.
|
||||||
|
if (!eglBindAPI(EGL_OPENGL_API)) {
|
||||||
|
mju_error("eglBindAPI error: 0x%x", eglGetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an EGL context.
|
||||||
|
constexpr EGLint context_attribs[] = {
|
||||||
|
EGL_CONTEXT_MAJOR_VERSION,
|
||||||
|
1,
|
||||||
|
EGL_CONTEXT_MINOR_VERSION,
|
||||||
|
5,
|
||||||
|
EGL_CONTEXT_OPENGL_PROFILE_MASK,
|
||||||
|
EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT,
|
||||||
|
EGL_NONE};
|
||||||
|
EGLContext context =
|
||||||
|
eglCreateContext(display, config, EGL_NO_CONTEXT, context_attribs);
|
||||||
|
if (context == EGL_NO_CONTEXT) {
|
||||||
|
mju_error("eglCreateContext error: 0x%x", eglGetError());
|
||||||
|
return EGL_NO_CONTEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the EGL context current.
|
||||||
|
if (!eglMakeCurrent(display, nullptr, nullptr, context)) {
|
||||||
|
mju_error("eglMakeCurrent error: 0x%x", eglGetError());
|
||||||
|
return EGL_NO_CONTEXT;
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EglContext {
|
||||||
|
EglContext() {
|
||||||
|
display_ = CreateInitializedEglDisplay();
|
||||||
|
context_ = InitializeEglContext(display_);
|
||||||
|
}
|
||||||
|
|
||||||
|
~EglContext() {
|
||||||
|
if (context_ != EGL_NO_CONTEXT) {
|
||||||
|
eglMakeCurrent(display_, nullptr, nullptr, EGL_NO_CONTEXT);
|
||||||
|
eglDestroyContext(display_, context_);
|
||||||
|
context_ = EGL_NO_CONTEXT;
|
||||||
|
}
|
||||||
|
if (display_ != EGL_NO_DISPLAY) {
|
||||||
|
eglTerminate(display_);
|
||||||
|
display_ = EGL_NO_DISPLAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLDisplay display_;
|
||||||
|
EGLContext context_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<void> CreateEglContext() {
|
||||||
|
auto egl_context = std::make_shared<EglContext>();
|
||||||
|
return std::static_pointer_cast<void>(egl_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mujoco::platform
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2026 DeepMind Technologies Limited
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef MUJOCO_SRC_EXPERIMENTAL_PLATFORM_EGL_UTILS_H_
|
||||||
|
#define MUJOCO_SRC_EXPERIMENTAL_PLATFORM_EGL_UTILS_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace mujoco::platform {
|
||||||
|
|
||||||
|
// Creates an opaque handle to an initialized EGL context and display.
|
||||||
|
// Resetting this handle will destroy the context and release the display.
|
||||||
|
std::shared_ptr<void> CreateEglContext();
|
||||||
|
|
||||||
|
} // namespace mujoco::platform
|
||||||
|
|
||||||
|
#endif // MUJOCO_SRC_EXPERIMENTAL_PLATFORM_EGL_UTILS_H_
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#if defined(MUJOCO_RENDERER_CLASSIC_OPENGL)
|
#if defined(MUJOCO_RENDERER_CLASSIC_OPENGL)
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <backends/imgui_impl_opengl3.h>
|
#include <backends/imgui_impl_opengl3.h>
|
||||||
|
#include "experimental/platform/egl_utils.h"
|
||||||
#else
|
#else
|
||||||
#include "experimental/filament/render_context_filament.h"
|
#include "experimental/filament/render_context_filament.h"
|
||||||
#include "experimental/platform/plugin.h"
|
#include "experimental/platform/plugin.h"
|
||||||
@@ -32,11 +33,17 @@ namespace mujoco::platform {
|
|||||||
|
|
||||||
Renderer::Renderer(void* native_window) : native_window_(native_window) {
|
Renderer::Renderer(void* native_window) : native_window_(native_window) {
|
||||||
#ifdef MUJOCO_RENDERER_CLASSIC_OPENGL
|
#ifdef MUJOCO_RENDERER_CLASSIC_OPENGL
|
||||||
|
if (native_window == nullptr) {
|
||||||
|
graphics_api_context_ = CreateEglContext();
|
||||||
|
}
|
||||||
ImGui_ImplOpenGL3_Init();
|
ImGui_ImplOpenGL3_Init();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::~Renderer() { Deinit(); }
|
Renderer::~Renderer() {
|
||||||
|
Deinit();
|
||||||
|
graphics_api_context_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::Init(const mjModel* model) {
|
void Renderer::Init(const mjModel* model) {
|
||||||
Deinit();
|
Deinit();
|
||||||
@@ -184,7 +191,6 @@ RendererBackend Renderer::GetBackend() {
|
|||||||
#error "Unsupported renderer backend."
|
#error "Unsupported renderer backend."
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mujoco::platform
|
} // namespace mujoco::platform
|
||||||
|
|
||||||
#if !defined(MUJOCO_RENDERER_CLASSIC_OPENGL)
|
#if !defined(MUJOCO_RENDERER_CLASSIC_OPENGL)
|
||||||
|
|||||||
@@ -17,12 +17,14 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
#include <ratio>
|
#include <ratio>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
#include <mujoco/mujoco.h>
|
#include <mujoco/mujoco.h>
|
||||||
#include "experimental/platform/renderer_backend.h"
|
#include "experimental/platform/renderer_backend.h"
|
||||||
|
|
||||||
|
|
||||||
namespace mujoco::platform {
|
namespace mujoco::platform {
|
||||||
|
|
||||||
// Renders the mujoco simulation and the imgui state.
|
// Renders the mujoco simulation and the imgui state.
|
||||||
@@ -99,6 +101,7 @@ class Renderer {
|
|||||||
void UpdateFps();
|
void UpdateFps();
|
||||||
|
|
||||||
void* native_window_ = nullptr;
|
void* native_window_ = nullptr;
|
||||||
|
std::shared_ptr<void> graphics_api_context_ = nullptr;
|
||||||
mjrContext render_context_;
|
mjrContext render_context_;
|
||||||
mjvScene scene_;
|
mjvScene scene_;
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
|
|||||||
@@ -20,10 +20,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#ifdef MUJOCO_STUDIO_EGL_SUPPORTED
|
|
||||||
#include "third_party/GL/gl/include/EGL/egl.h"
|
|
||||||
#include "third_party/GL/gl/include/EGL/eglext.h"
|
|
||||||
#endif
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <SDL_error.h>
|
#include <SDL_error.h>
|
||||||
#include <SDL_events.h>
|
#include <SDL_events.h>
|
||||||
@@ -160,9 +156,6 @@ Window::Window(std::string_view title, int width, int height, Config config)
|
|||||||
|
|
||||||
if (config_.offscreen_mode) {
|
if (config_.offscreen_mode) {
|
||||||
sdl_renderer_ = SDL_CreateRenderer(sdl_window_, -1, SDL_RENDERER_SOFTWARE);
|
sdl_renderer_ = SDL_CreateRenderer(sdl_window_, -1, SDL_RENDERER_SOFTWARE);
|
||||||
if (renderer_backend == RendererBackend::ClassicOpenGl) {
|
|
||||||
InitOffscreenEglContext();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SysWMinfo wmi;
|
SDL_SysWMinfo wmi;
|
||||||
@@ -187,13 +180,6 @@ Window::Window(std::string_view title, int width, int height, Config config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Window::~Window() {
|
Window::~Window() {
|
||||||
#ifdef MUJOCO_STUDIO_EGL_SUPPORTED
|
|
||||||
if (egl_display_ && egl_context_) {
|
|
||||||
eglMakeCurrent(egl_display_, nullptr, nullptr, EGL_NO_CONTEXT);
|
|
||||||
eglDestroyContext(egl_display_, egl_context_);
|
|
||||||
eglTerminate(egl_display_);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
SDL_DestroyWindow(sdl_window_);
|
SDL_DestroyWindow(sdl_window_);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
@@ -296,89 +282,4 @@ void Window::Present(std::span<const std::byte> pixels) {
|
|||||||
bool Window::IsOffscreenMode() const {
|
bool Window::IsOffscreenMode() const {
|
||||||
return config_.offscreen_mode;
|
return config_.offscreen_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::InitOffscreenEglContext() {
|
|
||||||
#ifdef MUJOCO_STUDIO_EGL_SUPPORTED
|
|
||||||
auto eglQueryDevicesEXT =
|
|
||||||
(PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
|
|
||||||
auto eglGetPlatformDisplayEXT =
|
|
||||||
(PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress(
|
|
||||||
"eglGetPlatformDisplayEXT");
|
|
||||||
|
|
||||||
if (!eglQueryDevicesEXT || !eglGetPlatformDisplayEXT) {
|
|
||||||
mju_error("Failed to load EGL functions");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query all available EGL devices.
|
|
||||||
constexpr int kMaxDevices = 32;
|
|
||||||
EGLDeviceEXT egl_devices[kMaxDevices];
|
|
||||||
int ndevice = 0;
|
|
||||||
if (!eglQueryDevicesEXT(kMaxDevices, egl_devices, &ndevice)) {
|
|
||||||
mju_error("eglQueryDevices error: 0x%x", eglGetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the first valid EGL display.
|
|
||||||
for (int i = 0; i < ndevice; ++i) {
|
|
||||||
egl_display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT,
|
|
||||||
egl_devices[i], nullptr);
|
|
||||||
if (egl_display_ != EGL_NO_DISPLAY) {
|
|
||||||
int major, minor;
|
|
||||||
EGLBoolean initialized = eglInitialize(egl_display_, &major, &minor);
|
|
||||||
if (!initialized) {
|
|
||||||
egl_display_ = EGL_NO_DISPLAY;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (egl_display_ == EGL_NO_DISPLAY) {
|
|
||||||
mju_error("Failed to create and initialize a valid EGL display!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Choose an EGL config.
|
|
||||||
constexpr EGLint config_attribs[] = {
|
|
||||||
EGL_RED_SIZE, 8,
|
|
||||||
EGL_GREEN_SIZE, 8,
|
|
||||||
EGL_BLUE_SIZE, 8,
|
|
||||||
EGL_ALPHA_SIZE, 8,
|
|
||||||
EGL_DEPTH_SIZE, 24,
|
|
||||||
EGL_STENCIL_SIZE, 8,
|
|
||||||
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
|
|
||||||
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
|
|
||||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
|
|
||||||
EGL_NONE
|
|
||||||
};
|
|
||||||
EGLint nconfig;
|
|
||||||
EGLConfig config;
|
|
||||||
if (!eglChooseConfig(egl_display_, config_attribs, &config, 1, &nconfig)) {
|
|
||||||
mju_error("eglChooseConfig error: 0x%x", eglGetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the OpenGL API to the EGL.
|
|
||||||
if (!eglBindAPI(EGL_OPENGL_API)) {
|
|
||||||
mju_error("eglBindAPI error: 0x%x", eglGetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an EGL context.
|
|
||||||
constexpr EGLint context_attribs[] = {
|
|
||||||
EGL_CONTEXT_MAJOR_VERSION, 1,
|
|
||||||
EGL_CONTEXT_MINOR_VERSION, 5,
|
|
||||||
EGL_CONTEXT_OPENGL_PROFILE_MASK,
|
|
||||||
EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT,
|
|
||||||
EGL_NONE};
|
|
||||||
egl_context_ =
|
|
||||||
eglCreateContext(egl_display_, config, EGL_NO_CONTEXT, context_attribs);
|
|
||||||
if (egl_context_ == EGL_NO_CONTEXT) {
|
|
||||||
mju_error("eglCreateContext error: 0x%x", eglGetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the EGL context current.
|
|
||||||
if (!eglMakeCurrent(egl_display_, nullptr, nullptr, egl_context_)) {
|
|
||||||
mju_error("eglMakeCurrent error: 0x%x", eglGetError());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
mju_error("EGL not supported on this platform");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mujoco::platform
|
} // namespace mujoco::platform
|
||||||
|
|||||||
@@ -22,10 +22,6 @@
|
|||||||
|
|
||||||
#include "experimental/platform/renderer_backend.h"
|
#include "experimental/platform/renderer_backend.h"
|
||||||
|
|
||||||
#if __has_include("third_party/GL/gl/include/EGL/egl.h")
|
|
||||||
#define MUJOCO_STUDIO_EGL_SUPPORTED 1
|
|
||||||
#include "third_party/GL/gl/include/EGL/egl.h"
|
|
||||||
#endif
|
|
||||||
#include <SDL_video.h>
|
#include <SDL_video.h>
|
||||||
#include <SDL_render.h>
|
#include <SDL_render.h>
|
||||||
|
|
||||||
@@ -107,10 +103,6 @@ class Window {
|
|||||||
SDL_Renderer* sdl_renderer_ = nullptr;
|
SDL_Renderer* sdl_renderer_ = nullptr;
|
||||||
bool should_exit_ = false;
|
bool should_exit_ = false;
|
||||||
std::string drop_file_;
|
std::string drop_file_;
|
||||||
#ifdef MUJOCO_STUDIO_EGL_SUPPORTED
|
|
||||||
EGLDisplay egl_display_ = EGL_NO_DISPLAY;
|
|
||||||
EGLContext egl_context_ = EGL_NO_CONTEXT;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mujoco::platform
|
} // namespace mujoco::platform
|
||||||
|
|||||||
Reference in New Issue
Block a user