SurfaceFlinger: Force HDR content on DEFAULT refresh rate
Do not allow Performance Refresh Rate when displaying HDR content.
Test: HDR Video on YouTube
Bug: 129694529
Change-Id: Ic9b5801d3a4c8b06964e0c4dcec95ef214ebedc6
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 8e36ae9..1db43a3 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -67,7 +67,8 @@
}
}
-void LayerHistory::insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime) {
+void LayerHistory::insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime,
+ bool isHdr) {
std::shared_ptr<LayerInfo> layerInfo;
{
std::lock_guard lock(mLock);
@@ -88,9 +89,36 @@
}
}
layerInfo->setLastPresentTime(presentTime);
+ layerInfo->setHDRContent(isHdr);
}
-float LayerHistory::getDesiredRefreshRate() {
+void LayerHistory::setVisibility(const std::unique_ptr<LayerHandle>& layerHandle, bool visible) {
+ std::shared_ptr<LayerInfo> layerInfo;
+ {
+ std::lock_guard lock(mLock);
+ auto layerInfoIterator = mInactiveLayerInfos.find(layerHandle->mId);
+ if (layerInfoIterator != mInactiveLayerInfos.end()) {
+ layerInfo = layerInfoIterator->second;
+ if (visible) {
+ mInactiveLayerInfos.erase(layerInfoIterator);
+ mActiveLayerInfos.insert({layerHandle->mId, layerInfo});
+ }
+ } else {
+ layerInfoIterator = mActiveLayerInfos.find(layerHandle->mId);
+ if (layerInfoIterator != mActiveLayerInfos.end()) {
+ layerInfo = layerInfoIterator->second;
+ } else {
+ ALOGW("Inserting information about layer that is not registered: %" PRId64,
+ layerHandle->mId);
+ return;
+ }
+ }
+ }
+ layerInfo->setVisibility(visible);
+}
+
+std::pair<float, bool> LayerHistory::getDesiredRefreshRateAndHDR() {
+ bool isHDR = false;
float newRefreshRate = 0.f;
std::lock_guard lock(mLock);
@@ -108,12 +136,13 @@
if (layerInfo->isRecentlyActive() && layerRefreshRate > newRefreshRate) {
newRefreshRate = layerRefreshRate;
}
+ isHDR |= layerInfo->getHDRContent();
}
if (mTraceEnabled) {
ALOGD("LayerHistory DesiredRefreshRate: %.2f", newRefreshRate);
}
- return newRefreshRate;
+ return {newRefreshRate, isHDR};
}
void LayerHistory::removeIrrelevantLayers() {
@@ -122,7 +151,9 @@
auto it = mActiveLayerInfos.begin();
while (it != mActiveLayerInfos.end()) {
// If last updated was before the obsolete time, remove it.
- if (it->second->getLastUpdatedTime() < obsoleteEpsilon) {
+ // Keep HDR layer around as long as they are visible.
+ if (!it->second->isVisible() ||
+ (!it->second->getHDRContent() && it->second->getLastUpdatedTime() < obsoleteEpsilon)) {
// erase() function returns the iterator of the next
// to last deleted element.
if (mTraceEnabled) {
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 39061e7..adc5ce5 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -56,10 +56,13 @@
std::unique_ptr<LayerHandle> createLayer(const std::string name, float maxRefreshRate);
// Method for inserting layers and their requested present time into the unordered map.
- void insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime);
+ void insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime, bool isHdr);
+ // Method for setting layer visibility
+ void setVisibility(const std::unique_ptr<LayerHandle>& layerHandle, bool visible);
+
// Returns the desired refresh rate, which is a max refresh rate of all the current
// layers. See go/content-fps-detection-in-scheduler for more information.
- float getDesiredRefreshRate();
+ std::pair<float, bool> getDesiredRefreshRateAndHDR();
// Removes the handle and the object from the map.
void destroyLayer(const int64_t id);
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 1970a47..02b6aef 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -115,6 +115,16 @@
// updated time, the updated time is the present time.
void setLastPresentTime(nsecs_t lastPresentTime);
+ void setHDRContent(bool isHdr) {
+ std::lock_guard lock(mLock);
+ mIsHDR = isHdr;
+ }
+
+ void setVisibility(bool visible) {
+ std::lock_guard lock(mLock);
+ mIsVisible = visible;
+ }
+
// Checks the present time history to see whether the layer is relevant.
bool isRecentlyActive() const {
std::lock_guard lock(mLock);
@@ -127,6 +137,16 @@
return mRefreshRateHistory.getRefreshRateAvg();
}
+ bool getHDRContent() {
+ std::lock_guard lock(mLock);
+ return mIsHDR;
+ }
+
+ bool isVisible() {
+ std::lock_guard lock(mLock);
+ return mIsVisible;
+ }
+
// Return the last updated time. If the present time is farther in the future than the
// updated time, the updated time is the present time.
nsecs_t getLastUpdatedTime() {
@@ -150,6 +170,8 @@
nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0;
RefreshRateHistory mRefreshRateHistory GUARDED_BY(mLock);
PresentTimeHistory mPresentTimeHistory GUARDED_BY(mLock);
+ bool mIsHDR GUARDED_BY(mLock) = false;
+ bool mIsVisible GUARDED_BY(mLock) = false;
};
} // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 88d2638..5b87a3d 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -306,10 +306,15 @@
return mLayerHistory.createLayer(name, fps);
}
-void Scheduler::addLayerPresentTime(
+void Scheduler::addLayerPresentTimeAndHDR(
const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
- nsecs_t presentTime) {
- mLayerHistory.insert(layerHandle, presentTime);
+ nsecs_t presentTime, bool isHDR) {
+ mLayerHistory.insert(layerHandle, presentTime, isHDR);
+}
+
+void Scheduler::setLayerVisibility(
+ const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) {
+ mLayerHistory.setVisibility(layerHandle, visible);
}
void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) {
@@ -317,18 +322,23 @@
}
void Scheduler::updateFpsBasedOnContent() {
- uint32_t refreshRate = std::round(mLayerHistory.getDesiredRefreshRate());
+ auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
+ const uint32_t refreshRateRound = std::round(refreshRate);
RefreshRateType newRefreshRateType;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
- if (mContentRefreshRate == refreshRate) {
+ if (mContentRefreshRate == refreshRateRound && mIsHDRContent == isHDR) {
return;
}
- mContentRefreshRate = refreshRate;
+ mContentRefreshRate = refreshRateRound;
ATRACE_INT("ContentFPS", mContentRefreshRate);
- mCurrentContentFeatureState = refreshRate > 0 ? ContentFeatureState::CONTENT_DETECTION_ON
- : ContentFeatureState::CONTENT_DETECTION_OFF;
+ mIsHDRContent = isHDR;
+ ATRACE_INT("ContentHDR", mIsHDRContent);
+
+ mCurrentContentFeatureState = refreshRateRound > 0
+ ? ContentFeatureState::CONTENT_DETECTION_ON
+ : ContentFeatureState::CONTENT_DETECTION_OFF;
newRefreshRateType = calculateRefreshRateType();
if (mRefreshRateType == newRefreshRateType) {
return;
@@ -400,6 +410,11 @@
return RefreshRateType::DEFAULT;
}
+ // HDR content is not supported on PERFORMANCE mode
+ if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
+ return RefreshRateType::DEFAULT;
+ }
+
// If content detection is off we choose performance as we don't know the content fps
if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_OFF) {
return RefreshRateType::PERFORMANCE;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 34327b5..76b1ee3 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -150,9 +150,12 @@
int windowType);
// Stores present time for a layer.
- void addLayerPresentTime(
+ void addLayerPresentTimeAndHDR(
const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
- nsecs_t presentTime);
+ nsecs_t presentTime, bool isHDR);
+ // Stores visibility for a layer.
+ void setLayerVisibility(
+ const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible);
// Updates FPS based on the most content presented.
void updateFpsBasedOnContent();
// Callback that gets invoked when Scheduler wants to change the refresh rate.
@@ -254,8 +257,12 @@
IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET;
uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock);
RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock);
+ bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false;
const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
+
+ // Global config to force HDR content to work on DEFAULT refreshRate
+ static constexpr bool mForceHDRContentToDefaultRefreshRate = true;
};
} // namespace android