SF: Introduce DisplayModeController
DisplayModeController will centralize the logic and state for selecting
the DisplayMode of each physical display. For now, register a display's
DisplaySnapshot with DMC during configure, and move the creation of its
RefreshRateSelector to DMC::registerDisplay.
Bug: 241285876
Test: presubmit
Change-Id: I673914328bea64636b8bcd193e710131926334a5
diff --git a/services/surfaceflinger/Display/DisplayModeController.cpp b/services/surfaceflinger/Display/DisplayModeController.cpp
new file mode 100644
index 0000000..f093384
--- /dev/null
+++ b/services/surfaceflinger/Display/DisplayModeController.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "DisplayModeController"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "Display/DisplayModeController.h"
+#include "Display/DisplaySnapshot.h"
+
+#include <log/log.h>
+
+namespace android::display {
+
+void DisplayModeController::registerDisplay(DisplaySnapshotRef snapshotRef,
+ DisplayModeId activeModeId,
+ scheduler::RefreshRateSelector::Config config) {
+ const auto& snapshot = snapshotRef.get();
+ const auto displayId = snapshot.displayId();
+
+ mDisplays.emplace_or_replace(displayId, snapshotRef, snapshot.displayModes(), activeModeId,
+ config);
+}
+
+void DisplayModeController::unregisterDisplay(PhysicalDisplayId displayId) {
+ const bool ok = mDisplays.erase(displayId);
+ ALOGE_IF(!ok, "%s: Unknown display %s", __func__, to_string(displayId).c_str());
+}
+
+auto DisplayModeController::selectorPtrFor(PhysicalDisplayId displayId) -> RefreshRateSelectorPtr {
+ return mDisplays.get(displayId)
+ .transform([](const Display& display) { return display.selectorPtr; })
+ .value_or(nullptr);
+}
+
+} // namespace android::display
diff --git a/services/surfaceflinger/Display/DisplayModeController.h b/services/surfaceflinger/Display/DisplayModeController.h
new file mode 100644
index 0000000..b6a6bee
--- /dev/null
+++ b/services/surfaceflinger/Display/DisplayModeController.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <utility>
+
+#include <android-base/thread_annotations.h>
+#include <ui/DisplayId.h>
+#include <ui/DisplayMap.h>
+
+#include "Display/DisplaySnapshotRef.h"
+#include "DisplayHardware/DisplayMode.h"
+#include "Scheduler/RefreshRateSelector.h"
+#include "ThreadContext.h"
+
+namespace android::display {
+
+// Selects the DisplayMode of each physical display, in accordance with DisplayManager policy and
+// certain heuristic signals.
+class DisplayModeController {
+public:
+ // The referenced DisplaySnapshot must outlive the registration.
+ void registerDisplay(DisplaySnapshotRef, DisplayModeId, scheduler::RefreshRateSelector::Config)
+ REQUIRES(kMainThreadContext);
+ void unregisterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext);
+
+ // TODO(b/241285876): Remove once ownership is no longer shared with DisplayDevice.
+ using RefreshRateSelectorPtr = std::shared_ptr<scheduler::RefreshRateSelector>;
+
+ // Returns `nullptr` if the display is no longer registered (or never was).
+ RefreshRateSelectorPtr selectorPtrFor(PhysicalDisplayId) REQUIRES(kMainThreadContext);
+
+ // Used by tests to inject an existing RefreshRateSelector.
+ // TODO(b/241285876): Remove this.
+ void registerDisplay(PhysicalDisplayId displayId, DisplaySnapshotRef snapshotRef,
+ RefreshRateSelectorPtr selectorPtr) {
+ mDisplays.emplace_or_replace(displayId, snapshotRef, selectorPtr);
+ }
+
+private:
+ struct Display {
+ Display(DisplaySnapshotRef snapshot, RefreshRateSelectorPtr selectorPtr)
+ : snapshot(snapshot), selectorPtr(std::move(selectorPtr)) {}
+
+ Display(DisplaySnapshotRef snapshot, DisplayModes modes, DisplayModeId activeModeId,
+ scheduler::RefreshRateSelector::Config config)
+ : Display(snapshot,
+ std::make_shared<scheduler::RefreshRateSelector>(std::move(modes),
+ activeModeId, config)) {}
+
+ const DisplaySnapshotRef snapshot;
+ const RefreshRateSelectorPtr selectorPtr;
+ };
+
+ ui::PhysicalDisplayMap<PhysicalDisplayId, Display> mDisplays;
+};
+
+} // namespace android::display
diff --git a/services/surfaceflinger/Display/DisplaySnapshotRef.h b/services/surfaceflinger/Display/DisplaySnapshotRef.h
new file mode 100644
index 0000000..6cc5f7e
--- /dev/null
+++ b/services/surfaceflinger/Display/DisplaySnapshotRef.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <functional>
+
+namespace android::display {
+
+class DisplaySnapshot;
+
+using DisplaySnapshotRef = std::reference_wrapper<const DisplaySnapshot>;
+
+} // namespace android::display
diff --git a/services/surfaceflinger/Display/PhysicalDisplay.h b/services/surfaceflinger/Display/PhysicalDisplay.h
index ef36234..9b1f1ed 100644
--- a/services/surfaceflinger/Display/PhysicalDisplay.h
+++ b/services/surfaceflinger/Display/PhysicalDisplay.h
@@ -25,6 +25,7 @@
#include <utils/StrongPointer.h>
#include "DisplaySnapshot.h"
+#include "DisplaySnapshotRef.h"
namespace android::display {
@@ -45,8 +46,7 @@
// Transformers for PhysicalDisplays::get.
- using SnapshotRef = std::reference_wrapper<const DisplaySnapshot>;
- SnapshotRef snapshotRef() const { return std::cref(mSnapshot); }
+ DisplaySnapshotRef snapshotRef() const { return std::cref(mSnapshot); }
bool isInternal() const {
return mSnapshot.connectionType() == ui::DisplayConnectionType::Internal;