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}
|
||||
PUBLIC
|
||||
egl_utils.cc
|
||||
egl_utils.h
|
||||
file_dialog.h
|
||||
gui.cc
|
||||
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)
|
||||
#include <imgui.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include "experimental/platform/egl_utils.h"
|
||||
#else
|
||||
#include "experimental/filament/render_context_filament.h"
|
||||
#include "experimental/platform/plugin.h"
|
||||
@@ -32,11 +33,17 @@ namespace mujoco::platform {
|
||||
|
||||
Renderer::Renderer(void* native_window) : native_window_(native_window) {
|
||||
#ifdef MUJOCO_RENDERER_CLASSIC_OPENGL
|
||||
if (native_window == nullptr) {
|
||||
graphics_api_context_ = CreateEglContext();
|
||||
}
|
||||
ImGui_ImplOpenGL3_Init();
|
||||
#endif
|
||||
}
|
||||
|
||||
Renderer::~Renderer() { Deinit(); }
|
||||
Renderer::~Renderer() {
|
||||
Deinit();
|
||||
graphics_api_context_.reset();
|
||||
}
|
||||
|
||||
void Renderer::Init(const mjModel* model) {
|
||||
Deinit();
|
||||
@@ -184,7 +191,6 @@ RendererBackend Renderer::GetBackend() {
|
||||
#error "Unsupported renderer backend."
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace mujoco::platform
|
||||
|
||||
#if !defined(MUJOCO_RENDERER_CLASSIC_OPENGL)
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <ratio>
|
||||
#include <span>
|
||||
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "experimental/platform/renderer_backend.h"
|
||||
|
||||
|
||||
namespace mujoco::platform {
|
||||
|
||||
// Renders the mujoco simulation and the imgui state.
|
||||
@@ -99,6 +101,7 @@ class Renderer {
|
||||
void UpdateFps();
|
||||
|
||||
void* native_window_ = nullptr;
|
||||
std::shared_ptr<void> graphics_api_context_ = nullptr;
|
||||
mjrContext render_context_;
|
||||
mjvScene scene_;
|
||||
bool initialized_ = false;
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
#include <string>
|
||||
#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_error.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) {
|
||||
sdl_renderer_ = SDL_CreateRenderer(sdl_window_, -1, SDL_RENDERER_SOFTWARE);
|
||||
if (renderer_backend == RendererBackend::ClassicOpenGl) {
|
||||
InitOffscreenEglContext();
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SysWMinfo wmi;
|
||||
@@ -187,13 +180,6 @@ Window::Window(std::string_view title, int width, int height, Config config)
|
||||
}
|
||||
|
||||
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_Quit();
|
||||
}
|
||||
@@ -296,89 +282,4 @@ void Window::Present(std::span<const std::byte> pixels) {
|
||||
bool Window::IsOffscreenMode() const {
|
||||
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
|
||||
|
||||
@@ -22,10 +22,6 @@
|
||||
|
||||
#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_render.h>
|
||||
|
||||
@@ -107,10 +103,6 @@ class Window {
|
||||
SDL_Renderer* sdl_renderer_ = nullptr;
|
||||
bool should_exit_ = false;
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user