diff --git a/android/filament-android/src/main/cpp/Engine.cpp b/android/filament-android/src/main/cpp/Engine.cpp
index 569be2475b..a5638bbbe4 100644
--- a/android/filament-android/src/main/cpp/Engine.cpp
+++ b/android/filament-android/src/main/cpp/Engine.cpp
@@ -252,6 +252,13 @@ Java_com_google_android_filament_Engine_nDestroyEntity(JNIEnv*, jclass,
engine->destroy(entity);
}
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_android_filament_Engine_nFlushAndWait(JNIEnv *env, jclass clazz,
+ jlong nativeEngine) {
+ Engine* engine = (Engine*) nativeEngine;
+ engine->flushAndWait();
+}
+
// Managers...
extern "C" JNIEXPORT jlong JNICALL
diff --git a/android/filament-android/src/main/java/com/google/android/filament/Engine.java b/android/filament-android/src/main/java/com/google/android/filament/Engine.java
index 7f6d1d3c9f..4c4acd6510 100644
--- a/android/filament-android/src/main/java/com/google/android/filament/Engine.java
+++ b/android/filament-android/src/main/java/com/google/android/filament/Engine.java
@@ -582,9 +582,14 @@ public class Engine {
* Kicks the hardware thread (e.g.: the OpenGL, Vulkan or Metal thread) and blocks until
* all commands to this point are executed. Note that this doesn't guarantee that the
* hardware is actually finished.
+ *
+ *
This is typically used right after destroying the SwapChain,
+ * in cases where a guarantee about the SwapChain destruction is needed in a timely fashion,
+ * such as when responding to Android's
+ * {@link android.view.SurfaceHolder.Callback#surfaceDestroyed surfaceDestroyed}.
*/
public void flushAndWait() {
- Fence.waitAndDestroy(createFence(), Fence.Mode.FLUSH);
+ nFlushAndWait(getNativeObject());
}
@UsedByReflection("TextureHelper.java")
@@ -626,6 +631,7 @@ public class Engine {
private static native void nDestroyTexture(long nativeEngine, long nativeTexture);
private static native void nDestroyRenderTarget(long nativeEngine, long nativeTarget);
private static native void nDestroyEntity(long nativeEngine, int entity);
+ private static native void nFlushAndWait(long nativeEngine);
private static native long nGetTransformManager(long nativeEngine);
private static native long nGetLightManager(long nativeEngine);
private static native long nGetRenderableManager(long nativeEngine);
diff --git a/android/filament-android/src/main/java/com/google/android/filament/android/UiHelper.java b/android/filament-android/src/main/java/com/google/android/filament/android/UiHelper.java
index be2ea29a94..dfc25d739b 100644
--- a/android/filament-android/src/main/java/com/google/android/filament/android/UiHelper.java
+++ b/android/filament-android/src/main/java/com/google/android/filament/android/UiHelper.java
@@ -99,10 +99,6 @@ import com.google.android.filament.SwapChain;
* // Always detach the surface before destroying the engine
* mUiHelper.detach();
*
- * // This ensures that all the commands we've sent to Filament have
- * // been processed before we attempt to destroy anything
- * Fence.waitAndDestroy(mEngine.createFence(Fence.Type.SOFT), Fence.Mode.FLUSH);
- *
* mEngine.destroy();
* }
*
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 9d8e9bb641..e3065314ad 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
@@ -434,10 +434,6 @@ class MainActivity : Activity() {
// Always detach the surface before destroying the engine
uiHelper.detach()
- // This ensures that all the commands we've sent to Filament have
- // been processed before we attempt to destroy anything
- engine.flushAndWait()
-
assetLoader.destroyAsset(filamentAsset)
assetLoader.destroy()
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 f19c1abbac..71850afe8f 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
@@ -261,10 +261,6 @@ class MainActivity : Activity() {
// Always detach the surface before destroying the engine
uiHelper.detach()
- // This ensures that all the commands we've sent to Filament have
- // been processed before we attempt to destroy anything
- engine.flushAndWait()
-
// Cleanup all resources
engine.destroyEntity(renderable)
engine.destroyRenderer(renderer)
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 0d9f94416a..a4c3502bfd 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
@@ -238,10 +238,6 @@ class MainActivity : Activity() {
// Always detach the surface before destroying the engine
uiHelper.detach()
- // This ensures that all the commands we've sent to Filament have
- // been processed before we attempt to destroy anything
- engine.flushAndWait()
-
// Cleanup all resources
destroyMesh(engine, mesh)
destroyIbl(engine, ibl)
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 defa60a5f1..e470c75abf 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
@@ -346,10 +346,6 @@ class MainActivity : Activity() {
// Always detach the surface before destroying the engine
uiHelper.detach()
- // This ensures that all the commands we've sent to Filament have
- // been processed before we attempt to destroy anything
- engine.flushAndWait()
-
// Cleanup all resources
engine.destroyEntity(light)
engine.destroyEntity(renderable)
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 5c8b96be41..f015f2aa9c 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
@@ -274,10 +274,6 @@ class MainActivity : Activity() {
// Always detach the surface before destroying the engine
uiHelper.detach()
- // This ensures that all the commands we've sent to Filament have
- // been processed before we attempt to destroy anything
- engine.flushAndWait()
-
// Cleanup all resources
destroyMesh(engine, mesh)
destroyIbl(engine, ibl)
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 550d399d03..bd5cea5b79 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
@@ -261,10 +261,6 @@ class MainActivity : Activity() {
// Always detach the surface before destroying the engine
uiHelper.detach()
- // This ensures that all the commands we've sent to Filament have
- // been processed before we attempt to destroy anything
- engine.flushAndWait()
-
// Cleanup all resources
engine.destroyEntity(renderable)
engine.destroyRenderer(renderer)
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 161a495eb9..5e7d242970 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
@@ -257,10 +257,6 @@ class MainActivity : Activity() {
// Always detach the surface before destroying the engine
uiHelper.detach()
- // This ensures that all the commands we've sent to Filament have
- // been processed before we attempt to destroy anything
- engine.flushAndWait()
-
// Cleanup all resources
destroyMesh(engine, mesh)
destroyIbl(engine, ibl)
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 7d81786a00..cd5f27e620 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
@@ -279,10 +279,6 @@ class MainActivity : Activity() {
// Always detach the surface before destroying the engine
uiHelper.detach()
- // This ensures that all the commands we've sent to Filament have
- // been processed before we attempt to destroy anything
- engine.flushAndWait()
-
// Cleanup all resources
engine.destroyEntity(renderable)
engine.destroyRenderer(renderer)
diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h
index 43286d540c..9bccff2bd4 100644
--- a/filament/include/filament/Engine.h
+++ b/filament/include/filament/Engine.h
@@ -339,6 +339,18 @@ public:
void destroy(const View* p); //!< Destroys a View object.
void destroy(utils::Entity e); //!< Destroys all filament-known components from this entity
+ /**
+ * Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) and blocks until
+ * all commands to this point are executed. Note that this doesn't guarantee that the
+ * hardware is actually finished.
+ *
+ * This is typically used right after destroying the SwapChain,
+ * in cases where a guarantee about the SwapChain destruction is needed in a
+ * timely fashion, such as when responding to Android's
+ * android.view.SurfaceHolder.Callback.surfaceDestroyed
+ */
+ void flushAndWait();
+
/**
* Returns the default Material.
*
diff --git a/filament/src/Engine.cpp b/filament/src/Engine.cpp
index 1cc2d99329..39e87a739f 100644
--- a/filament/src/Engine.cpp
+++ b/filament/src/Engine.cpp
@@ -347,6 +347,10 @@ void FEngine::flush() {
flushCommandBuffer(mCommandBufferQueue);
}
+void FEngine::flushAndWait() {
+ FFence::waitAndDestroy(FEngine::createFence(FFence::Type::SOFT), FFence::Mode::FLUSH);
+}
+
// -----------------------------------------------------------------------------------------------
// Render thread / command queue
// -----------------------------------------------------------------------------------------------
@@ -885,6 +889,10 @@ void Engine::destroy(Entity e) {
upcast(this)->destroy(e);
}
+void Engine::flushAndWait() {
+ upcast(this)->flushAndWait();
+}
+
RenderableManager& Engine::getRenderableManager() noexcept {
return upcast(this)->getRenderableManager();
}
diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h
index e4df728e18..7acafea6d1 100644
--- a/filament/src/details/Engine.h
+++ b/filament/src/details/Engine.h
@@ -259,6 +259,8 @@ public:
void destroy(const FView* p);
void destroy(utils::Entity e);
+ void flushAndWait();
+
// flush the current buffer
void flush();
diff --git a/samples/gltf_baker.cpp b/samples/gltf_baker.cpp
index 6e319d178f..f96818b03c 100644
--- a/samples/gltf_baker.cpp
+++ b/samples/gltf_baker.cpp
@@ -936,8 +936,6 @@ int main(int argc, char** argv) {
AssetLoader::destroy(&app.loader);
std::cout << "Destroying NameComponentManager..." << std::endl;
delete app.names;
-
- Fence::waitAndDestroy(engine->createFence());
};
auto animate = [&app](Engine* engine, View* view, double now) {
diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp
index 4153a4b884..b7f0f8dedd 100644
--- a/samples/gltf_viewer.cpp
+++ b/samples/gltf_viewer.cpp
@@ -243,7 +243,6 @@ int main(int argc, char** argv) {
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
- Fence::waitAndDestroy(engine->createFence());
delete app.viewer;
app.loader->destroyAsset(app.asset);
app.materials->destroyMaterials();
diff --git a/samples/lucy_bloom.cpp b/samples/lucy_bloom.cpp
index 1c3a735f60..912fe76643 100644
--- a/samples/lucy_bloom.cpp
+++ b/samples/lucy_bloom.cpp
@@ -368,7 +368,6 @@ static void cleanup(LucyApp& app, Engine* engine) {
engine->destroy(app.finalCamera);
- Fence::waitAndDestroy(engine->createFence());
app.loader->destroyAsset(app.asset);
app.materials->destroyMaterials();
delete app.materials;
diff --git a/samples/point_sprites.cpp b/samples/point_sprites.cpp
index a2803c214e..28ebd557aa 100644
--- a/samples/point_sprites.cpp
+++ b/samples/point_sprites.cpp
@@ -154,7 +154,6 @@ void setup(App& app, Engine* engine, View* view, Scene* scene) {
};
void cleanup(App& app, Engine* engine) {
- Fence::waitAndDestroy(engine->createFence());
engine->destroy(app.renderable);
engine->destroy(app.matInstance);
engine->destroy(app.mat);
diff --git a/samples/suzanne.cpp b/samples/suzanne.cpp
index 75f7447dce..aa1d3251a5 100644
--- a/samples/suzanne.cpp
+++ b/samples/suzanne.cpp
@@ -125,7 +125,6 @@ int main(int argc, char** argv) {
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
- Fence::waitAndDestroy(engine->createFence());
engine->destroy(app.materialInstance);
engine->destroy(app.mesh.renderable);
engine->destroy(app.material);
diff --git a/samples/vk_animation.cpp b/samples/vk_animation.cpp
index 2e2b9f60e3..5a617ad3ab 100644
--- a/samples/vk_animation.cpp
+++ b/samples/vk_animation.cpp
@@ -85,7 +85,6 @@ int main(int argc, char** argv) {
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
- Fence::waitAndDestroy(engine->createFence());
engine->destroy(app.renderable);
engine->destroy(app.mat);
engine->destroy(app.vb);
diff --git a/samples/vk_depthtesting.cpp b/samples/vk_depthtesting.cpp
index 33ea70394e..16c84e2840 100644
--- a/samples/vk_depthtesting.cpp
+++ b/samples/vk_depthtesting.cpp
@@ -112,7 +112,6 @@ int main(int argc, char** argv) {
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
- Fence::waitAndDestroy(engine->createFence());
engine->destroy(app.whiteTriangle);
engine->destroy(app.colorTriangle);
engine->destroy(app.mat);
diff --git a/samples/vk_hellopbr.cpp b/samples/vk_hellopbr.cpp
index 4fbaede54a..0ce4f4eff9 100644
--- a/samples/vk_hellopbr.cpp
+++ b/samples/vk_hellopbr.cpp
@@ -85,7 +85,6 @@ int main(int argc, char** argv) {
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
- Fence::waitAndDestroy(engine->createFence());
engine->destroy(app.light);
engine->destroy(app.materialInstance);
engine->destroy(app.mesh.renderable);
diff --git a/samples/vk_hellotriangle.cpp b/samples/vk_hellotriangle.cpp
index 846cebb992..a839f34ef2 100644
--- a/samples/vk_hellotriangle.cpp
+++ b/samples/vk_hellotriangle.cpp
@@ -100,7 +100,6 @@ int main(int argc, char** argv) {
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
- Fence::waitAndDestroy(engine->createFence());
engine->destroy(app.renderable);
engine->destroy(app.mat);
engine->destroy(app.vb);
diff --git a/samples/vk_shadowtest.cpp b/samples/vk_shadowtest.cpp
index f3d238bc02..da6d66dcab 100644
--- a/samples/vk_shadowtest.cpp
+++ b/samples/vk_shadowtest.cpp
@@ -105,7 +105,6 @@ int main(int argc, char** argv) {
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
- Fence::waitAndDestroy(engine->createFence());
engine->destroy(app.plane.renderable);
engine->destroy(app.plane.mat);
engine->destroy(app.plane.vb);
diff --git a/samples/vk_texturedquad.cpp b/samples/vk_texturedquad.cpp
index c663cb07f4..f777ec6466 100644
--- a/samples/vk_texturedquad.cpp
+++ b/samples/vk_texturedquad.cpp
@@ -144,7 +144,6 @@ int main(int argc, char** argv) {
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
- Fence::waitAndDestroy(engine->createFence());
engine->destroy(app.renderable);
engine->destroy(app.matInstance);
engine->destroy(app.mat);
diff --git a/samples/vk_vbotest.cpp b/samples/vk_vbotest.cpp
index d69631bffa..c6fb5d00bd 100644
--- a/samples/vk_vbotest.cpp
+++ b/samples/vk_vbotest.cpp
@@ -81,7 +81,6 @@ int main(int argc, char** argv) {
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
- Fence::waitAndDestroy(engine->createFence());
engine->destroy(app.renderable);
engine->destroy(app.mat);
engine->destroy(app.vb);
diff --git a/samples/vk_viewtest.cpp b/samples/vk_viewtest.cpp
index b7e3b133ed..0ba3895c27 100644
--- a/samples/vk_viewtest.cpp
+++ b/samples/vk_viewtest.cpp
@@ -64,7 +64,6 @@ int main(int argc, char** argv) {
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
- Fence::waitAndDestroy(engine->createFence());
engine->destroy(app.renderable);
engine->destroy(app.vb);
engine->destroy(app.ib);