SurfaceFlinger: add Refresh Rate overlay
Add an overlay to indicate what is the current refresh rate.
Currently it is implemented by a ColorLayer:
- Red - Default refresh rate
- Green - Performance refresh rate
To enable the overlay:
adb shell service call SurfaceFlinger 1034 i32 1
To disable the overlay:
adb shell service call SurfaceFlinger 1034 i32 0
Test: manual
Change-Id: I851f2530e7accacd2cac446b30aa2e0b6d431a92
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index ac1d492..c3324af 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -138,8 +138,9 @@
"LayerVector.cpp",
"MonitoredProducer.cpp",
"NativeWindowSurface.cpp",
- "RenderArea.cpp",
+ "RefreshRateOverlay.cpp",
"RegionSamplingThread.cpp",
+ "RenderArea.cpp",
"Scheduler/DispSync.cpp",
"Scheduler/DispSyncSource.cpp",
"Scheduler/EventControlThread.cpp",
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
new file mode 100644
index 0000000..e70bfe4
--- /dev/null
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#include "RefreshRateOverlay.h"
+#include "Client.h"
+#include "Layer.h"
+
+namespace android {
+
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
+RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger)
+ : mFlinger(flinger), mClient(new Client(&mFlinger)) {
+ createLayer();
+}
+
+bool RefreshRateOverlay::createLayer() {
+ const status_t ret =
+ mFlinger.createLayer(String8("RefreshRateOverlay"), mClient, 0, 0,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor,
+ LayerMetadata(), &mIBinder, &mGbp, &mLayer);
+ if (ret) {
+ ALOGE("failed to color layer");
+ return false;
+ }
+
+ mLayer = mClient->getLayerUser(mIBinder);
+ mLayer->setCrop_legacy(Rect(0, 0, 200, 100), true);
+ mLayer->setLayer(INT32_MAX - 2);
+
+ return true;
+}
+
+void RefreshRateOverlay::changeRefreshRate(RefreshRateType type) {
+ const half3& color = (type == RefreshRateType::PERFORMANCE) ? GREEN : RED;
+ mLayer->setColor(color);
+ mFlinger.setTransactionFlags(eTransactionMask);
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
new file mode 100644
index 0000000..ce29bc3
--- /dev/null
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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 "SurfaceFlinger.h"
+
+namespace android {
+
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
+class RefreshRateOverlay {
+public:
+ RefreshRateOverlay(SurfaceFlinger& flinger);
+
+ void changeRefreshRate(RefreshRateType type);
+
+private:
+ bool createLayer();
+
+ SurfaceFlinger& mFlinger;
+ sp<Client> mClient;
+ sp<Layer> mLayer;
+ sp<IBinder> mIBinder;
+ sp<IGraphicBufferProducer> mGbp;
+
+ const half3 RED = half3(1.0f, 0.0f, 0.0f);
+ const half3 GREEN = half3(0.0f, 1.0f, 0.0f);
+};
+
+}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e11ab6d..f51b652 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -84,6 +84,7 @@
#include "LayerVector.h"
#include "MonitoredProducer.h"
#include "NativeWindowSurface.h"
+#include "RefreshRateOverlay.h"
#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
#include "SurfaceInterceptor.h"
@@ -128,8 +129,6 @@
using ui::Hdr;
using ui::RenderIntent;
-using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
-
namespace {
#pragma clang diagnostic push
@@ -942,19 +941,18 @@
return display->getActiveConfig();
}
-void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
- Scheduler::ConfigEvent event) {
+void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
ATRACE_CALL();
// Lock is acquired by setRefreshRateTo.
- const auto display = getDisplayDeviceLocked(displayToken);
+ const auto display = getDisplayDeviceLocked(info.displayToken);
if (!display) {
- ALOGE("Attempt to set active config %d for invalid display token %p", mode,
- displayToken.get());
+ ALOGE("Attempt to set active config %d for invalid display token %p", info.configId,
+ info.displayToken.get());
return;
}
if (display->isVirtual()) {
- ALOGW("Attempt to set active config %d for virtual display", mode);
+ ALOGW("Attempt to set active config %d for virtual display", info.configId);
return;
}
int currentDisplayPowerMode = display->getPowerMode();
@@ -967,8 +965,9 @@
// config twice. However event generation config might have changed so we need to update it
// accordingly
std::lock_guard<std::mutex> lock(mActiveConfigLock);
- const Scheduler::ConfigEvent desiredConfig = mDesiredActiveConfig.event | event;
- mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, desiredConfig};
+ const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event;
+ mDesiredActiveConfig = info;
+ mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;
if (!mDesiredActiveConfigChanged) {
// This is the first time we set the desired
@@ -979,6 +978,10 @@
}
mDesiredActiveConfigChanged = true;
ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+
+ if (mRefreshRateOverlay) {
+ mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
+ }
}
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
@@ -1492,7 +1495,7 @@
}
mPhaseOffsets->setRefreshRateType(refreshRate);
- setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
+ setDesiredActiveConfig({refreshRate, desiredConfigId, getInternalDisplayTokenLocked(), event});
}
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -5021,9 +5024,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1033 are currently used for backdoors. The code
+ // Numbers from 1000 to 1034 are currently used for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1033) {
+ if (code >= 1000 && code <= 1034) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -5339,6 +5342,18 @@
reply->writeInt32(NO_ERROR);
return NO_ERROR;
}
+ case 1034: {
+ // TODO(b/129297325): expose this via developer menu option
+ n = data.readInt32();
+ if (n && !mRefreshRateOverlay) {
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
+ mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
+ } else if (!n) {
+ mRefreshRateOverlay.reset();
+ }
+ return NO_ERROR;
+ }
}
}
return err;
@@ -5811,8 +5826,8 @@
for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
if (iter->second && isConfigAllowed(*displayId, iter->second->configId)) {
ALOGV("switching to config %d", iter->second->configId);
- setDesiredActiveConfig(displayToken, iter->second->configId,
- Scheduler::ConfigEvent::Changed);
+ setDesiredActiveConfig({iter->first, iter->second->configId, displayToken,
+ Scheduler::ConfigEvent::Changed});
break;
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 26d0cd1..30fd244 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -90,6 +90,8 @@
namespace android {
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
// ---------------------------------------------------------------------------
class Client;
@@ -102,6 +104,7 @@
class IInputFlinger;
class InjectVSyncSource;
class Layer;
+class RefreshRateOverlay;
class Surface;
class SurfaceFlingerBE;
class TimeStats;
@@ -366,6 +369,7 @@
friend class BufferQueueLayer;
friend class BufferStateLayer;
friend class MonitoredProducer;
+ friend class RefreshRateOverlay;
friend class RegionSamplingThread;
friend class SurfaceTracing;
@@ -528,11 +532,30 @@
void signalLayerUpdate();
void signalRefresh();
+ struct ActiveConfigInfo {
+ RefreshRateType type;
+ int configId;
+ sp<IBinder> displayToken;
+ Scheduler::ConfigEvent event;
+
+ bool operator!=(const ActiveConfigInfo& other) const {
+ if (type != other.type) {
+ return true;
+ }
+ if (configId != other.configId) {
+ return true;
+ }
+ if (displayToken != other.displayToken) {
+ return true;
+ }
+ return (event != other.event);
+ }
+ };
+
// called on the main thread in response to initializeDisplays()
void onInitializeDisplays() REQUIRES(mStateLock);
// Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
- void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
- Scheduler::ConfigEvent event) REQUIRES(mStateLock);
+ void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
// Once HWC has returned the present fence, this sets the active config and a new refresh
// rate in SF. It also triggers HWC vsync.
void setActiveConfigInternal() REQUIRES(mStateLock);
@@ -815,8 +838,7 @@
// Sets the refresh rate by switching active configs, if they are available for
// the desired refresh rate.
- void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType,
- Scheduler::ConfigEvent event) REQUIRES(mStateLock);
+ void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock);
bool isConfigAllowed(const DisplayId& displayId, int32_t config);
@@ -1134,18 +1156,6 @@
std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
GUARDED_BY(mAllowedConfigsLock);
- struct ActiveConfigInfo {
- int configId;
- sp<IBinder> displayToken;
- Scheduler::ConfigEvent event;
-
- bool operator!=(const ActiveConfigInfo& other) const {
- if (configId != other.configId) {
- return true;
- }
- return (displayToken != other.displayToken);
- }
- };
std::mutex mActiveConfigLock;
// This bit is set once we start setting the config. We read from this bit during the
// process. If at the end, this bit is different than mDesiredActiveConfig, we restart
@@ -1172,6 +1182,8 @@
sp<SetInputWindowsListener> mSetInputWindowsListener;
bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
Hwc2::impl::PowerAdvisor mPowerAdvisor;
+
+ std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
};
}; // namespace android