diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 4a1a9c7fa7..77a7acc5f4 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -7,3 +7,5 @@ for next branch cut* header. appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut + +- engine: Add experimental APIs `Engine::builder::paused()` and `Engine::setPaused()` diff --git a/android/filament-android/src/main/cpp/Engine.cpp b/android/filament-android/src/main/cpp/Engine.cpp index 80409702c3..c9fa78dccd 100644 --- a/android/filament-android/src/main/cpp/Engine.cpp +++ b/android/filament-android/src/main/cpp/Engine.cpp @@ -391,6 +391,13 @@ Java_com_google_android_filament_Engine_nFlush(JNIEnv*, jclass, engine->flush(); } +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_Engine_nSetPaused(JNIEnv*, jclass, + jlong nativeEngine, jboolean paused) { + Engine* engine = (Engine*) nativeEngine; + engine->setPaused(paused); +} + // Managers... extern "C" JNIEXPORT jlong JNICALL @@ -518,6 +525,12 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu builder->sharedContext((void*) sharedContext); } +extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderPaused( + JNIEnv*, jclass, jlong nativeBuilder, jboolean paused) { + Engine::Builder* builder = (Engine::Builder*) nativeBuilder; + builder->paused((bool) paused); +} + extern "C" JNIEXPORT jlong JNICALL Java_com_google_android_filament_Engine_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder) { Engine::Builder* builder = (Engine::Builder*) nativeBuilder; 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 aee4c2b34a..0a4c213576 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 @@ -239,6 +239,18 @@ public class Engine { return this; } + /** + * Sets the initial paused state of the rendering thread. + * + * @param paused Whether to start the rendering thread paused. + * @return A reference to this Builder for chaining calls. + * @warning Experimental. + */ + public Builder paused(boolean paused) { + nSetBuilderPaused(mNativeBuilder, paused); + return this; + } + /** * Creates an instance of Engine * @@ -1189,6 +1201,13 @@ public class Engine { nFlush(getNativeObject()); } + /** + * Pause or resume the rendering thread. + * @warning Experimental. + */ + public void setPaused(boolean paused) { + nSetPaused(getNativeObject(), paused); + } @UsedByReflection("TextureHelper.java") public long getNativeObject() { @@ -1263,6 +1282,7 @@ public class Engine { private static native void nDestroyEntity(long nativeEngine, int entity); private static native void nFlushAndWait(long nativeEngine); private static native void nFlush(long nativeEngine); + private static native void nSetPaused(long nativeEngine, boolean paused); private static native long nGetTransformManager(long nativeEngine); private static native long nGetLightManager(long nativeEngine); private static native long nGetRenderableManager(long nativeEngine); @@ -1286,5 +1306,6 @@ public class Engine { long resourceAllocatorCacheSizeMB, long resourceAllocatorCacheMaxAge); private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal); private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext); + private static native void nSetBuilderPaused(long nativeBuilder, boolean paused); private static native long nBuilderBuild(long nativeBuilder); } diff --git a/filament/backend/include/private/backend/CommandBufferQueue.h b/filament/backend/include/private/backend/CommandBufferQueue.h index 2812245238..92bf7e1488 100644 --- a/filament/backend/include/private/backend/CommandBufferQueue.h +++ b/filament/backend/include/private/backend/CommandBufferQueue.h @@ -50,12 +50,13 @@ class CommandBufferQueue { size_t mFreeSpace = 0; size_t mHighWatermark = 0; uint32_t mExitRequested = 0; + bool mPaused = false; static constexpr uint32_t EXIT_REQUESTED = 0x31415926; public: // requiredSize: guaranteed available space after flush() - CommandBufferQueue(size_t requiredSize, size_t bufferSize); + CommandBufferQueue(size_t requiredSize, size_t bufferSize, bool paused); ~CommandBufferQueue(); CircularBuffer& getCircularBuffer() noexcept { return mCircularBuffer; } @@ -80,6 +81,9 @@ public: // returns from waitForCommands() immediately. void requestExit(); + // suspend or unsuspend the queue. + void setPaused(bool paused); + bool isExitRequested() const; }; diff --git a/filament/backend/src/CommandBufferQueue.cpp b/filament/backend/src/CommandBufferQueue.cpp index e3e5de045c..9de07ed0e2 100644 --- a/filament/backend/src/CommandBufferQueue.cpp +++ b/filament/backend/src/CommandBufferQueue.cpp @@ -39,10 +39,11 @@ using namespace utils; namespace filament::backend { -CommandBufferQueue::CommandBufferQueue(size_t requiredSize, size_t bufferSize) +CommandBufferQueue::CommandBufferQueue(size_t requiredSize, size_t bufferSize, bool paused) : mRequiredSize((requiredSize + (CircularBuffer::getBlockSize() - 1u)) & ~(CircularBuffer::getBlockSize() -1u)), mCircularBuffer(bufferSize), - mFreeSpace(mCircularBuffer.size()) { + mFreeSpace(mCircularBuffer.size()), + mPaused(paused) { assert_invariant(mCircularBuffer.size() > requiredSize); } @@ -56,6 +57,15 @@ void CommandBufferQueue::requestExit() { mCondition.notify_one(); } +void CommandBufferQueue::setPaused(bool paused) { + if (paused) { + mPaused = true; + } else { + mPaused = false; + mCondition.notify_one(); + } +} + bool CommandBufferQueue::isExitRequested() const { std::lock_guard const lock(mLock); ASSERT_PRECONDITION( mExitRequested == 0 || mExitRequested == EXIT_REQUESTED, @@ -127,7 +137,7 @@ std::vector CommandBufferQueue::waitForCommands() con return std::move(mCommandBuffersToExecute); } std::unique_lock lock(mLock); - while (mCommandBuffersToExecute.empty() && !mExitRequested) { + while ((mCommandBuffersToExecute.empty() || mPaused) && !mExitRequested) { mCondition.wait(lock); } diff --git a/filament/backend/test/BackendTest.cpp b/filament/backend/test/BackendTest.cpp index 0730236344..5bb694c974 100644 --- a/filament/backend/test/BackendTest.cpp +++ b/filament/backend/test/BackendTest.cpp @@ -51,7 +51,7 @@ void BackendTest::init(Backend backend, bool isMobilePlatform) { } BackendTest::BackendTest() : commandBufferQueue(CONFIG_MIN_COMMAND_BUFFERS_SIZE, - CONFIG_COMMAND_BUFFERS_SIZE) { + CONFIG_COMMAND_BUFFERS_SIZE, /*mPaused=*/false) { initializeDriver(); } diff --git a/filament/backend/test/ComputeTest.cpp b/filament/backend/test/ComputeTest.cpp index 6ec640dbed..5808c3b182 100644 --- a/filament/backend/test/ComputeTest.cpp +++ b/filament/backend/test/ComputeTest.cpp @@ -46,7 +46,8 @@ void ComputeTest::init(Backend backend) { } ComputeTest::ComputeTest() - : commandBufferQueue(CONFIG_MIN_COMMAND_BUFFERS_SIZE, CONFIG_COMMAND_BUFFERS_SIZE) { + : commandBufferQueue(CONFIG_MIN_COMMAND_BUFFERS_SIZE, CONFIG_COMMAND_BUFFERS_SIZE, + /*paused=*/false) { } ComputeTest::~ComputeTest() = default; diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h index 04d71259b7..a702b3de26 100644 --- a/filament/include/filament/Engine.h +++ b/filament/include/filament/Engine.h @@ -402,6 +402,13 @@ public: */ Builder& featureLevel(FeatureLevel featureLevel) noexcept; + /** + * @param paused Whether to start the rendering thread paused. + * @return A reference to this Builder for chaining calls. + * @warning Experimental. + */ + Builder& paused(bool paused) noexcept; + #if UTILS_HAS_THREADING /** * Creates the filament Engine asynchronously. @@ -827,6 +834,12 @@ public: */ void flush(); + /** + * Pause or resume rendering thread. + * @warning Experimental. + */ + void setPaused(bool paused); + /** * Drains the user callback message queue and immediately execute all pending callbacks. * diff --git a/filament/src/Engine.cpp b/filament/src/Engine.cpp index 380b7e55ad..ffb85ae70a 100644 --- a/filament/src/Engine.cpp +++ b/filament/src/Engine.cpp @@ -295,6 +295,11 @@ utils::JobSystem& Engine::getJobSystem() noexcept { return downcast(this)->getJobSystem(); } +void Engine::setPaused(bool paused) { + ASSERT_PRECONDITION(UTILS_HAS_THREADING, "Pause is meant for multi-threaded platforms."); + downcast(this)->setPaused(paused); +} + DebugRegistry& Engine::getDebugRegistry() noexcept { return downcast(this)->getDebugRegistry(); } diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index 97c22b90c1..c0d3f802fb 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -69,6 +69,7 @@ struct Engine::BuilderDetails { Engine::Config mConfig; FeatureLevel mFeatureLevel = FeatureLevel::FEATURE_LEVEL_1; void* mSharedContext = nullptr; + bool mPaused = false; static Config validateConfig(const Config* pConfig) noexcept; }; @@ -200,7 +201,8 @@ FEngine::FEngine(Engine::Builder const& builder) : mCameraManager(*this), mCommandBufferQueue( builder->mConfig.minCommandBufferSizeMB * MiB, - builder->mConfig.commandBufferSizeMB * MiB), + builder->mConfig.commandBufferSizeMB * MiB, + builder->mPaused), mPerRenderPassArena( "FEngine::mPerRenderPassAllocator", builder->mConfig.perRenderPassArenaSizeMB * MiB), @@ -1194,6 +1196,10 @@ void FEngine::destroy(FEngine* engine) { } } +void FEngine::setPaused(bool paused) { + mCommandBufferQueue.setPaused(paused); +} + Engine::FeatureLevel FEngine::getSupportedFeatureLevel() const noexcept { FEngine::DriverApi& driver = const_cast(this)->getDriverApi(); return driver.getFeatureLevel(); @@ -1247,6 +1253,11 @@ Engine::Builder& Engine::Builder::sharedContext(void* sharedContext) noexcept { return *this; } +Engine::Builder& Engine::Builder::paused(bool paused) noexcept { + mImpl->mPaused = paused; + return *this; +} + #if UTILS_HAS_THREADING void Engine::Builder::build(Invocable&& callback) const { diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index 002e4f25f9..ead937e644 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -340,6 +340,8 @@ public: void destroy(utils::Entity e); + void setPaused(bool paused); + void flushAndWait(); // flush the current buffer