From c79d695ffb56cc2f2348af385b276cd92f0ada2c Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 13 Oct 2025 12:18:28 -0700 Subject: [PATCH] fix wasm build. (#9312) The new AsyncJobQueue can't work with wasm, which doesn't support threads. --- filament/src/FrameInfo.cpp | 6 ++++++ libs/utils/include/utils/AsyncJobQueue.h | 4 ++++ libs/utils/src/AsyncJobQueue.cpp | 17 +++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/filament/src/FrameInfo.cpp b/filament/src/FrameInfo.cpp index ca1c5408e0..49ff5d4a80 100644 --- a/filament/src/FrameInfo.cpp +++ b/filament/src/FrameInfo.cpp @@ -173,6 +173,12 @@ void FrameInfoManager::endFrame(DriverApi& driver) noexcept { // backend frame end-time front.backendEndFrame = std::chrono::steady_clock::now(); + if (UTILS_UNLIKELY(!jobQueue.isValid())) { + front.gpuFrameComplete = {}; + front.ready.store(true, std::memory_order_release); + return; + } + // now launch a job that'll wait for the gpu to complete jobQueue.push([&driver, &front] { FenceStatus const status = driver.fenceWait(front.fence, FENCE_WAIT_FOR_EVER); diff --git a/libs/utils/include/utils/AsyncJobQueue.h b/libs/utils/include/utils/AsyncJobQueue.h index 3cf9064362..cb5f498c92 100644 --- a/libs/utils/include/utils/AsyncJobQueue.h +++ b/libs/utils/include/utils/AsyncJobQueue.h @@ -48,13 +48,17 @@ public: // adds a job to the queue. no-op if drainAndExit() was called. void push(Job&& job); + bool isValid() const noexcept; + private: +#if !defined(__EMSCRIPTEN__) using Container = std::vector; std::thread mThread; Mutex mLock; // NOLINT(*-include-cleaner) Condition mCondition; // NOLINT(*-include-cleaner) Container mQueue; bool mExitRequested = false; +#endif }; } // namespace utils diff --git a/libs/utils/src/AsyncJobQueue.cpp b/libs/utils/src/AsyncJobQueue.cpp index 3b00daed66..3057eaec9b 100644 --- a/libs/utils/src/AsyncJobQueue.cpp +++ b/libs/utils/src/AsyncJobQueue.cpp @@ -26,6 +26,7 @@ namespace utils { AsyncJobQueue::AsyncJobQueue(const char* name, Priority priority) { +#if !defined(__EMSCRIPTEN__) mQueue.reserve(2); mThread = std::thread([this, name, priority]() { JobSystem::setThreadName(name); @@ -50,13 +51,17 @@ AsyncJobQueue::AsyncJobQueue(const char* name, Priority priority) { } } while (!exitRequested); }); +#endif } AsyncJobQueue::~AsyncJobQueue() noexcept { +#if !defined(__EMSCRIPTEN__) assert_invariant(mQueue.empty()); +#endif } void AsyncJobQueue::push(Job&& job) { +#if !defined(__EMSCRIPTEN__) std::unique_lock lock(mLock); if (UTILS_UNLIKELY(mExitRequested)) { LOG(WARNING) << "AsyncJobQueue::push() called after drainAndExit()"; @@ -67,9 +72,20 @@ void AsyncJobQueue::push(Job&& job) { lock.unlock(); mCondition.notify_one(); } +#endif } +bool AsyncJobQueue::isValid() const noexcept { +#if !defined(__EMSCRIPTEN__) + return mThread.joinable(); +#else + return false; +#endif +} + + void AsyncJobQueue::drainAndExit() { +#if !defined(__EMSCRIPTEN__) std::unique_lock lock(mLock); // we request the service thread to exit, but we're guaranteed that it'll only exit // after all current callbacks are processed. In addition, once mExitRequested is set, @@ -80,6 +96,7 @@ void AsyncJobQueue::drainAndExit() { if (mThread.joinable()) { mThread.join(); } +#endif } } // namespace utils