diff --git a/android/common/CallbackUtils.cpp b/android/common/CallbackUtils.cpp index 46b9b38344..c5a8affcfa 100644 --- a/android/common/CallbackUtils.cpp +++ b/android/common/CallbackUtils.cpp @@ -14,11 +14,9 @@ * limitations under the License. */ -#include - #include "CallbackUtils.h" -static void initCallbackJni(JNIEnv* env, CallbackJni& callbackUtils) { +void initCallbackJni(JNIEnv* env, CallbackJni& callbackUtils) { #ifdef ANDROID callbackUtils.handlerClass = env->FindClass("android/os/Handler"); callbackUtils.handlerClass = (jclass) env->NewGlobalRef(callbackUtils.handlerClass); diff --git a/android/common/CallbackUtils.h b/android/common/CallbackUtils.h index e0c6f47650..d8290fbd7c 100644 --- a/android/common/CallbackUtils.h +++ b/android/common/CallbackUtils.h @@ -32,6 +32,8 @@ struct CallbackJni { jmethodID execute; }; +void initCallbackJni(JNIEnv* env, CallbackJni& callbackUtils); + struct JniBufferCallback { static JniBufferCallback* make(filament::Engine* engine, JNIEnv* env, jobject handler, jobject callback, AutoBuffer&& buffer); diff --git a/android/filament-android/src/main/cpp/Texture.cpp b/android/filament-android/src/main/cpp/Texture.cpp index 80b272d552..876dcd7044 100644 --- a/android/filament-android/src/main/cpp/Texture.cpp +++ b/android/filament-android/src/main/cpp/Texture.cpp @@ -404,7 +404,36 @@ public: } } + AutoBitmap(JNIEnv* env, jobject bitmap, jobject handler, jobject runnable) noexcept + : mEnv(env) + , mBitmap(env->NewGlobalRef(bitmap)) + , mHandler(env->NewGlobalRef(handler)) + , mCallback(env->NewGlobalRef(runnable)) + { + initCallbackJni(env, mCallbackUtils); + if (mBitmap) { + AndroidBitmap_getInfo(mEnv, mBitmap, &mInfo); + AndroidBitmap_lockPixels(mEnv, mBitmap, &mData); + } + } + ~AutoBitmap() noexcept { + if (mHandler && mCallback) { + #ifdef ANDROID + if (mEnv->IsInstanceOf(mHandler, mCallbackUtils.handlerClass)) { + mEnv->CallBooleanMethod(mHandler, mCallbackUtils.post, mCallback); + } + #endif + if (mEnv->IsInstanceOf(mHandler, mCallbackUtils.executorClass)) { + mEnv->CallVoidMethod(mHandler, mCallbackUtils.execute, mCallback); + } + } + mEnv->DeleteGlobalRef(mHandler); + mEnv->DeleteGlobalRef(mCallback); + #ifdef ANDROID + mEnv->DeleteGlobalRef(mCallbackUtils.handlerClass); + #endif + mEnv->DeleteGlobalRef(mCallbackUtils.executorClass); if (mBitmap) { AndroidBitmap_unlockPixels(mEnv, mBitmap); mEnv->DeleteGlobalRef(mBitmap); @@ -453,11 +482,19 @@ public: return new AutoBitmap(env, bitmap); } + static AutoBitmap* make(Engine* engine, JNIEnv* env, jobject bitmap, + jobject handler, jobject runnable) { + return new AutoBitmap(env, bitmap, handler, runnable); + } + private: JNIEnv* mEnv; void* mData = nullptr; jobject mBitmap = nullptr; + jobject mHandler = nullptr; + jobject mCallback = nullptr; AndroidBitmapInfo mInfo; + CallbackJni mCallbackUtils; }; extern "C" @@ -483,4 +520,27 @@ Java_com_google_android_filament_android_TextureHelper_nSetBitmap(JNIEnv* env, j std::move(desc)); } +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_android_TextureHelper_nSetBitmapWithCallback(JNIEnv* env, jclass, + jlong nativeTexture, jlong nativeEngine, jint level, jint xoffset, jint yoffset, + jint width, jint height, jobject bitmap, jint format, jobject handler, jobject runnable) { + Texture* texture = (Texture*) nativeTexture; + Engine *engine = (Engine *) nativeEngine; + + auto* autoBitmap = AutoBitmap::make(engine, env, bitmap, handler, runnable); + + Texture::PixelBufferDescriptor desc( + autoBitmap->getData(), + autoBitmap->getSizeInBytes(), + autoBitmap->getFormat(format), + autoBitmap->getType(format), + &AutoBitmap::invoke, autoBitmap); + + texture->setImage(*engine, (size_t) level, + (uint32_t) xoffset, (uint32_t) yoffset, + (uint32_t) width, (uint32_t) height, + std::move(desc)); +} + #endif diff --git a/android/filament-android/src/main/java/com/google/android/filament/android/TextureHelper.java b/android/filament-android/src/main/java/com/google/android/filament/android/TextureHelper.java index c9dad31f5a..0e6db619d0 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/android/TextureHelper.java +++ b/android/filament-android/src/main/java/com/google/android/filament/android/TextureHelper.java @@ -43,6 +43,14 @@ public final class TextureHelper { level, 0, 0, texture.getWidth(level), texture.getHeight(level), bitmap); } + public static void setBitmap(@NonNull Engine engine, + @NonNull Texture texture, @IntRange(from = 0) int level, @NonNull Bitmap bitmap, + Object handler, Runnable callback) { + setBitmap(engine, texture, + level, 0, 0, texture.getWidth(level), texture.getHeight(level), bitmap, + handler, callback); + } + public static void setBitmap(@NonNull Engine engine, @NonNull Texture texture, @IntRange(from = 0) int level, @IntRange(from = 0) int xoffset, @IntRange(from = 0) int yoffset, @@ -60,6 +68,23 @@ public final class TextureHelper { bitmap, format); } + public static void setBitmap(@NonNull Engine engine, + @NonNull Texture texture, @IntRange(from = 0) int level, + @IntRange(from = 0) int xoffset, @IntRange(from = 0) int yoffset, + @IntRange(from = 0) int width, @IntRange(from = 0) int height, + @NonNull Bitmap bitmap, Object handler, Runnable callback) { + + int format = toNativeFormat(bitmap.getConfig()); + if (format == BITMAP_CONFIG_RGBA_4444 || format == BITMAP_CONFIG_HARDWARE) { + throw new IllegalArgumentException("Unsupported config: ARGB_4444 or HARDWARE"); + } + + long nativeTexture = texture.getNativeObject(); + long nativeEngine = engine.getNativeObject(); + nSetBitmapWithCallback(nativeTexture, nativeEngine, level, xoffset, yoffset, width, height, + bitmap, format, handler, callback); + } + private static int toNativeFormat(Bitmap.Config config) { switch (config) { case ALPHA_8: return BITMAP_CONFIG_ALPHA_8; @@ -74,4 +99,8 @@ public final class TextureHelper { private static native void nSetBitmap(long nativeTexture, long nativeEngine, int level, int xoffset, int yoffset, int width, int height, Bitmap bitmap, int format); + + private static native void nSetBitmapWithCallback(long nativeTexture, long nativeEngine, + int level, int xoffset, int yoffset, int width, int height, Bitmap bitmap, int format, + Object handler, Runnable callback); } diff --git a/android/samples/sample-page-curl/src/main/java/com/google/android/filament/pagecurl/MainActivity.java b/android/samples/sample-page-curl/src/main/java/com/google/android/filament/pagecurl/MainActivity.java index e9518d66ea..32b426877d 100644 --- a/android/samples/sample-page-curl/src/main/java/com/google/android/filament/pagecurl/MainActivity.java +++ b/android/samples/sample-page-curl/src/main/java/com/google/android/filament/pagecurl/MainActivity.java @@ -31,6 +31,7 @@ import android.view.Surface; import android.view.SurfaceView; import android.view.View; import android.view.Window; +import android.util.Log; import com.google.android.filament.Camera; import com.google.android.filament.Engine; @@ -275,7 +276,13 @@ public class MainActivity extends Activity .levels(0xff) // tells Filament to figure out the number of mip levels .build(engine); - TextureHelper.setBitmap(engine, texture, 0, bitmap); + android.os.Handler handler = new android.os.Handler(); + TextureHelper.setBitmap(engine, texture, 0, bitmap, handler, new Runnable() { + @Override + public void run() { + Log.i("page-curl", "Bitmap is released."); + } + }); texture.generateMipmaps(engine); return texture; }