diff --git a/filament/backend/include/backend/platforms/PlatformEGLAndroid.h b/filament/backend/include/backend/platforms/PlatformEGLAndroid.h index 3a8b412e0b..607d6cfb39 100644 --- a/filament/backend/include/backend/platforms/PlatformEGLAndroid.h +++ b/filament/backend/include/backend/platforms/PlatformEGLAndroid.h @@ -203,7 +203,10 @@ private: using clock = std::chrono::high_resolution_clock; clock::time_point mStartTimeOfActualWork; + int32_t (*ANativeWindow_setProducerThrottlingEnabled)(ANativeWindow* window, bool enabled) = nullptr; + int32_t (*ANativeWindow_isProducerThrottlingEnabled)(ANativeWindow* window, bool* outEnabled) = nullptr; bool mAssertNativeWindowIsValid = false; + bool mHasProducerThrottlingControl = false; }; } // namespace filament::backend diff --git a/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp b/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp index 5fc9b68299..77a201c969 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp @@ -32,6 +32,7 @@ #include "ExternalStreamManagerAndroid.h" #include +#include #include #include @@ -57,6 +58,7 @@ #include #include +#include #include #include #include @@ -114,9 +116,30 @@ PlatformEGLAndroid::PlatformEGLAndroid() noexcept if (mOSVersion < 0) { mOSVersion = __ANDROID_API_FUTURE__; } + + // TODO: remove this code one the new NDK is available + void* nativeWindowLibHandle = dlopen("libnativewindow.so", RTLD_LOCAL | RTLD_NOW); + if (nativeWindowLibHandle) { + ANativeWindow_setProducerThrottlingEnabled = + (int32_t(*)(ANativeWindow*, bool))dlsym(nativeWindowLibHandle, + "ANativeWindow_setProducerThrottlingEnabled"); + + ANativeWindow_isProducerThrottlingEnabled = + (int32_t(*)(ANativeWindow*, bool*))dlsym(nativeWindowLibHandle, + "ANativeWindow_isProducerThrottlingEnabled"); + + if (ANativeWindow_setProducerThrottlingEnabled && + ANativeWindow_isProducerThrottlingEnabled) { + mHasProducerThrottlingControl = true; + LOG(INFO) << "Producer Throttling API available"; + } + } } PlatformEGLAndroid::~PlatformEGLAndroid() noexcept { + // note: we don't need to dlclose() mNativeWindowLib here, because the library will be cleaned + // when the process ends and dlopen() are ref-counted. dlclose() NDK documentation documents + // not to call dlclose(). } void PlatformEGLAndroid::terminate() noexcept { @@ -649,6 +672,16 @@ AcquiredImage PlatformEGLAndroid::transformAcquiredImage(AcquiredImage const sou PlatformEGLAndroid::SwapChainEGLAndroid::SwapChainEGLAndroid(PlatformEGLAndroid const& platform, void* nativeWindow, uint64_t const flags) : SwapChainEGL(platform, nativeWindow, flags) { + + if (nativeWindow && platform.mHasProducerThrottlingControl) { + // Disable Producer Throttling when supported. This allows eglSwapBuffers() to not stall + int32_t const result = platform.ANativeWindow_setProducerThrottlingEnabled( + EGLNativeWindowType(nativeWindow), false); + if (UTILS_UNLIKELY(result < 0)) { + LOG(WARNING) << "ANativeWindow_setProducerThrottlingEnabled(false) failed: " << result; + } + } + if (UTILS_LIKELY(platform.ext.egl.ANDROID_get_frame_timestamps)) { if (sur != EGL_NO_SURFACE) { // we ignore the result, it doesn't matter much if it fails