Compare commits

...

1 Commits

Author SHA1 Message Date
Sungun Park
7017bde04d Optimize thread variables in ServiceThread
Wraps thread-related member variables in preprocessor checks to ensure
they are excluded when multithreading is not supported. Previously,
these variables were declared unconditionally, leading to unnecessary
memory usage for platforms that don't support multithreading.
2026-01-20 07:42:15 -08:00
3 changed files with 40 additions and 33 deletions

View File

@@ -51,39 +51,39 @@ namespace filament::backend {
DriverBase::DriverBase(const Platform::DriverConfig& driverConfig) noexcept DriverBase::DriverBase(const Platform::DriverConfig& driverConfig) noexcept
: mDriverConfig(driverConfig) { : mDriverConfig(driverConfig) {
if constexpr (UTILS_HAS_THREADING) { #if UTILS_HAS_THREADING
// This thread services user callbacks // This thread services user callbacks
mServiceThread = std::thread([this]() { mServiceThread = std::thread([this]() {
JobSystem::setThreadName("ServiceThread"); JobSystem::setThreadName("ServiceThread");
do { do {
auto& serviceThreadCondition = mServiceThreadCondition; auto& serviceThreadCondition = mServiceThreadCondition;
auto& serviceThreadCallbackQueue = mServiceThreadCallbackQueue; auto& serviceThreadCallbackQueue = mServiceThreadCallbackQueue;
// wait for some callbacks to dispatch // wait for some callbacks to dispatch
std::unique_lock<std::mutex> lock(mServiceThreadLock); std::unique_lock<std::mutex> lock(mServiceThreadLock);
while (serviceThreadCallbackQueue.empty() && !mExitRequested) { while (serviceThreadCallbackQueue.empty() && !mExitRequested) {
serviceThreadCondition.wait(lock); serviceThreadCondition.wait(lock);
} }
if (mExitRequested) { if (mExitRequested) {
break; break;
} }
// move the callbacks to a temporary vector // move the callbacks to a temporary vector
auto callbacks(std::move(serviceThreadCallbackQueue)); auto callbacks(std::move(serviceThreadCallbackQueue));
lock.unlock(); lock.unlock();
// and make sure to call them without our lock held // and make sure to call them without our lock held
for (auto[handler, callback, user]: callbacks) { for (auto[handler, callback, user]: callbacks) {
handler->post(user, callback); handler->post(user, callback);
} }
} while (true); } while (true);
}); });
} #endif
} }
DriverBase::~DriverBase() noexcept { DriverBase::~DriverBase() noexcept {
assert_invariant(mCallbacks.empty()); assert_invariant(mCallbacks.empty());
if constexpr (UTILS_HAS_THREADING) { #if UTILS_HAS_THREADING
stopServiceThread(); stopServiceThread();
} #endif
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@@ -107,11 +107,14 @@ void DriverBase::CallbackData::release(CallbackData* data) {
void DriverBase::scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) { void DriverBase::scheduleCallback(CallbackHandler* handler, void* user, CallbackHandler::Callback callback) {
if (handler && UTILS_HAS_THREADING) { #if UTILS_HAS_THREADING
if (handler) {
std::lock_guard<std::mutex> const lock(mServiceThreadLock); std::lock_guard<std::mutex> const lock(mServiceThreadLock);
mServiceThreadCallbackQueue.emplace_back(handler, callback, user); mServiceThreadCallbackQueue.emplace_back(handler, callback, user);
mServiceThreadCondition.notify_one(); mServiceThreadCondition.notify_one();
} else { } else
#endif
{
std::lock_guard<std::mutex> const lock(mPurgeLock); std::lock_guard<std::mutex> const lock(mPurgeLock);
mCallbacks.emplace_back(user, callback); mCallbacks.emplace_back(user, callback);
} }

View File

@@ -238,9 +238,11 @@ protected:
void debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override; void debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
void debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override; void debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept override;
#if UTILS_HAS_THREADING
// Stops the `ServiceThread`. This method is called during destruction but may be called // Stops the `ServiceThread`. This method is called during destruction but may be called
// explicitly if earlier shutdown is needed. This method is idempotent. // explicitly if earlier shutdown is needed. This method is idempotent.
void stopServiceThread() noexcept; void stopServiceThread() noexcept;
#endif
private: private:
const Platform::DriverConfig mDriverConfig; const Platform::DriverConfig mDriverConfig;
@@ -248,11 +250,13 @@ private:
std::mutex mPurgeLock; std::mutex mPurgeLock;
std::vector<std::pair<void*, CallbackHandler::Callback>> mCallbacks; std::vector<std::pair<void*, CallbackHandler::Callback>> mCallbacks;
#if UTILS_HAS_THREADING
std::thread mServiceThread; std::thread mServiceThread;
std::mutex mServiceThreadLock; std::mutex mServiceThreadLock;
std::condition_variable mServiceThreadCondition; std::condition_variable mServiceThreadCondition;
std::vector<std::tuple<CallbackHandler*, CallbackHandler::Callback, void*>> mServiceThreadCallbackQueue; std::vector<std::tuple<CallbackHandler*, CallbackHandler::Callback, void*>> mServiceThreadCallbackQueue;
bool mExitRequested = false; bool mExitRequested = false;
#endif
}; };

View File

@@ -390,9 +390,9 @@ void OpenGLDriver::terminate() {
if (getJobWorker()) { if (getJobWorker()) {
getJobWorker()->terminate(); getJobWorker()->terminate();
} }
if constexpr (UTILS_HAS_THREADING) { #if UTILS_HAS_THREADING
stopServiceThread(); stopServiceThread();
} #endif
mContext.terminate(); mContext.terminate();
mPlatform.terminate(); mPlatform.terminate();