diff --git a/android/common/CallbackUtils.cpp b/android/common/CallbackUtils.cpp index dd962cda64..2ef64e144e 100644 --- a/android/common/CallbackUtils.cpp +++ b/android/common/CallbackUtils.cpp @@ -95,3 +95,25 @@ void JniImageCallback::invoke(void*, void* user) { JniImageCallback* data = reinterpret_cast(user); delete data; } + +// ----------------------------------------------------------------------------------------------- + +JniCallback* JniCallback::make(JNIEnv* env, jobject handler, jobject callback) { + return new JniCallback(env, handler, callback); +} + +JniCallback::JniCallback(JNIEnv* env, jobject handler, jobject callback) + : mEnv(env) + , mHandler(env->NewGlobalRef(handler)) + , mCallback(env->NewGlobalRef(callback)) { + acquireCallbackJni(env, mCallbackUtils); +} + +JniCallback::~JniCallback() { + releaseCallbackJni(mEnv, mCallbackUtils, mHandler, mCallback); +} + +void JniCallback::invoke(void* user) { + JniCallback* data = reinterpret_cast(user); + delete data; +} diff --git a/android/common/CallbackUtils.h b/android/common/CallbackUtils.h index 0212a741ce..0fa9c793bb 100644 --- a/android/common/CallbackUtils.h +++ b/android/common/CallbackUtils.h @@ -62,8 +62,8 @@ struct JniImageCallback { private: JniImageCallback(JNIEnv* env, jobject handler, jobject runnable, long image); - JniImageCallback(JniBufferCallback const &) = delete; - JniImageCallback(JniBufferCallback&&) = delete; + JniImageCallback(JniImageCallback const &) = delete; + JniImageCallback(JniImageCallback&&) = delete; ~JniImageCallback(); JNIEnv* mEnv; @@ -72,3 +72,20 @@ private: long mImage; CallbackJni mCallbackUtils; }; + +struct JniCallback { + static JniCallback* make(JNIEnv* env, jobject handler, jobject runnable); + + static void invoke(void* user); + +private: + JniCallback(JNIEnv* env, jobject handler, jobject runnable); + JniCallback(JniCallback const &) = delete; + JniCallback(JniCallback&&) = delete; + ~JniCallback(); + + JNIEnv* mEnv; + jobject mHandler; + jobject mCallback; + CallbackJni mCallbackUtils; +}; diff --git a/android/filament-android/CMakeLists.txt b/android/filament-android/CMakeLists.txt index b51fc7a124..31666830a5 100644 --- a/android/filament-android/CMakeLists.txt +++ b/android/filament-android/CMakeLists.txt @@ -70,6 +70,7 @@ add_library(filament-jni SHARED src/main/cpp/SkyBox.cpp src/main/cpp/Stream.cpp src/main/cpp/SurfaceOrientation.cpp + src/main/cpp/SwapChain.cpp src/main/cpp/Texture.cpp src/main/cpp/TextureSampler.cpp src/main/cpp/TransformManager.cpp diff --git a/android/filament-android/src/main/cpp/SwapChain.cpp b/android/filament-android/src/main/cpp/SwapChain.cpp new file mode 100644 index 0000000000..5528c00411 --- /dev/null +++ b/android/filament-android/src/main/cpp/SwapChain.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 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. + */ + +#include + +#include + +#include "common/CallbackUtils.h" + +using namespace filament; + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_SwapChain_nSetFrameCompletedCallback(JNIEnv* env, jclass, + jlong nativeSwapChain, jobject handler, jobject runnable) { + SwapChain* swapChain = (SwapChain*) nativeSwapChain; + auto *callback = JniCallback::make(env, handler, runnable); + swapChain->setFrameCompletedCallback(&JniCallback::invoke, callback); +} diff --git a/android/filament-android/src/main/java/com/google/android/filament/SwapChain.java b/android/filament-android/src/main/java/com/google/android/filament/SwapChain.java index 96821515fc..391f1f6e1d 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/SwapChain.java +++ b/android/filament-android/src/main/java/com/google/android/filament/SwapChain.java @@ -104,6 +104,31 @@ public class SwapChain { return mSurface; } + /** + * FrameCompletedCallback is a callback function that notifies an application when a frame's + * contents have completed rendering on the GPU. + * + *

+ * Use setFrameCompletedCallback to set a callback on an individual SwapChain. Each time a frame + * completes GPU rendering, the callback will be called. + *

+ * + *

+ * The FrameCompletedCallback is guaranteed to be called on the main Filament thread. + *

+ * + *

+ * Warning: Only Filament's Metal backend supports frame callbacks. Other backends ignore the + * callback (which will never be called) and proceed normally. + *

+ * + * @param handler A {@link java.util.concurrent.Executor Executor}. + * @param callback The Runnable callback to invoke. + */ + public void setFrameCompletedCallback(@NonNull Object handler, @NonNull Runnable callback) { + nSetFrameCompletedCallback(getNativeObject(), handler, callback); + } + public long getNativeObject() { if (mNativeObject == 0) { throw new IllegalStateException("Calling method on destroyed SwapChain"); @@ -114,4 +139,6 @@ public class SwapChain { void clearNativeObject() { mNativeObject = 0; } + + private static native void nSetFrameCompletedCallback(long nativeSwapChain, Object handler, Runnable callback); }