Skip to content

Commit

Permalink
feat(tur/luanti): perform the migration from SDL2+GLX to libxi+EGL
Browse files Browse the repository at this point in the history
I am pretty sure upstream Luanti has mostly already done this on **all its X11-based
official targets**, but I did not yet do this
to Luanti-on-TUR because I have not had time to finish fixing + testing
this mode.

In particular I believe that this mode has a unique potential to
possibly engage with twaik's `termux-wsi-layer` and possibly benefit
from an extremely huge performance boost on some specific devices, if it
can be made to work with it. termux/termux-packages#22353

However, unfortunately right now when I try to use this PR with
`termux-wsi-layer` installed on a device where it works with
`glmark2-es2`, I see this error

```
Thread 1 "luanti" received signal SIGSEGV, Segmentation fault.
0x0000007fad9782b0 in XGetVisualInfo ()
   from /data/data/com.termux/files/usr/lib/libX11.so
(gdb) bt
   from /data/data/com.termux/files/usr/lib/libX11.so
    config=0xb400007d1ca54f00, attribute=12334, value=0x7fffffd464)
    at /data/data/com.termux/files/home/termux-packages/packages/termux-wsi-layer/egl.c:133
    this=0xb400007daca1c9b0)
    at /data/data/com.termux/files/home/.termux-build/luanti/src/irr/src/CEGLManager.cpp:185
    this=this@entry=0xb400007ddca220d0)
    at /data/data/com.termux/files/home/.termux-build/luanti/src/irr/src/CIrrDeviceLinux.cpp:414
    this=0xb400007ddca220d0, param=...)
    at /data/data/com.termux/files/home/.termux-build/luanti/src/irr/src/CIrrDeviceLinux.cpp:166
    at /data/data/com.termux/files/home/.termux-build/luanti/src/irr/src/Irrlicht.cpp:66
    at /data/data/com.termux/files/home/.termux-build/luanti/src/src/client/renderingengine.cpp:151
    receiver=0xb400007d9ca1d630)
    at /data/data/com.termux/files/home/.termux-build/luanti/src/src/client/renderingengine.cpp:206
    at /data/data/com.termux/files/home/.termux-build/luanti/src/src/client/clientlauncher.cpp:290
    cmd_args=...)
    at /data/data/com.termux/files/home/.termux-build/luanti/src/src/client/clientlauncher.cpp:98
    at /data/data/com.termux/files/home/.termux-build/luanti/src/src/main.cpp:264
(gdb)
```

`0001-force-egl-priority-over-glx.patch`: this is
minetest/minetest#15286 but applied to
Luanti-on-TUR

`0005-toggle-on-the-recent-migration-away-from-sdl2.patch`: this is
minetest/minetest#15284 but applied to
Luanti-on-TUR

`0006-fix-incompatible-type-ekey-code.patch`: I wrote this, this is necessary to fix a
minor build error when SDL2 is disabled in Luanti
  • Loading branch information
robertkirkman committed Nov 24, 2024
1 parent da93168 commit 8d264f9
Show file tree
Hide file tree
Showing 7 changed files with 403 additions and 3 deletions.
374 changes: 374 additions & 0 deletions tur/luanti/0001-force-egl-priority-over-glx.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,374 @@
This is https://github.com/minetest/minetest/pull/15286
which is currently disabled upstream, because of
https://github.com/minetest/minetest/issues/15313
which is an NVIDIA-specific issue.
--- a/irr/src/CEGLManager.cpp
+++ b/irr/src/CEGLManager.cpp
@@ -40,29 +40,26 @@ bool CEGLManager::initialize(const SIrrlichtCreationParameters &params, const SE
if (EglWindow != 0 && EglDisplay != EGL_NO_DISPLAY)
return true;

- // Window is depend on platform.
+ // Window is depend on platform.
+ setWindow(Data);
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
- EglWindow = (NativeWindowType)Data.OpenGLWin32.HWnd;
- Data.OpenGLWin32.HDc = GetDC((HWND)EglWindow);
EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLWin32.HDc);
#elif defined(_IRR_EMSCRIPTEN_PLATFORM_)
- EglWindow = 0;
EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_)
- EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window;
EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLLinux.X11Display);
#endif

// We must check if EGL display is valid.
if (EglDisplay == EGL_NO_DISPLAY) {
- os::Printer::log("Could not get EGL display.");
+ os::Printer::log("Could not get EGL display.", ELL_ERROR);
terminate();
return false;
}

