From a67d92c2ca4eb3aad92d8c69ed9ae7fcfd7a18b2 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Sat, 28 Sep 2019 14:13:06 +0300 Subject: [PATCH] Lower limit from API 21 to API 19 (#1701) * Lower limit from API 21 to API 19 This was requested by an internal application. API 19 is when OpenGL ES 3.0 support was added so there is no good reason for us to not support this API level. The only trick is to avoid referring to the glTexStorage2DMultisample symbol directly as it only exists in 3.1. * Compile out code we never use * Use reflection to handle shared EGL contexts pre-API 21. * Remove comment * More fixes required to run on API level 19 - dlym() fails for ashmem on API 19, so we only try on API 26+ instead. - Older emulation for OpenGL ES 3.0 returns error states for valid API calls so we need to clear the GL error bit before we create the GL driver. - Activity lifecycle changes since API 19 would cause animations to keep running and to reference destroyed objects. - EGLContext.getNativeHandle() is new in API 21, we need to use reflection on API 19. The new code path uses the class loading trick to avoid a bytecode verification error on API 19. * Filament now runs properly on API level 19 This commit adds a new api_level() API to libutils which can be used to query the platform's API level. On Android it works as expected, other platforms currently return 0. --- RELEASE_NOTES.md | 1 + android/filamat-android/build.gradle | 2 +- .../.idea/codeStyles/Project.xml | 134 ++++++++++++++---- android/filament-android/build.gradle | 6 +- .../android/filament/AndroidPlatform.java | 18 ++- .../android/filament/AndroidPlatform21.java | 25 ++++ android/gltfio-android/build.gradle | 2 +- android/samples/gltf-bloom/app/build.gradle | 2 +- .../android/filament/gltf/MainActivity.kt | 5 + .../samples/hello-triangle/app/build.gradle | 2 +- .../filament/hellotriangle/MainActivity.kt | 5 + .../image-based-lighting/app/build.gradle | 2 +- .../android/filament/ibl/MainActivity.kt | 5 + android/samples/lit-cube/app/build.gradle | 2 +- .../android/filament/litcube/MainActivity.kt | 5 + .../samples/material-builder/app/build.gradle | 2 +- .../filament/material_builder/MainActivity.kt | 5 + android/samples/texture-view/app/build.gradle | 2 +- .../filament/textureview/MainActivity.kt | 5 + .../samples/textured-object/app/build.gradle | 2 +- .../android/filament/textured/MainActivity.kt | 5 + .../filament/textured/TextureLoader.kt | 21 +-- .../samples/transparent-view/app/build.gradle | 2 +- .../transparentrendering/MainActivity.kt | 5 + build.sh | 3 + build/toolchain-arm7-linux-android.cmake | 2 +- build/toolchain-x86-linux-android.cmake | 2 +- .../android/ExternalStreamManagerAndroid.cpp | 21 +-- .../android/ExternalTextureManagerAndroid.cpp | 8 +- filament/backend/src/opengl/OpenGLDriver.cpp | 32 +++-- filament/backend/src/opengl/PlatformEGL.cpp | 22 ++- libs/utils/CMakeLists.txt | 1 + libs/utils/include/utils/api_level.h | 34 +++++ libs/utils/src/api_level.cpp | 53 +++++++ libs/utils/src/ashmem.cpp | 17 ++- 35 files changed, 373 insertions(+), 87 deletions(-) create mode 100644 android/filament-android/src/main/java/com/google/android/filament/AndroidPlatform21.java create mode 100644 libs/utils/include/utils/api_level.h create mode 100644 libs/utils/src/api_level.cpp diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 7f6e8f8866..494fd45c23 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -5,6 +5,7 @@ A new header is inserted each time a *tag* is created. ## Next release +- Minimum API level on Android is now API 19 instead of API 21. - Added missing API documentation. - Improved existing API documentation. - Added `Camera::setExposure(float)` to directly control the camera's exposure. diff --git a/android/filamat-android/build.gradle b/android/filamat-android/build.gradle index ba1faf9895..9e04bc2d86 100644 --- a/android/filamat-android/build.gradle +++ b/android/filamat-android/build.gradle @@ -47,7 +47,7 @@ android { externalNativeBuild { cmake { arguments.add("-DANDROID_PIE=ON") - arguments.add("-DANDROID_PLATFORM=android-21") + arguments.add("-DANDROID_PLATFORM=android-19") arguments.add("-DANDROID_STL=c++_static") arguments.add("-DFILAMENT_DIST_DIR=${filament_path}".toString()) cppFlags.add("-std=c++14") diff --git a/android/filament-android/.idea/codeStyles/Project.xml b/android/filament-android/.idea/codeStyles/Project.xml index 30aa626c23..ae78c113ff 100644 --- a/android/filament-android/.idea/codeStyles/Project.xml +++ b/android/filament-android/.idea/codeStyles/Project.xml @@ -1,29 +1,113 @@ - - - - - - - - - - + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
\ No newline at end of file diff --git a/android/filament-android/build.gradle b/android/filament-android/build.gradle index 7aece47a7a..97bd4c621e 100644 --- a/android/filament-android/build.gradle +++ b/android/filament-android/build.gradle @@ -37,9 +37,9 @@ if (project.hasProperty("filament_dist_dir")) { android { compileSdkVersion 29 defaultConfig { - // Our minSdkVersion is actually 21, we lie and say 14 here so apps don't have + // Our minSdkVersion is actually 19, we lie and say 14 here so apps don't have // to increase their minSdkVersion unnecessarily. It is however up to them to - // ensure they do not initialize Filament on API levels < 21. + // ensure they do not initialize Filament on API levels < 19. minSdkVersion 14 targetSdkVersion 29 versionCode 1 @@ -50,7 +50,7 @@ android { externalNativeBuild { cmake { arguments.add("-DANDROID_PIE=ON") - arguments.add("-DANDROID_PLATFORM=android-21") + arguments.add("-DANDROID_PLATFORM=android-19") arguments.add("-DANDROID_STL=c++_static") arguments.add("-DFILAMENT_DIST_DIR=${filament_path}".toString()) cppFlags.add("-std=c++14") diff --git a/android/filament-android/src/main/java/com/google/android/filament/AndroidPlatform.java b/android/filament-android/src/main/java/com/google/android/filament/AndroidPlatform.java index 6570a623c4..cb6add9e04 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/AndroidPlatform.java +++ b/android/filament-android/src/main/java/com/google/android/filament/AndroidPlatform.java @@ -19,8 +19,10 @@ package com.google.android.filament; import android.graphics.SurfaceTexture; import android.opengl.EGL14; import android.opengl.EGLContext; +import android.os.Build; import android.util.Log; import android.view.Surface; +import java.lang.reflect.Method; final class AndroidPlatform extends Platform { private static final String LOG_TAG = "Filament"; @@ -59,6 +61,20 @@ final class AndroidPlatform extends Platform { @Override long getSharedContextNativeHandle(Object sharedContext) { - return ((EGLContext) sharedContext).getNativeHandle(); + if (Build.VERSION.SDK_INT >= 21) { + return AndroidPlatform21.getSharedContextNativeHandle(sharedContext); + } else { + try { + //noinspection JavaReflectionMemberAccess + Method method = EGLContext.class.getDeclaredMethod("getHandle"); + Integer handle = (Integer) method.invoke(sharedContext); + //noinspection ConstantConditions + return handle.longValue(); + } catch (Exception e) { + Log.d(LOG_TAG, "Could not access shared context's native handle", e); + } + // Should not happen + return 0; + } } } diff --git a/android/filament-android/src/main/java/com/google/android/filament/AndroidPlatform21.java b/android/filament-android/src/main/java/com/google/android/filament/AndroidPlatform21.java new file mode 100644 index 0000000000..c50c00a167 --- /dev/null +++ b/android/filament-android/src/main/java/com/google/android/filament/AndroidPlatform21.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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. + */ + +package com.google.android.filament; + +import android.opengl.EGLContext; + +final class AndroidPlatform21 { + static long getSharedContextNativeHandle(Object sharedContext) { + return ((EGLContext) sharedContext).getNativeHandle(); + } +} diff --git a/android/gltfio-android/build.gradle b/android/gltfio-android/build.gradle index 5024fd04a8..2f904336a6 100644 --- a/android/gltfio-android/build.gradle +++ b/android/gltfio-android/build.gradle @@ -47,7 +47,7 @@ android { externalNativeBuild { cmake { arguments.add("-DANDROID_PIE=ON") - arguments.add("-DANDROID_PLATFORM=android-21") + arguments.add("-DANDROID_PLATFORM=android-19") arguments.add("-DANDROID_STL=c++_static") arguments.add("-DFILAMENT_DIST_DIR=${filament_path}".toString()) cppFlags.add("-std=c++14") diff --git a/android/samples/gltf-bloom/app/build.gradle b/android/samples/gltf-bloom/app/build.gradle index a373781fd3..707374599a 100644 --- a/android/samples/gltf-bloom/app/build.gradle +++ b/android/samples/gltf-bloom/app/build.gradle @@ -38,7 +38,7 @@ android { compileSdkVersion 29 defaultConfig { applicationId "com.google.android.filament.gltf" - minSdkVersion 26 + minSdkVersion 19 targetSdkVersion 29 versionCode 1 versionName "1.0" diff --git a/android/samples/gltf-bloom/app/src/main/java/com/google/android/filament/gltf/MainActivity.kt b/android/samples/gltf-bloom/app/src/main/java/com/google/android/filament/gltf/MainActivity.kt index 0e59412946..013c007a04 100644 --- a/android/samples/gltf-bloom/app/src/main/java/com/google/android/filament/gltf/MainActivity.kt +++ b/android/samples/gltf-bloom/app/src/main/java/com/google/android/filament/gltf/MainActivity.kt @@ -426,6 +426,11 @@ class MainActivity : Activity() { override fun onDestroy() { super.onDestroy() + + // Stop the animation and any pending frame + choreographer.removeFrameCallback(frameScheduler) + animator.cancel(); + // Always detach the surface before destroying the engine uiHelper.detach() diff --git a/android/samples/hello-triangle/app/build.gradle b/android/samples/hello-triangle/app/build.gradle index 9523759200..bb12e8c252 100644 --- a/android/samples/hello-triangle/app/build.gradle +++ b/android/samples/hello-triangle/app/build.gradle @@ -22,7 +22,7 @@ android { compileSdkVersion 29 defaultConfig { applicationId "com.google.android.filament.hellotriangle" - minSdkVersion 21 + minSdkVersion 19 targetSdkVersion 29 versionCode 1 versionName "1.0" diff --git a/android/samples/hello-triangle/app/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt b/android/samples/hello-triangle/app/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt index fdc9e497a8..f19c1abbac 100644 --- a/android/samples/hello-triangle/app/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt +++ b/android/samples/hello-triangle/app/src/main/java/com/google/android/filament/hellotriangle/MainActivity.kt @@ -253,6 +253,11 @@ class MainActivity : Activity() { override fun onDestroy() { super.onDestroy() + + // Stop the animation and any pending frame + choreographer.removeFrameCallback(frameScheduler) + animator.cancel(); + // Always detach the surface before destroying the engine uiHelper.detach() diff --git a/android/samples/image-based-lighting/app/build.gradle b/android/samples/image-based-lighting/app/build.gradle index 75622921a7..ddeff1f5e0 100644 --- a/android/samples/image-based-lighting/app/build.gradle +++ b/android/samples/image-based-lighting/app/build.gradle @@ -40,7 +40,7 @@ android { compileSdkVersion 29 defaultConfig { applicationId "com.google.android.filament.ibl" - minSdkVersion 21 + minSdkVersion 19 targetSdkVersion 29 versionCode 1 versionName "1.0" diff --git a/android/samples/image-based-lighting/app/src/main/java/com/google/android/filament/ibl/MainActivity.kt b/android/samples/image-based-lighting/app/src/main/java/com/google/android/filament/ibl/MainActivity.kt index 14b02175bd..0d9f94416a 100644 --- a/android/samples/image-based-lighting/app/src/main/java/com/google/android/filament/ibl/MainActivity.kt +++ b/android/samples/image-based-lighting/app/src/main/java/com/google/android/filament/ibl/MainActivity.kt @@ -230,6 +230,11 @@ class MainActivity : Activity() { override fun onDestroy() { super.onDestroy() + + // Stop the animation and any pending frame + choreographer.removeFrameCallback(frameScheduler) + animator.cancel(); + // Always detach the surface before destroying the engine uiHelper.detach() diff --git a/android/samples/lit-cube/app/build.gradle b/android/samples/lit-cube/app/build.gradle index 8d78fa8713..daa0ce1a11 100644 --- a/android/samples/lit-cube/app/build.gradle +++ b/android/samples/lit-cube/app/build.gradle @@ -22,7 +22,7 @@ android { compileSdkVersion 29 defaultConfig { applicationId "com.google.android.filament.litcube" - minSdkVersion 21 + minSdkVersion 19 targetSdkVersion 29 versionCode 1 versionName "1.0" diff --git a/android/samples/lit-cube/app/src/main/java/com/google/android/filament/litcube/MainActivity.kt b/android/samples/lit-cube/app/src/main/java/com/google/android/filament/litcube/MainActivity.kt index 95839956a8..defa60a5f1 100644 --- a/android/samples/lit-cube/app/src/main/java/com/google/android/filament/litcube/MainActivity.kt +++ b/android/samples/lit-cube/app/src/main/java/com/google/android/filament/litcube/MainActivity.kt @@ -338,6 +338,11 @@ class MainActivity : Activity() { override fun onDestroy() { super.onDestroy() + + // Stop the animation and any pending frame + choreographer.removeFrameCallback(frameScheduler) + animator.cancel(); + // Always detach the surface before destroying the engine uiHelper.detach() diff --git a/android/samples/material-builder/app/build.gradle b/android/samples/material-builder/app/build.gradle index 874dbaf013..1d634c0ec0 100644 --- a/android/samples/material-builder/app/build.gradle +++ b/android/samples/material-builder/app/build.gradle @@ -27,7 +27,7 @@ android { compileSdkVersion 29 defaultConfig { applicationId "com.google.android.filament.material_builder" - minSdkVersion 21 + minSdkVersion 19 targetSdkVersion 29 versionCode 1 versionName "1.0" diff --git a/android/samples/material-builder/app/src/main/java/com/google/android/filament/material_builder/MainActivity.kt b/android/samples/material-builder/app/src/main/java/com/google/android/filament/material_builder/MainActivity.kt index a0f308b001..5c8b96be41 100644 --- a/android/samples/material-builder/app/src/main/java/com/google/android/filament/material_builder/MainActivity.kt +++ b/android/samples/material-builder/app/src/main/java/com/google/android/filament/material_builder/MainActivity.kt @@ -266,6 +266,11 @@ class MainActivity : Activity() { override fun onDestroy() { super.onDestroy() + + // Stop the animation and any pending frame + choreographer.removeFrameCallback(frameScheduler) + animator.cancel(); + // Always detach the surface before destroying the engine uiHelper.detach() diff --git a/android/samples/texture-view/app/build.gradle b/android/samples/texture-view/app/build.gradle index 70afbb965e..0559e057a9 100644 --- a/android/samples/texture-view/app/build.gradle +++ b/android/samples/texture-view/app/build.gradle @@ -22,7 +22,7 @@ android { compileSdkVersion 29 defaultConfig { applicationId "com.google.android.filament.textureview" - minSdkVersion 21 + minSdkVersion 19 targetSdkVersion 29 versionCode 1 versionName "1.0" diff --git a/android/samples/texture-view/app/src/main/java/com/google/android/filament/textureview/MainActivity.kt b/android/samples/texture-view/app/src/main/java/com/google/android/filament/textureview/MainActivity.kt index 436ad9dc97..550d399d03 100644 --- a/android/samples/texture-view/app/src/main/java/com/google/android/filament/textureview/MainActivity.kt +++ b/android/samples/texture-view/app/src/main/java/com/google/android/filament/textureview/MainActivity.kt @@ -253,6 +253,11 @@ class MainActivity : Activity() { override fun onDestroy() { super.onDestroy() + + // Stop the animation and any pending frame + choreographer.removeFrameCallback(frameScheduler) + animator.cancel(); + // Always detach the surface before destroying the engine uiHelper.detach() diff --git a/android/samples/textured-object/app/build.gradle b/android/samples/textured-object/app/build.gradle index 87b6a9dd81..4db15b8247 100644 --- a/android/samples/textured-object/app/build.gradle +++ b/android/samples/textured-object/app/build.gradle @@ -40,7 +40,7 @@ android { compileSdkVersion 29 defaultConfig { applicationId "com.google.android.filament.textured" - minSdkVersion 26 + minSdkVersion 19 targetSdkVersion 29 versionCode 1 versionName "1.0" diff --git a/android/samples/textured-object/app/src/main/java/com/google/android/filament/textured/MainActivity.kt b/android/samples/textured-object/app/src/main/java/com/google/android/filament/textured/MainActivity.kt index 181a2898f9..161a495eb9 100644 --- a/android/samples/textured-object/app/src/main/java/com/google/android/filament/textured/MainActivity.kt +++ b/android/samples/textured-object/app/src/main/java/com/google/android/filament/textured/MainActivity.kt @@ -249,6 +249,11 @@ class MainActivity : Activity() { override fun onDestroy() { super.onDestroy() + + // Stop the animation and any pending frame + choreographer.removeFrameCallback(frameScheduler) + animator.cancel(); + // Always detach the surface before destroying the engine uiHelper.detach() diff --git a/android/samples/textured-object/app/src/main/java/com/google/android/filament/textured/TextureLoader.kt b/android/samples/textured-object/app/src/main/java/com/google/android/filament/textured/TextureLoader.kt index 784a914e2a..1306e6fb1b 100644 --- a/android/samples/textured-object/app/src/main/java/com/google/android/filament/textured/TextureLoader.kt +++ b/android/samples/textured-object/app/src/main/java/com/google/android/filament/textured/TextureLoader.kt @@ -79,19 +79,20 @@ private fun internalFormat(type: TextureType) = when (type) { } // Not required when SKIP_BITMAP_COPY is true -private fun format(bitmap: Bitmap) = when (bitmap.config) { - Bitmap.Config.ALPHA_8 -> Texture.Format.ALPHA - Bitmap.Config.RGB_565 -> Texture.Format.RGB - Bitmap.Config.ARGB_8888 -> Texture.Format.RGBA - Bitmap.Config.RGBA_F16 -> Texture.Format.RGBA +// Use String representation for compatibility across API levels +private fun format(bitmap: Bitmap) = when (bitmap.config.name) { + "ALPHA_8" -> Texture.Format.ALPHA + "RGB_565" -> Texture.Format.RGB + "ARGB_8888" -> Texture.Format.RGBA + "RGBA_F16" -> Texture.Format.RGBA else -> throw IllegalArgumentException("Unknown bitmap configuration") } // Not required when SKIP_BITMAP_COPY is true -private fun type(bitmap: Bitmap) = when (bitmap.config) { - Bitmap.Config.ALPHA_8 -> Texture.Type.UBYTE - Bitmap.Config.RGB_565 -> Texture.Type.UBYTE - Bitmap.Config.ARGB_8888 -> Texture.Type.UBYTE - Bitmap.Config.RGBA_F16 -> Texture.Type.HALF +private fun type(bitmap: Bitmap) = when (bitmap.config.name) { + "ALPHA_8" -> Texture.Type.UBYTE + "RGB_565" -> Texture.Type.UBYTE + "ARGB_8888" -> Texture.Type.UBYTE + "RGBA_F16" -> Texture.Type.HALF else -> throw IllegalArgumentException("Unsupported bitmap configuration") } diff --git a/android/samples/transparent-view/app/build.gradle b/android/samples/transparent-view/app/build.gradle index 9523759200..bb12e8c252 100644 --- a/android/samples/transparent-view/app/build.gradle +++ b/android/samples/transparent-view/app/build.gradle @@ -22,7 +22,7 @@ android { compileSdkVersion 29 defaultConfig { applicationId "com.google.android.filament.hellotriangle" - minSdkVersion 21 + minSdkVersion 19 targetSdkVersion 29 versionCode 1 versionName "1.0" diff --git a/android/samples/transparent-view/app/src/main/java/com/google/android/filament/transparentrendering/MainActivity.kt b/android/samples/transparent-view/app/src/main/java/com/google/android/filament/transparentrendering/MainActivity.kt index e3d7097c7e..7d81786a00 100644 --- a/android/samples/transparent-view/app/src/main/java/com/google/android/filament/transparentrendering/MainActivity.kt +++ b/android/samples/transparent-view/app/src/main/java/com/google/android/filament/transparentrendering/MainActivity.kt @@ -271,6 +271,11 @@ class MainActivity : Activity() { override fun onDestroy() { super.onDestroy() + + // Stop the animation and any pending frame + choreographer.removeFrameCallback(frameScheduler) + animator.cancel(); + // Always detach the surface before destroying the engine uiHelper.detach() diff --git a/build.sh b/build.sh index a4efc3142d..6bcf929f8c 100755 --- a/build.sh +++ b/build.sh @@ -121,8 +121,11 @@ function build_clean { echo "Cleaning build directories..." rm -Rf out rm -Rf android/filament-android/build android/filament-android/.externalNativeBuild + rm -Rf android/filament-android/build android/filament-android/.cxx rm -Rf android/filamat-android/build android/filamat-android/.externalNativeBuild + rm -Rf android/filamat-android/build android/filamat-android/.cxx rm -Rf android/gltfio-android/build android/gltfio-android/.externalNativeBuild + rm -Rf android/gltfio-android/build android/gltfio-android/.cxx } function build_desktop_target { diff --git a/build/toolchain-arm7-linux-android.cmake b/build/toolchain-arm7-linux-android.cmake index 3e37fd35db..aa3cbb1ce8 100644 --- a/build/toolchain-arm7-linux-android.cmake +++ b/build/toolchain-arm7-linux-android.cmake @@ -21,7 +21,7 @@ set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_VERSION 1) # android -set(API_LEVEL 21) +set(API_LEVEL 19) # architecture set(ARCH armv7a-linux-androideabi) diff --git a/build/toolchain-x86-linux-android.cmake b/build/toolchain-x86-linux-android.cmake index e5d68d2a0c..d1d9f1ab75 100644 --- a/build/toolchain-x86-linux-android.cmake +++ b/build/toolchain-x86-linux-android.cmake @@ -21,7 +21,7 @@ set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_VERSION 1) # android -set(API_LEVEL 21) +set(API_LEVEL 19) # architecture set(ARCH i686-linux-android) diff --git a/filament/backend/src/android/ExternalStreamManagerAndroid.cpp b/filament/backend/src/android/ExternalStreamManagerAndroid.cpp index 26b9e0eff0..da2941f545 100644 --- a/filament/backend/src/android/ExternalStreamManagerAndroid.cpp +++ b/filament/backend/src/android/ExternalStreamManagerAndroid.cpp @@ -16,6 +16,7 @@ #include "ExternalStreamManagerAndroid.h" +#include #include #include @@ -42,22 +43,22 @@ ExternalStreamManagerAndroid& ExternalStreamManagerAndroid::get() noexcept { ExternalStreamManagerAndroid::ExternalStreamManagerAndroid() noexcept : mVm(VirtualMachineEnv::get()) { - // We're not initializing the JVM here -- but we could -- because most of the time - // we don't need the jvm. Instead we do the initialization on first use. This means we could get - // a nasty slow down the very first time, but we'll live with it for now. - loadSymbol(ASurfaceTexture_fromSurfaceTexture, "ASurfaceTexture_fromSurfaceTexture"); - loadSymbol(ASurfaceTexture_release, "ASurfaceTexture_release"); - loadSymbol(ASurfaceTexture_attachToGLContext, "ASurfaceTexture_attachToGLContext"); - loadSymbol(ASurfaceTexture_detachFromGLContext, "ASurfaceTexture_detachFromGLContext"); - loadSymbol(ASurfaceTexture_updateTexImage, "ASurfaceTexture_updateTexImage"); - loadSymbol(ASurfaceTexture_getTimestamp, "ASurfaceTexture_getTimestamp"); + // the following dlsym() calls don't work on API 19 + if (api_level() >= 21) { + loadSymbol(ASurfaceTexture_fromSurfaceTexture, "ASurfaceTexture_fromSurfaceTexture"); + loadSymbol(ASurfaceTexture_release, "ASurfaceTexture_release"); + loadSymbol(ASurfaceTexture_attachToGLContext, "ASurfaceTexture_attachToGLContext"); + loadSymbol(ASurfaceTexture_detachFromGLContext, "ASurfaceTexture_detachFromGLContext"); + loadSymbol(ASurfaceTexture_updateTexImage, "ASurfaceTexture_updateTexImage"); + loadSymbol(ASurfaceTexture_getTimestamp, "ASurfaceTexture_getTimestamp"); + } + if (ASurfaceTexture_fromSurfaceTexture) { slog.d << "Using ASurfaceTexture" << io::endl; } } - UTILS_NOINLINE JNIEnv* ExternalStreamManagerAndroid::getEnvironmentSlow() noexcept { JNIEnv * env = mVm.getEnvironment(); diff --git a/filament/backend/src/android/ExternalTextureManagerAndroid.cpp b/filament/backend/src/android/ExternalTextureManagerAndroid.cpp index a52fb71ebd..d667db2bcc 100644 --- a/filament/backend/src/android/ExternalTextureManagerAndroid.cpp +++ b/filament/backend/src/android/ExternalTextureManagerAndroid.cpp @@ -17,6 +17,7 @@ #include "ExternalTextureManagerAndroid.h" +#include #include #include @@ -94,8 +95,11 @@ ExternalTextureManagerAndroid::ExternalTextureManagerAndroid() noexcept // if we compile for API 26 (Oreo) and above, we're guaranteed to have AHardwareBuffer // in all other cases, we need to get them at runtime. #ifndef PLATFORM_HAS_HARDWAREBUFFER - loadSymbol(AHardwareBuffer_allocate, "AHardwareBuffer_allocate"); - loadSymbol(AHardwareBuffer_release, "AHardwareBuffer_release"); + // the following dlsym() calls don't work on API 19 + if (api_level() >= 21) { + loadSymbol(AHardwareBuffer_allocate, "AHardwareBuffer_allocate"); + loadSymbol(AHardwareBuffer_release, "AHardwareBuffer_release"); + } #endif } diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index ebe1c962f8..db391ce4c2 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -35,6 +35,10 @@ // we don't want to rely on it. #define ALLOW_REVERSE_MULTISAMPLE_RESOLVE false +// We can only support this feature on OpenGL ES 3.1+ +// Support is currently disabled as we don't need it +#define TEXTURE_2D_MULTISAMPLE_SUPPORTED false + #if defined(__EMSCRIPTEN__) #define HAS_MAPBUFFERS 0 #else @@ -65,7 +69,7 @@ Driver* OpenGLDriverFactory::create( return OpenGLDriver::create(platform, sharedGLContext); } -} // namesapce backend +} // namespace backend using namespace backend; using namespace GLUtils; @@ -76,7 +80,8 @@ Driver* OpenGLDriver::create( assert(platform); OpenGLPlatform* const ec = platform; - { // here we check we're on a supported version of GL before initializing the driver + { + // here we check we're on a supported version of GL before initializing the driver GLint major = 0, minor = 0; glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MINOR_VERSION, &minor); @@ -93,7 +98,6 @@ Driver* OpenGLDriver::create( if (UTILS_UNLIKELY(!(major >= 3 && minor >= 0))) { PANIC_LOG("OpenGL ES 3.0 minimum needed (current %d.%d)", major, minor); goto cleanup; - } } else if (GL41_HEADERS) { // we require GL 4.1 headers and minimum version @@ -573,20 +577,24 @@ void OpenGLDriver::textureStorage(OpenGLDriver::GLTexture* t, break; } case GL_TEXTURE_2D_MULTISAMPLE: - // NOTE: if there is a mix of texture and renderbuffers, "fixed_sample_locations" must be true - // NOTE: what's the benefit of setting "fixed_sample_locations" to false? + if (TEXTURE_2D_MULTISAMPLE_SUPPORTED) { + // NOTE: if there is a mix of texture and renderbuffers, "fixed_sample_locations" must be true + // NOTE: what's the benefit of setting "fixed_sample_locations" to false? #if GLES31_HEADERS - // only supported from GL 4.3 and GLES 3.1 - glTexStorage2DMultisample(t->gl.target, t->samples, t->gl.internalFormat, - GLsizei(width), GLsizei(height), GL_TRUE); + // only supported from GL 4.3 and GLES 3.1 + glTexStorage2DMultisample(t->gl.target, t->samples, t->gl.internalFormat, + GLsizei(width), GLsizei(height), GL_TRUE); #elif GL41_HEADERS - // only supported in GL (never in GLES) - // TODO: use glTexStorage2DMultisample() on GL 4.3 and above - glTexImage2DMultisample(t->gl.target, t->samples, t->gl.internalFormat, - GLsizei(width), GLsizei(height), GL_TRUE); + // only supported in GL (never in GLES) + // TODO: use glTexStorage2DMultisample() on GL 4.3 and above + glTexImage2DMultisample(t->gl.target, t->samples, t->gl.internalFormat, + GLsizei(width), GLsizei(height), GL_TRUE); #else # error "GL/GLES header version not supported" #endif + } else { + PANIC_LOG("GL_TEXTURE_2D_MULTISAMPLE is not supported"); + } break; default: // cannot happen break; diff --git a/filament/backend/src/opengl/PlatformEGL.cpp b/filament/backend/src/opengl/PlatformEGL.cpp index 099adba4fd..4a2bf9336d 100644 --- a/filament/backend/src/opengl/PlatformEGL.cpp +++ b/filament/backend/src/opengl/PlatformEGL.cpp @@ -41,9 +41,11 @@ #include #include -// We require filament to be built with a API 21 toolchain, before that, OpenGLES 3.0 didn't exist -#if __ANDROID_API__ < 21 -# error "__ANDROID_API__ must be at least 21" +// We require filament to be built with a API 19 toolchain, before that, OpenGLES 3.0 didn't exist +// Actually, OpenGL ES 3.0 was added to API 18, but API 19 is the better target and +// the minimum for Jetpack at the time of this comment. +#if __ANDROID_API__ < 19 +# error "__ANDROID_API__ must be at least 19" #endif using namespace utils; @@ -96,6 +98,14 @@ static void logEglError(const char* name) noexcept { slog.e << name << " failed with " << err << io::endl; } +static void clearGlError() noexcept { + // clear GL error that may have been set by previous calls + GLenum error = glGetError(); + if (error != GL_NO_ERROR) { + slog.w << "Ignoring pending GL error " << io::hex << error << io::endl; + } +} + class unordered_string_set : public std::unordered_set { public: bool has(const char* str) { @@ -251,7 +261,6 @@ Driver* PlatformEGL::createDriver(void* sharedContext) noexcept { } } - if (!extensions.has("EGL_KHR_no_config_context")) { // if we have the EGL_KHR_no_config_context, we don't need to worry about the config // when creating the context, otherwise, we must always pick a transparent config. @@ -290,6 +299,9 @@ Driver* PlatformEGL::createDriver(void* sharedContext) noexcept { initializeGlExtensions(); + // this is needed with older emulators/API levels on Android + clearGlError(); + // success!! return OpenGLDriverFactory::create(this, sharedContext); @@ -513,7 +525,7 @@ void PlatformEGL::initializeGlExtensions() noexcept { GLint n; glGetIntegerv(GL_NUM_EXTENSIONS, &n); for (GLint i = 0; i < n; ++i) { - const char * const extension = (const char*)glGetStringi(GL_EXTENSIONS, (GLuint)i); + const char * const extension = (const char*) glGetStringi(GL_EXTENSIONS, (GLuint)i); glExtensions.insert(extension); } ext.OES_EGL_image_external_essl3 = glExtensions.has("GL_OES_EGL_image_external_essl3"); diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt index 8cf133bfd5..0b4e7b7253 100644 --- a/libs/utils/CMakeLists.txt +++ b/libs/utils/CMakeLists.txt @@ -23,6 +23,7 @@ set(DIST_HDRS ) set(SRCS + src/api_level.cpp src/ashmem.cpp src/Allocator.cpp src/CallStack.cpp diff --git a/libs/utils/include/utils/api_level.h b/libs/utils/include/utils/api_level.h new file mode 100644 index 0000000000..bf347fd2ff --- /dev/null +++ b/libs/utils/include/utils/api_level.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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 TNT_UTILS_API_H +#define TNT_UTILS_API_H + +#include + +namespace utils { + +/** + * Returns this platform's API level. On Android this function will return + * the API level as defined by the SDK API level version. If a platform does + * not have an API level, this function returns 0. + */ +UTILS_PUBLIC +int api_level(); + +} // namespace utils + +#endif // TNT_UTILS_ARCHITECTURE_H diff --git a/libs/utils/src/api_level.cpp b/libs/utils/src/api_level.cpp new file mode 100644 index 0000000000..0e74770bd4 --- /dev/null +++ b/libs/utils/src/api_level.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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 TNT_UTILS_API_H +#define TNT_UTILS_API_H + +#include + +#ifdef ANDROID +#include +#include +#endif + +namespace utils { + +#ifdef ANDROID + +uint32_t sApiLevel = 0; +std::once_flag sApiLevelOnceFlag; + +int api_level() { + std::call_once(sApiLevelOnceFlag, []() { + char sdkVersion[PROP_VALUE_MAX]; + __system_property_get("ro.build.version.sdk", sdkVersion); + sApiLevel = atoi(sdkVersion); + }); + return sApiLevel; +} + +#else + +int api_level() { + return 0; // API level is only supported on Android currently +} + +#endif + +} // namespace utils + +#endif // TNT_UTILS_ARCHITECTURE_H diff --git a/libs/utils/src/ashmem.cpp b/libs/utils/src/ashmem.cpp index 08e01e5867..ef3595ead6 100644 --- a/libs/utils/src/ashmem.cpp +++ b/libs/utils/src/ashmem.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -85,13 +86,15 @@ static int __ashmem_open() { } int ashmem_create_region(const char *name, size_t size) { - - // dynamically check if we have "ASharedMemory_create" (should be the case since 26 (Oreo)) - using TASharedMemory_create = int(*)(const char *name, size_t size); - TASharedMemory_create pfnASharedMemory_create = - (TASharedMemory_create)dlsym(RTLD_DEFAULT, "ASharedMemory_create"); - if (pfnASharedMemory_create) { - return pfnASharedMemory_create(name, size); + // Fetch the API level to avoid dlsym() on API 19 + if (api_level() >= 26) { + // dynamically check if we have "ASharedMemory_create" (should be the case since 26 (Oreo)) + using TASharedMemory_create = int(*)(const char *name, size_t size); + TASharedMemory_create pfnASharedMemory_create = + (TASharedMemory_create)dlsym(RTLD_DEFAULT, "ASharedMemory_create"); + if (pfnASharedMemory_create) { + return pfnASharedMemory_create(name, size); + } } int ret, save_errno;