From a7d50fa8fa8706b15d452320c834b274b9f7478f Mon Sep 17 00:00:00 2001 From: Emux Date: Sat, 23 Mar 2019 13:41:54 +0200 Subject: [PATCH] OpenGL ES 3.0: sanitize Android #646 --- .../src/org/oscim/android/MapView.java | 71 ++++++++++++++++--- .../oscim/android/gl/GlContextFactory.java | 11 +-- 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/vtm-android/src/org/oscim/android/MapView.java b/vtm-android/src/org/oscim/android/MapView.java index d46ec7e5..db779007 100644 --- a/vtm-android/src/org/oscim/android/MapView.java +++ b/vtm-android/src/org/oscim/android/MapView.java @@ -47,6 +47,9 @@ import org.oscim.utils.Parameters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; @@ -61,10 +64,12 @@ public class MapView extends GLSurfaceView { static final Logger log = LoggerFactory.getLogger(MapView.class); + private static final Pattern GL_PATTERN = Pattern.compile("OpenGL ES (\\d(\\.\\d){0,2})"); + /** * Target OpenGL ES version, if not available fall back to OpenGL ES 2.0 */ - public static int targetGLESVersion = 3; + public static double targetGLESVersion = 3.0; private static void init() { System.loadLibrary("vtm-jni"); @@ -122,8 +127,12 @@ public class MapView extends GLSurfaceView { mMap = new AndroidMap(this); /* Initialize Renderer */ - //setEGLContextClientVersion(targetGLESVersion); - setEGLContextFactory(new GlContextFactory()); + try { + setEGLContextFactory(new GlContextFactory()); + } catch (Throwable t) { + log.error("Falling back to GLES 2", t); + setEGLContextClientVersion(2); + } setEGLConfigChooser(new GlConfigChooser()); if (GLAdapter.debug) @@ -301,16 +310,58 @@ public class MapView extends GLSurfaceView { super(map); } + /** + * @return GL version as [major, minor, release] + */ + private int[] extractVersion(String versionString) { + int[] version = new int[3]; + Matcher matcher = GL_PATTERN.matcher(versionString); + if (matcher.find()) { + String[] split = matcher.group(1).split("\\."); + version[0] = parseInt(split[0], 2); + version[1] = split.length < 2 ? 0 : parseInt(split[1], 0); + version[2] = split.length < 3 ? 0 : parseInt(split[2], 0); + } else { + log.error("Invalid version string: " + versionString); + version[0] = 2; + version[1] = 0; + version[2] = 0; + } + return version; + } + + /** + * Forgiving parsing of GL major, minor and release versions as some manufacturers don't adhere to spec. + **/ + private int parseInt(String value, int defaultValue) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + log.error("Error parsing number: " + value + ", assuming: " + defaultValue); + return defaultValue; + } + } + @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { - // Check OpenGL ES version - String versionStr = gl.glGetString(GL10.GL_VERSION); - int versionIndex = "OpenGL ES ".length(); - float version = Float.parseFloat(versionStr.substring(versionIndex, versionIndex + 3)); - if (version >= 3) - GLAdapter.init(new AndroidGL30()); - else + try { + // Create a minimum supported OpenGL ES context, then check: + String versionString = gl.glGetString(GL10.GL_VERSION); + log.info("Version: " + versionString); + // The version format is displayed as: "OpenGL ES ." + // followed by optional content provided by the implementation. + + // OpenGLES. + int[] version = extractVersion(versionString); + int majorVersion = version[0]; + if (majorVersion >= 3) + GLAdapter.init(new AndroidGL30()); + else + GLAdapter.init(new AndroidGL()); + } catch (Throwable t) { + log.error("Falling back to GLES 2", t); GLAdapter.init(new AndroidGL()); + } super.onSurfaceCreated(); } diff --git a/vtm-android/src/org/oscim/android/gl/GlContextFactory.java b/vtm-android/src/org/oscim/android/gl/GlContextFactory.java index 814310b0..47673e9d 100644 --- a/vtm-android/src/org/oscim/android/gl/GlContextFactory.java +++ b/vtm-android/src/org/oscim/android/gl/GlContextFactory.java @@ -1,5 +1,6 @@ /* * Copyright 2019 Gustl22 + * Copyright 2019 devemux86 * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software @@ -38,7 +39,9 @@ import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; /** - * See https://github.com/libgdx/libgdx/blob/master/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/GLSurfaceView20.java + * https://developer.android.com/guide/topics/graphics/opengl.html#version-check + *

+ * https://github.com/libgdx/libgdx/blob/master/backends/gdx-backend-android/src/com/badlogic/gdx/backends/android/surfaceview/GLSurfaceView20.java */ public class GlContextFactory implements GLSurfaceView.EGLContextFactory { @@ -48,15 +51,15 @@ public class GlContextFactory implements GLSurfaceView.EGLContextFactory { @Override public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { - log.info("creating OpenGL ES " + MapView.targetGLESVersion + ".0 context"); + log.info("creating OpenGL ES " + MapView.targetGLESVersion + " context"); checkEglError("Before eglCreateContext " + MapView.targetGLESVersion, egl); - int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, MapView.targetGLESVersion, EGL10.EGL_NONE}; + int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, (int) MapView.targetGLESVersion, EGL10.EGL_NONE}; EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); boolean success = checkEglError("After eglCreateContext " + MapView.targetGLESVersion, egl); if ((!success || context == null) && MapView.targetGLESVersion > 2) { log.warn("Falling back to GLES 2"); - MapView.targetGLESVersion = 2; + MapView.targetGLESVersion = 2.0; return createContext(egl, display, eglConfig); } log.info("Returning a GLES " + MapView.targetGLESVersion + " context");