From 8d264f9244aeb0f04b4a1cfc8656762fb850f66f Mon Sep 17 00:00:00 2001 From: Robert Kirkman Date: Sat, 23 Nov 2024 22:45:47 -0600 Subject: [PATCH] feat(tur/luanti): perform the migration from SDL2+GLX to libxi+EGL 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. https://github.com/termux/termux-packages/pull/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 https://github.com/minetest/minetest/pull/15286 but applied to Luanti-on-TUR `0005-toggle-on-the-recent-migration-away-from-sdl2.patch`: this is https://github.com/minetest/minetest/pull/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 --- .../0001-force-egl-priority-over-glx.patch | 374 ++++++++++++++++++ ...x-elf-directory-for-cross-compiling.patch} | 0 ...003-bionic-libc-x11-wsi-opengl-es-2.patch} | 0 ...4-prepend-termux-prefix-to-tmp-path.patch} | 0 ...nt-upstream-migration-away-from-sdl2.patch | 16 + ...0006-fix-incompatible-type-ekey-code.patch | 11 + tur/luanti/build.sh | 5 +- 7 files changed, 403 insertions(+), 3 deletions(-) create mode 100644 tur/luanti/0001-force-egl-priority-over-glx.patch rename tur/luanti/{0001-fix-elf-directory-for-cross-compiling.patch => 0002-fix-elf-directory-for-cross-compiling.patch} (100%) rename tur/luanti/{0002-bionic-libc-x11-wsi-opengl-es-2.patch => 0003-bionic-libc-x11-wsi-opengl-es-2.patch} (100%) rename tur/luanti/{0003-prepend-termux-prefix-to-tmp-path.patch => 0004-prepend-termux-prefix-to-tmp-path.patch} (100%) create mode 100644 tur/luanti/0005-toggle-on-the-recent-upstream-migration-away-from-sdl2.patch create mode 100644 tur/luanti/0006-fix-incompatible-type-ekey-code.patch diff --git a/tur/luanti/0001-force-egl-priority-over-glx.patch b/tur/luanti/0001-force-egl-priority-over-glx.patch new file mode 100644 index 000000000..46c12289c --- /dev/null +++ b/tur/luanti/0001-force-egl-priority-over-glx.patch @@ -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 ¶ms, 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 ¶ms, 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 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 ¶ms, 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 + #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 + #endif +@@ -152,8 +148,20 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters ¶m) : + // 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(ContextManager); ++ os::Printer::log("Using X visual from EGL"); ++ XVisualInfo templ; ++ int n; ++ templ.visualid = static_cast(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(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(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(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 diff --git a/tur/luanti/0001-fix-elf-directory-for-cross-compiling.patch b/tur/luanti/0002-fix-elf-directory-for-cross-compiling.patch similarity index 100% rename from tur/luanti/0001-fix-elf-directory-for-cross-compiling.patch rename to tur/luanti/0002-fix-elf-directory-for-cross-compiling.patch diff --git a/tur/luanti/0002-bionic-libc-x11-wsi-opengl-es-2.patch b/tur/luanti/0003-bionic-libc-x11-wsi-opengl-es-2.patch similarity index 100% rename from tur/luanti/0002-bionic-libc-x11-wsi-opengl-es-2.patch rename to tur/luanti/0003-bionic-libc-x11-wsi-opengl-es-2.patch diff --git a/tur/luanti/0003-prepend-termux-prefix-to-tmp-path.patch b/tur/luanti/0004-prepend-termux-prefix-to-tmp-path.patch similarity index 100% rename from tur/luanti/0003-prepend-termux-prefix-to-tmp-path.patch rename to tur/luanti/0004-prepend-termux-prefix-to-tmp-path.patch diff --git a/tur/luanti/0005-toggle-on-the-recent-upstream-migration-away-from-sdl2.patch b/tur/luanti/0005-toggle-on-the-recent-upstream-migration-away-from-sdl2.patch new file mode 100644 index 000000000..5ad98a774 --- /dev/null +++ b/tur/luanti/0005-toggle-on-the-recent-upstream-migration-away-from-sdl2.patch @@ -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() + diff --git a/tur/luanti/0006-fix-incompatible-type-ekey-code.patch b/tur/luanti/0006-fix-incompatible-type-ekey-code.patch new file mode 100644 index 000000000..f2cc6cc2f --- /dev/null +++ b/tur/luanti/0006-fix-incompatible-type-ekey-code.patch @@ -0,0 +1,11 @@ +--- a/irr/src/CIrrDeviceLinux.cpp ++++ b/irr/src/CIrrDeviceLinux.cpp +@@ -693,7 +693,7 @@ EKEY_CODE CIrrDeviceLinux::getKeyCode(XEvent &event) + keyCode = (EKEY_CODE)KeyMap[idx].Win32Key; + } + if (keyCode == 0) { +- keyCode = KEY_UNKNOWN; ++ keyCode = (EKEY_CODE)KEY_UNKNOWN; + if (!mp.X11Key) { + os::Printer::log("No such X11Key, event keycode", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION); + } else if (idx == -1) { diff --git a/tur/luanti/build.sh b/tur/luanti/build.sh index c7cd47297..1df31e29c 100644 --- a/tur/luanti/build.sh +++ b/tur/luanti/build.sh @@ -3,12 +3,11 @@ TERMUX_PKG_DESCRIPTION="An open source voxel game engine." TERMUX_PKG_LICENSE="LGPL-2.1" TERMUX_PKG_MAINTAINER="@termux-user-repository" TERMUX_PKG_VERSION=1:5.10.0 -TERMUX_PKG_REVISION=1 +TERMUX_PKG_REVISION=2 TERMUX_PKG_SRCURL=https://github.com/minetest/minetest/archive/refs/tags/${TERMUX_PKG_VERSION:2}.zip TERMUX_PKG_SHA256=e74e994c0f1b188d60969477f553ad83b8ce20ee1e0e2dcd068120189cb0f56c TERMUX_PKG_AUTO_UPDATE=true -# incomplete depends, i dont have time yet to write the perfect depends for this -TERMUX_PKG_DEPENDS="sdl2, libc++, openal-soft, libvorbis, libsqlite, freetype, libpng, libcurl, libandroid-spawn" +TERMUX_PKG_DEPENDS="freetype, libandroid-spawn, libc++, libcurl, libpng, libsqlite, libvorbis, libxi, openal-soft" termux_step_pre_configure() { export LDFLAGS+=" -landroid-spawn"