// Initialize EGL here.
if (!eglInitialize(EglDisplay, &MajorVersion, &MinorVersion)) {
- os::Printer::log("Could not initialize EGL display.");
+ os::Printer::log("Could not initialize EGL display.", ELL_ERROR);

EglDisplay = EGL_NO_DISPLAY;
terminate();
@@ -73,6 +70,22 @@ bool CEGLManager::initialize(const SIrrlichtCreationParameters &params, const SE
return true;
}

+void CEGLManager::setWindow(const SExposedVideoData &inData)
+{
+#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
+ Data.OpenGLWin32.HWnd = inData.OpenGLWin32.HWnd;
+ if (Data.OpenGLWin32.HWnd) {
+ EglWindow = (NativeWindowType)Data.OpenGLWin32.HWnd;
+ Data.OpenGLWin32.HDc = GetDC((HWND)EglWindow);
+ }
+#elif defined(_IRR_EMSCRIPTEN_PLATFORM_)
+ EglWindow = 0;
+#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_)
+ Data.OpenGLLinux.X11Window = inData.OpenGLLinux.X11Window;
+ EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window;
+#endif
+}
+
void CEGLManager::terminate()
{
if (EglWindow == 0 && EglDisplay == EGL_NO_DISPLAY)
@@ -105,20 +118,16 @@ bool CEGLManager::generateSurface()
if (EglSurface != EGL_NO_SURFACE)
return true;

- // We should assign new WindowID on platforms, where WindowID may change at runtime,
- // at this time only Android support this feature.
- // this needs an update method instead!
-
+ if (!EglConfig) {
#if defined(_IRR_EMSCRIPTEN_PLATFORM_)
- // eglChooseConfig is currently only implemented as stub in emscripten (version 1.37.22 at point of writing)
- // But the other solution would also be fine as it also only generates a single context so there is not much to choose from.
- EglConfig = chooseConfig(ECS_IRR_CHOOSE);
+ EglConfig = chooseConfig(ECS_IRR_CHOOSE);
#else
- EglConfig = chooseConfig(ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS);
+ EglConfig = chooseConfig(ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS);
#endif
+ }

- if (EglConfig == 0) {
- os::Printer::log("Could not get config for EGL display.");
+ if (!EglConfig) {
+ os::Printer::log("Could not choose EGL config.", ELL_ERROR);
return false;
}

@@ -129,11 +138,26 @@ bool CEGLManager::generateSurface()
EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, 0, 0);

if (EGL_NO_SURFACE == EglSurface)
- os::Printer::log("Could not create EGL surface.");
+ os::Printer::log("Could not create EGL surface.", ELL_ERROR);

#ifdef EGL_VERSION_1_2
- if (MinorVersion > 1)
- eglBindAPI(EGL_OPENGL_ES_API);
+ if (MinorVersion > 1) {
+ EGLBoolean ok = 0;
+ switch (Params.DriverType) {
+ case EDT_OGLES2:
+ case EDT_WEBGL1:
+ ok = eglBindAPI(EGL_OPENGL_ES_API);
+ break;
+ case EDT_OPENGL:
+ ok = eglBindAPI(EGL_OPENGL_API);
+ default:
+ break;
+ }
+ if (!ok) {
+ os::Printer::log("Could not bind EGL API.", ELL_ERROR);
+ return false;
+ }
+ }
#endif

if (Params.Vsync)
@@ -142,6 +166,26 @@ bool CEGLManager::generateSurface()
return true;
}

+EGLint CEGLManager::getNativeVisualID()
+{
+ if (!EglConfig) {
+#if defined(_IRR_EMSCRIPTEN_PLATFORM_)
+ EglConfig = chooseConfig(ECS_IRR_CHOOSE);
+#else
+ EglConfig = chooseConfig(ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS);
+#endif
+ }
+
+ if (!EglConfig) {
+ os::Printer::log("Could not choose EGL config.", ELL_WARNING);
+ return 0;
+ }
+
+ EGLint ret = 0;
+ eglGetConfigAttrib(EglDisplay, EglConfig, EGL_NATIVE_VISUAL_ID, &ret);
+ return ret;
+}
+
EGLConfig CEGLManager::chooseConfig(EConfigStyle confStyle)
{
EGLConfig configResult = 0;
@@ -153,6 +197,8 @@ EGLConfig CEGLManager::chooseConfig(EConfigStyle confStyle)
case EDT_WEBGL1:
eglOpenGLBIT = EGL_OPENGL_ES2_BIT;
break;
+ case EDT_OPENGL:
+ eglOpenGLBIT = EGL_OPENGL_BIT;
default:
break;
}
@@ -293,6 +339,8 @@ EGLConfig CEGLManager::chooseConfig(EConfigStyle confStyle)
}

