diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 96dc8dbadab..13a51736fdc 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include "common/util.h" #include "common/textconsole.h" @@ -167,6 +168,9 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _touch_pt_dt(), _eventScaleX(100), _eventScaleY(100), +#if defined(USE_OPENGL) && defined(USE_GLAD) + _gles2DL(nullptr), +#endif // TODO put these values in some option dlg? _touch_mode(TOUCH_MODE_TOUCHPAD), _touchpad_scale(66), @@ -849,8 +853,24 @@ int OSystem_Android::getGraphicsMode() const { #if defined(USE_OPENGL) && defined(USE_GLAD) void *OSystem_Android::getOpenGLProcAddress(const char *name) const { - // This exists since Android 2.3 (API Level 9) - return (void *)eglGetProcAddress(name); + // eglGetProcAddress exists since Android 2.3 (API Level 9) + // EGL 1.5+ supports loading core functions too: try to optimize + if (JNI::eglVersion() >= 0x00010005) { + return (void *)eglGetProcAddress(name); + } + + if (!_gles2DL) { + _gles2DL = dlopen("libGLESv2.so", RTLD_NOW | RTLD_LOCAL); + if (!_gles2DL) { + error("Can't load libGLESv2.so with old EGL context"); + } + } + + void *ptr = dlsym(_gles2DL, name); + if (!ptr) { + ptr = (void *)eglGetProcAddress(name); + } + return ptr; } #endif diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index f980bd0ac08..119dc07c3d7 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -167,6 +167,10 @@ private: TouchControls _touchControls; +#if defined(USE_OPENGL) && defined(USE_GLAD) + // Cached dlopen object + mutable void *_gles2DL; +#endif public: bool pollEvent(Common::Event &event) override; Common::HardwareInputSet *getHardwareInputSet() override; diff --git a/backends/platform/android/jni-android.cpp b/backends/platform/android/jni-android.cpp index bc38d630c63..e94edde61e5 100644 --- a/backends/platform/android/jni-android.cpp +++ b/backends/platform/android/jni-android.cpp @@ -66,6 +66,7 @@ jobject JNI::_jobj_audio_track = 0; jobject JNI::_jobj_egl = 0; jobject JNI::_jobj_egl_display = 0; jobject JNI::_jobj_egl_surface = 0; +int JNI::_egl_version = 0; Common::Archive *JNI::_asset_archive = 0; OSystem_Android *JNI::_system = 0; @@ -98,6 +99,7 @@ jmethodID JNI::_MID_getSysArchives = 0; jmethodID JNI::_MID_getAllStorageLocations = 0; jmethodID JNI::_MID_initSurface = 0; jmethodID JNI::_MID_deinitSurface = 0; +jmethodID JNI::_MID_eglVersion = 0; jmethodID JNI::_MID_getNewSAFTree = 0; jmethodID JNI::_MID_getSAFTrees = 0; jmethodID JNI::_MID_findSAFTree = 0; @@ -637,6 +639,23 @@ void JNI::deinitSurface() { } } +int JNI::fetchEGLVersion() { + JNIEnv *env = JNI::getEnv(); + + _egl_version = env->CallIntMethod(_jobj, _MID_eglVersion); + + if (env->ExceptionCheck()) { + LOGE("eglVersion failed"); + + env->ExceptionDescribe(); + env->ExceptionClear(); + + _egl_version = 0; + } + + return _egl_version; +} + void JNI::setAudioPause() { JNIEnv *env = JNI::getEnv(); @@ -731,6 +750,7 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager, FIND_METHOD(, getAllStorageLocations, "()[Ljava/lang/String;"); FIND_METHOD(, initSurface, "()Ljavax/microedition/khronos/egl/EGLSurface;"); FIND_METHOD(, deinitSurface, "()V"); + FIND_METHOD(, eglVersion, "()I"); FIND_METHOD(, getNewSAFTree, "(ZZLjava/lang/String;Ljava/lang/String;)Lorg/scummvm/scummvm/SAFFSTree;"); FIND_METHOD(, getSAFTrees, "()[Lorg/scummvm/scummvm/SAFFSTree;"); @@ -738,6 +758,7 @@ void JNI::create(JNIEnv *env, jobject self, jobject asset_manager, _jobj_egl = env->NewGlobalRef(egl); _jobj_egl_display = env->NewGlobalRef(egl_display); + _egl_version = 0; env->DeleteLocalRef(cls); diff --git a/backends/platform/android/jni-android.h b/backends/platform/android/jni-android.h index 00719e5f40e..d0fbfb6ebe5 100644 --- a/backends/platform/android/jni-android.h +++ b/backends/platform/android/jni-android.h @@ -96,6 +96,12 @@ public: static inline bool swapBuffers(); static bool initSurface(); static void deinitSurface(); + static int eglVersion() { + if (_egl_version) { + return _egl_version; + } + return fetchEGLVersion(); + } static void setAudioPause(); static void setAudioPlay(); @@ -120,6 +126,8 @@ private: static jobject _jobj_egl; static jobject _jobj_egl_display; static jobject _jobj_egl_surface; + // cached EGL version + static int _egl_version; static Common::Archive *_asset_archive; static OSystem_Android *_system; @@ -145,6 +153,7 @@ private: static jmethodID _MID_getAllStorageLocations; static jmethodID _MID_initSurface; static jmethodID _MID_deinitSurface; + static jmethodID _MID_eglVersion; static jmethodID _MID_getNewSAFTree; static jmethodID _MID_getSAFTrees; static jmethodID _MID_findSAFTree; @@ -185,6 +194,7 @@ private: static PauseToken _pauseToken; static JNIEnv *fetchEnv(); + static int fetchEGLVersion(); }; inline bool JNI::haveSurface() { diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVM.java b/backends/platform/android/org/scummvm/scummvm/ScummVM.java index 0c2064917bf..e6368b77ae2 100644 --- a/backends/platform/android/org/scummvm/scummvm/ScummVM.java +++ b/backends/platform/android/org/scummvm/scummvm/ScummVM.java @@ -14,6 +14,7 @@ import android.view.SurfaceHolder; import java.util.LinkedHashMap; import java.util.Locale; +import java.util.Scanner; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; @@ -254,6 +255,20 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable { _egl_surface = EGL10.EGL_NO_SURFACE; } + // Callback from C++ peer instance + final protected int eglVersion() { + String version = _egl.eglQueryString(_egl_display, EGL10.EGL_VERSION); + if (version == null) { + // 1.0 + return 0x00010000; + } + + Scanner versionScan = new Scanner(version).useLocale(Locale.ROOT).useDelimiter("[ .]"); + int versionInt = versionScan.nextInt() << 16; + versionInt |= versionScan.nextInt() & 0xffff; + return versionInt; + } + private void deinitEGL() { if (_egl_display != EGL10.EGL_NO_DISPLAY) { _egl.eglMakeCurrent(_egl_display, EGL10.EGL_NO_SURFACE,