SF: Introduce a configure stage
Decouple hotplug processing from commit of display transactions, as a
step toward per-display commit/composite. The configure stage will be
responsible for mode setting as well.
Bug: 241285876
Test: libsurfaceflinger_unittest
Change-Id: I72b7223760fa5896debb046f158845a0b4f4599a
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f7146c6..85c003a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -763,10 +763,10 @@
// Do not call property_set on main thread which will be blocked by init
// Use StartPropertySetThread instead.
-void SurfaceFlinger::init() {
+void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- Mutex::Autolock _l(mStateLock);
+ Mutex::Autolock lock(mStateLock);
// Get a RenderEngine for the given display / config (can't fail)
// TODO(b/77156734): We need to stop casting and use HAL types when possible.
@@ -806,12 +806,14 @@
}
// Process any initial hotplug and resulting display changes.
- processDisplayHotplugEventsLocked();
+ LOG_ALWAYS_FATAL_IF(!configureLocked(),
+ "Initial display configuration failed: HWC did not hotplug");
+ processDisplayChangesLocked();
+
const auto display = getDefaultDisplayDeviceLocked();
- LOG_ALWAYS_FATAL_IF(!display, "Missing primary display after registering composer callback.");
- const auto displayId = display->getPhysicalId();
- LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId),
- "Primary display is disconnected.");
+ LOG_ALWAYS_FATAL_IF(!display, "Failed to configure the primary display");
+ LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getPhysicalId()),
+ "Primary display is disconnected");
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -1869,23 +1871,14 @@
void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
hal::Connection connection) {
- const bool connected = connection == hal::Connection::CONNECTED;
- ALOGI("%s HAL display %" PRIu64, connected ? "Connecting" : "Disconnecting", hwcDisplayId);
-
- // Only lock if we're not on the main thread. This function is normally
- // called on a hwbinder thread, but for the primary display it's called on
- // the main thread with the state lock already held, so don't attempt to
- // acquire it here.
- ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
-
- mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection});
-
- if (std::this_thread::get_id() == mMainThreadId) {
- // Process all pending hot plug events immediately if we are on the main thread.
- processDisplayHotplugEventsLocked();
+ {
+ std::lock_guard<std::mutex> lock(mHotplugMutex);
+ mPendingHotplugEvents.push_back(HotplugEvent{hwcDisplayId, connection});
}
- setTransactionFlags(eDisplayTransactionNeeded);
+ if (mScheduler) {
+ mScheduler->scheduleConfigure();
+ }
}
void SurfaceFlinger::onComposerHalVsyncPeriodTimingChanged(
@@ -1958,6 +1951,13 @@
return vsyncDeadline + schedule.period();
}
+void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) {
+ Mutex::Autolock lock(mStateLock);
+ if (configureLocked()) {
+ setTransactionFlags(eDisplayTransactionNeeded);
+ }
+}
+
bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime)
FTL_FAKE_GUARD(kMainThreadContext) {
// The expectedVsyncTime, which was predicted when this frame was scheduled, is normally in the
@@ -2642,8 +2642,14 @@
return {modes, activeMode};
}
-void SurfaceFlinger::processDisplayHotplugEventsLocked() {
- for (const auto& event : mPendingHotplugEvents) {
+bool SurfaceFlinger::configureLocked() {
+ std::vector<HotplugEvent> events;
+ {
+ std::lock_guard<std::mutex> lock(mHotplugMutex);
+ events = std::move(mPendingHotplugEvents);
+ }
+
+ for (const auto& event : events) {
std::optional<DisplayIdentificationInfo> info =
getHwComposer().onHotplug(event.hwcDisplayId, event.connection);
@@ -2653,6 +2659,7 @@
const auto displayId = info->id;
const auto token = mPhysicalDisplayTokens.get(displayId);
+ const char* log;
if (event.connection == hal::Connection::CONNECTED) {
auto [supportedModes, activeMode] = loadDisplayModes(displayId);
@@ -2664,7 +2671,7 @@
}
if (!token) {
- ALOGV("Creating display %s", to_string(displayId).c_str());
+ log = "Connecting";
DisplayDeviceState state;
state.physical = {.id = displayId,
@@ -2681,7 +2688,7 @@
mPhysicalDisplayTokens.try_emplace(displayId, std::move(token));
mInterceptor->saveDisplayCreation(state);
} else {
- ALOGV("Recreating display %s", to_string(displayId).c_str());
+ log = "Reconnecting";
auto& state = mCurrentState.displays.editValueFor(token->get());
state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId.
@@ -2692,7 +2699,7 @@
}
}
} else {
- ALOGV("Removing display %s", to_string(displayId).c_str());
+ log = "Disconnecting";
if (const ssize_t index = mCurrentState.displays.indexOfKey(token->get()); index >= 0) {
const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
@@ -2703,15 +2710,14 @@
mPhysicalDisplayTokens.erase(displayId);
}
- processDisplayChangesLocked();
+ ALOGI("%s display %s (HAL ID %" PRIu64 ")", log, to_string(displayId).c_str(),
+ event.hwcDisplayId);
}
- mPendingHotplugEvents.clear();
+ return !events.empty();
}
void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
- ALOGI("Dispatching display hotplug event displayId=%s, connected=%d",
- to_string(displayId).c_str(), connected);
mScheduler->onHotplugReceived(mAppConnectionHandle, displayId, connected);
mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected);
}
@@ -3041,7 +3047,6 @@
const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
if (displayTransactionNeeded) {
processDisplayChangesLocked();
- processDisplayHotplugEventsLocked();
}
mForceTransactionDisplayChange = displayTransactionNeeded;