delete[] configs;
+ } else {
+ _IRR_DEBUG_BREAK_IF(1)
}

return configResult;
@@ -450,33 +498,36 @@ bool CEGLManager::generateContext()
if (EglContext != EGL_NO_CONTEXT)
return true;

- EGLint OpenGLESVersion = 0;
+ std::vector<EGLint> ContextAttrib;

switch (Params.DriverType) {
case EDT_OGLES2:
case EDT_WEBGL1:
- OpenGLESVersion = 2;
+#ifdef EGL_VERSION_1_3
+ ContextAttrib.push_back(EGL_CONTEXT_CLIENT_VERSION);
+ ContextAttrib.push_back(2);
+#endif
+ break;
+ case EDT_OPENGL:
+#ifdef EGL_VERSION_1_5
+ ContextAttrib.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK);
+ ContextAttrib.push_back(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
+#endif
break;
default:
break;
}

- EGLint ContextAttrib[] = {
-#ifdef EGL_VERSION_1_3
- EGL_CONTEXT_CLIENT_VERSION, OpenGLESVersion,
-#endif
- EGL_NONE, 0,
- };
+ ContextAttrib.push_back(EGL_NONE);
+ ContextAttrib.push_back(0);

- EglContext = eglCreateContext(EglDisplay, EglConfig, EGL_NO_CONTEXT, ContextAttrib);
+ EglContext = eglCreateContext(EglDisplay, EglConfig, EGL_NO_CONTEXT, ContextAttrib.data());

if (testEGLError()) {
os::Printer::log("Could not create EGL context.", ELL_ERROR);
return false;
}

- os::Printer::log("EGL context created with OpenGLESVersion: ", core::stringc((int)OpenGLESVersion), ELL_DEBUG);
-
return true;
}

--- a/irr/src/CEGLManager.h
+++ b/irr/src/CEGLManager.h
@@ -31,6 +31,10 @@ class CEGLManager : public IContextManager
aren't create. */
bool initialize(const SIrrlichtCreationParameters &params, const SExposedVideoData &data) override;

+ // Set EGL window.
+ // Call this if window is not known at time of initialize()
+ void setWindow(const SExposedVideoData &data);
+
// Terminate EGL.
/* Terminate EGL context. This method break both existed surface and context. */
void terminate() override;
@@ -66,6 +70,9 @@ class CEGLManager : public IContextManager
// Swap buffers.
bool swapBuffers() override;

+ // Returns native visual ID. Will choose config if not already done.
+ EGLint getNativeVisualID();
+
protected:
enum EConfigStyle
{
--- a/irr/src/CGLXManager.cpp
+++ /dev/null
--- a/irr/src/CGLXManager.h
+++ /dev/null
--- a/irr/src/CIrrDeviceLinux.cpp
+++ b/irr/src/CIrrDeviceLinux.cpp
@@ -34,14 +34,10 @@
#include <X11/extensions/XInput2.h>
#endif

-#if defined(_IRR_COMPILE_WITH_OGLES2_)
+#if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES2_)
#include "CEGLManager.h"
#endif

-#if defined(_IRR_COMPILE_WITH_OPENGL_)
-#include "CGLXManager.h"
-#endif
-
#ifdef _IRR_LINUX_XCURSOR_
#include <X11/Xcursor/Xcursor.h>
#endif
@@ -152,8 +148,20 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters &param) :
// without it, multi-threaded GL drivers may crash
XInitThreads();

- // create window
if (CreationParams.DriverType != video::EDT_NULL) {
+ // initialize EGL so it can choose a config
+#ifdef _IRR_COMPILE_WITH_X11_
+#if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES2_)
+ video::SExposedVideoData data;
+ data.OpenGLLinux.X11Window = 0; // not created yet, but that's ok
+ data.OpenGLLinux.X11Display = XDisplay;
+
+ ContextManager = new video::CEGLManager();
+ if (!ContextManager->initialize(CreationParams, data))
+ return;
+#endif
+#endif
+
// create the window, only if we do not use the null device
if (!createWindow())
return;
@@ -397,14 +405,14 @@ bool CIrrDeviceLinux::createWindow()
if (WMCheck != None)
HasNetWM = true;

-#if defined(_IRR_COMPILE_WITH_OPENGL_)
- // don't use the XVisual with OpenGL, because it ignores all requested
- // properties of the CreationParams
- if (CreationParams.DriverType == video::EDT_OPENGL) {
- video::SExposedVideoData data;
- data.OpenGLLinux.X11Display = XDisplay;
- ContextManager = new video::CGLXManager(CreationParams, data, Screennr);
- VisualInfo = ((video::CGLXManager *)ContextManager)->getVisual();
+#if defined(_IRR_COMPILE_WITH_OPENGL_) || defined(_IRR_COMPILE_WITH_OGLES2_)
+ if (ContextManager) {
+ auto *c = static_cast<video::CEGLManager*>(ContextManager);
+ os::Printer::log("Using X visual from EGL");
+ XVisualInfo templ;
+ int n;
+ templ.visualid = static_cast<VisualID>(c->getNativeVisualID());
+ VisualInfo = XGetVisualInfo(XDisplay, VisualIDMask, &templ, &n);
}
#endif

@@ -543,9 +551,7 @@ void CIrrDeviceLinux::createDriver()
{
video::SExposedVideoData data;
data.OpenGLLinux.X11Window = XWindow;
- data.OpenGLLinux.X11Display = XDisplay;
-
- ContextManager->initialize(CreationParams, data);
+ static_cast<video::CEGLManager*>(ContextManager)->setWindow(data);

VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager);
}
@@ -558,10 +564,7 @@ void CIrrDeviceLinux::createDriver()
{
video::SExposedVideoData data;
data.OpenGLLinux.X11Window = XWindow;
- data.OpenGLLinux.X11Display = XDisplay;
-
- ContextManager = new video::CEGLManager();
- ContextManager->initialize(CreationParams, data);
+ static_cast<video::CEGLManager*>(ContextManager)->setWindow(data);

VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager);
}
@@ -574,10 +577,7 @@ void CIrrDeviceLinux::createDriver()
{
video::SExposedVideoData data;
data.OpenGLLinux.X11Window = XWindow;
- data.OpenGLLinux.X11Display = XDisplay;
-
- ContextManager = new video::CEGLManager();
- ContextManager->initialize(CreationParams, data);
+ static_cast<video::CEGLManager*>(ContextManager)->setWindow(data);

VideoDriver = video::createWebGL1Driver(CreationParams, FileSystem, ContextManager);
}
--- a/irr/src/CMakeLists.txt
+++ b/irr/src/CMakeLists.txt
@@ -158,7 +158,7 @@ if(ENABLE_OPENGL)
if(DEVICE STREQUAL "WINDOWS")
add_definitions(-D_IRR_COMPILE_WITH_WGL_MANAGER_)
elseif(DEVICE STREQUAL "X11")
- add_definitions(-D_IRR_COMPILE_WITH_GLX_MANAGER_)
+ add_definitions(-D_IRR_COMPILE_WITH_EGL_MANAGER_)
elseif(DEVICE STREQUAL "OSX")
add_definitions(-D_IRR_COMPILE_WITH_NSOGL_MANAGER_)
endif()
@@ -213,7 +213,15 @@ if(ENABLE_GLES2)
find_package(OpenGLES2 REQUIRED)
endif()
if(ENABLE_OPENGL)
- find_package(OpenGL REQUIRED)
+ if(DEVICE STREQUAL "X11")
+ # use components so we can grab EGL
+ find_package(OpenGL REQUIRED COMPONENTS EGL OpenGL)
+ set(OPENGL_LIBRARIES OpenGL::GL)
+ set(EGL_INCLUDE_DIR OpenGL::EGL)
+ set(EGL_LIBRARY OpenGL::EGL)
+ else()
+ find_package(OpenGL REQUIRED)
+ endif()
endif()
if(USE_SDL2)
if(NOT ANDROID)
@@ -315,7 +323,6 @@ target_link_libraries(IRRMESHOBJ PUBLIC tiniergltf::tiniergltf)

set(IRRDRVROBJ
CNullDriver.cpp
- CGLXManager.cpp
CWGLManager.cpp
CEGLManager.cpp
CSDLManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
This is https://github.com/minetest/minetest/pull/15284
but for Termux
--- a/irr/src/CMakeLists.txt
+++ b/irr/src/CMakeLists.txt
@@ -1,6 +1,10 @@
# When enabling SDL2 by default on macOS, don't forget to change
# "NSHighResolutionCapable" to true in "Info.plist".
-if(ANDROID)
+# luanti has migrated to make SDL2 an optional dependency
+# on all platforms that are not using system APIs that directly interface with
+# normal Android/SurfaceFlinger/ANativeWindow/JNI/ART/DEX/Android SDK/Android without Termux
+# with possibly subtly-different behavior between the mode with SDL2 and the mode without it.
+if(THIS_IS_OPTIONAL)
set(DEFAULT_SDL2 ON)
endif()

Loading

0 comments on commit 8d264f9

Please sign in to comment.