summaryrefslogtreecommitdiff
path: root/libhwc2.1/libdevice/ExynosDisplay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libhwc2.1/libdevice/ExynosDisplay.cpp')
-rw-r--r--libhwc2.1/libdevice/ExynosDisplay.cpp145
1 files changed, 140 insertions, 5 deletions
diff --git a/libhwc2.1/libdevice/ExynosDisplay.cpp b/libhwc2.1/libdevice/ExynosDisplay.cpp
index 6542984..d050dee 100644
--- a/libhwc2.1/libdevice/ExynosDisplay.cpp
+++ b/libhwc2.1/libdevice/ExynosDisplay.cpp
@@ -31,6 +31,7 @@
#include <sys/ioctl.h>
#include <utils/CallStack.h>
+#include <charconv>
#include <future>
#include <map>
@@ -988,6 +989,7 @@ ExynosDisplay::ExynosDisplay(uint32_t type, uint32_t index, ExynosDevice *device
mClientCompositionInfo(COMPOSITION_CLIENT),
mExynosCompositionInfo(COMPOSITION_EXYNOS),
mGeometryChanged(0x0),
+ mBufferUpdates(0),
mRenderingState(RENDERING_STATE_NONE),
mHWCRenderingState(RENDERING_STATE_NONE),
mDisplayBW(0),
@@ -1475,11 +1477,16 @@ void ExynosDisplay::setGeometryChanged(uint64_t changedBit) {
void ExynosDisplay::clearGeometryChanged()
{
mGeometryChanged = 0;
+ mBufferUpdates = 0;
for (size_t i=0; i < mLayers.size(); i++) {
mLayers[i]->clearGeometryChanged();
}
}
+bool ExynosDisplay::isFrameUpdate() {
+ return mGeometryChanged > 0 || mBufferUpdates > 0;
+}
+
int ExynosDisplay::handleStaticLayers(ExynosCompositionInfo& compositionInfo)
{
if (compositionInfo.mType != COMPOSITION_CLIENT)
@@ -1701,11 +1708,13 @@ int ExynosDisplay::skipStaticLayers(ExynosCompositionInfo& compositionInfo)
return NO_ERROR;
}
-bool ExynosDisplay::skipSignalIdleForVideoLayer(void) {
- /* ignore the frame update in case we have video layer but ui layer is not updated */
+bool ExynosDisplay::skipSignalIdle(void) {
for (size_t i = 0; i < mLayers.size(); i++) {
- if (!mLayers[i]->isLayerFormatYuv() &&
- mLayers[i]->mLastLayerBuffer != mLayers[i]->mLayerBuffer) {
+ // Frame update for refresh rate overlay indicator layer can be ignored
+ if (mLayers[i]->mCompositionType == HWC2_COMPOSITION_REFRESH_RATE_INDICATOR) continue;
+ // Frame update for video layer can be ignored
+ if (mLayers[i]->isLayerFormatYuv()) continue;
+ if (mLayers[i]->mLastLayerBuffer != mLayers[i]->mLayerBuffer) {
return false;
}
}
@@ -3024,6 +3033,9 @@ int32_t ExynosDisplay::getLayerCompositionTypeForValidationType(uint32_t layerIn
} else if ((mLayers[layerIndex]->mCompositionType == HWC2_COMPOSITION_SOLID_COLOR) &&
(mLayers[layerIndex]->mValidateCompositionType == HWC2_COMPOSITION_DEVICE)) {
type = HWC2_COMPOSITION_SOLID_COLOR;
+ } else if ((mLayers[layerIndex]->mCompositionType == HWC2_COMPOSITION_REFRESH_RATE_INDICATOR) &&
+ (mLayers[layerIndex]->mValidateCompositionType == HWC2_COMPOSITION_DEVICE)) {
+ type = HWC2_COMPOSITION_REFRESH_RATE_INDICATOR;
} else {
type = mLayers[layerIndex]->mValidateCompositionType;
}
@@ -3601,10 +3613,14 @@ int32_t ExynosDisplay::presentDisplay(int32_t* outRetireFence) {
goto err;
}
- if (mGeometryChanged != 0 || !skipSignalIdleForVideoLayer()) {
+ if (mGeometryChanged != 0 || !skipSignalIdle()) {
mPowerHalHint.signalIdle();
}
+ if (isFrameUpdate()) {
+ updateRefreshRateIndicator();
+ }
+
handleWindowUpdate();
setDisplayWinConfigData();
@@ -6149,3 +6165,122 @@ bool ExynosDisplay::RotatingLogFileWriter::chooseOpenedFile() {
}
return false;
}
+
+ExynosDisplay::RefreshRateIndicatorHandler::RefreshRateIndicatorHandler(ExynosDisplay *display)
+ : mDisplay(display), mLastRefreshRate(0), mLastCallbackTime(0) {}
+
+int32_t ExynosDisplay::RefreshRateIndicatorHandler::init() {
+ auto path = String8::format(kRefreshRateStatePathFormat, mDisplay->mIndex);
+ mFd.Set(open(path.c_str(), O_RDONLY));
+ if (mFd.get() < 0) {
+ ALOGE("Failed to open sysfs(%s) for refresh rate debug event: %s", path.c_str(),
+ strerror(errno));
+ return -errno;
+ }
+
+ return NO_ERROR;
+}
+
+void ExynosDisplay::RefreshRateIndicatorHandler::updateRefreshRateLocked(int refreshRate) {
+ ATRACE_CALL();
+ ATRACE_INT("Refresh rate indicator event", refreshRate);
+ auto lastUpdate = mDisplay->getLastLayerUpdateTime();
+ // Ignore refresh rate increase that is caused by refresh rate indicator update but there's
+ // no update for the other layers
+ if (refreshRate > mLastRefreshRate && mLastRefreshRate > 0 && lastUpdate < mLastCallbackTime) {
+ mIgnoringLastUpdate = true;
+ return;
+ }
+ mIgnoringLastUpdate = false;
+ if (refreshRate == mLastRefreshRate) {
+ return;
+ }
+ mLastRefreshRate = refreshRate;
+ mLastCallbackTime = systemTime(CLOCK_MONOTONIC);
+ ATRACE_INT("Refresh rate indicator callback", mLastRefreshRate);
+ mDisplay->mDevice->onRefreshRateChangedDebug(mDisplay->mDisplayId, s2ns(1) / mLastRefreshRate);
+}
+
+void ExynosDisplay::RefreshRateIndicatorHandler::handleSysfsEvent() {
+ ATRACE_CALL();
+ std::scoped_lock lock(mMutex);
+
+ char buffer[1024];
+ lseek(mFd.get(), 0, SEEK_SET);
+ int ret = read(mFd.get(), &buffer, sizeof(buffer));
+ if (ret < 0) {
+ ALOGE("%s: Failed to read refresh rate from fd %d: %s", __func__, mFd.get(),
+ strerror(errno));
+ return;
+ }
+ std::string_view bufferView(buffer);
+ auto pos = bufferView.find('@');
+ if (pos == std::string::npos) {
+ ALOGE("%s: Failed to parse refresh rate event (invalid format)", __func__);
+ return;
+ }
+ int refreshRate = 0;
+ std::from_chars(bufferView.data() + pos + 1, bufferView.data() + bufferView.size() - 1,
+ refreshRate);
+ updateRefreshRateLocked(refreshRate);
+}
+
+void ExynosDisplay::RefreshRateIndicatorHandler::updateRefreshRate(int refreshRate) {
+ std::scoped_lock lock(mMutex);
+ updateRefreshRateLocked(refreshRate);
+}
+
+int32_t ExynosDisplay::setRefreshRateChangedCallbackDebugEnabled(bool enabled) {
+ if ((!!mRefreshRateIndicatorHandler) == enabled) {
+ ALOGW("%s: RefreshRateChangedCallbackDebug is already %s", __func__,
+ enabled ? "enabled" : "disabled");
+ return NO_ERROR;
+ }
+ int32_t ret = NO_ERROR;
+ if (enabled) {
+ mRefreshRateIndicatorHandler = std::make_shared<RefreshRateIndicatorHandler>(this);
+ if (!mRefreshRateIndicatorHandler) {
+ ALOGE("%s: Failed to create refresh rate debug handler", __func__);
+ return -ENOMEM;
+ }
+ ret = mRefreshRateIndicatorHandler->init();
+ if (ret != NO_ERROR) {
+ ALOGE("%s: Failed to initialize refresh rate debug handler: %d", __func__, ret);
+ mRefreshRateIndicatorHandler.reset();
+ return ret;
+ }
+ ret = mDevice->mDeviceInterface->registerSysfsEventHandler(mRefreshRateIndicatorHandler);
+ if (ret != NO_ERROR) {
+ ALOGE("%s: Failed to register sysfs event handler: %d", __func__, ret);
+ mRefreshRateIndicatorHandler.reset();
+ return ret;
+ }
+ // Call the callback immediately
+ mRefreshRateIndicatorHandler->handleSysfsEvent();
+ } else {
+ ret = mDevice->mDeviceInterface->unregisterSysfsEventHandler(
+ mRefreshRateIndicatorHandler->getFd());
+ mRefreshRateIndicatorHandler.reset();
+ }
+ return ret;
+}
+
+nsecs_t ExynosDisplay::getLastLayerUpdateTime() {
+ Mutex::Autolock lock(mDRMutex);
+ nsecs_t time = 0;
+ for (size_t i = 0; i < mLayers.size(); ++i) {
+ // The update from refresh rate indicator layer should be ignored
+ if (mLayers[i]->mCompositionType == HWC2_COMPOSITION_REFRESH_RATE_INDICATOR) continue;
+ time = max(time, mLayers[i]->mLastUpdateTime);
+ }
+ return time;
+}
+
+void ExynosDisplay::updateRefreshRateIndicator() {
+ // Update refresh rate indicator if the last update event is ignored to make sure that
+ // the refresh rate caused by the current frame update will be applied immediately since
+ // we may not receive the sysfs event if the refresh rate is the same as the last ignored one.
+ if (!mRefreshRateIndicatorHandler || !mRefreshRateIndicatorHandler->isIgnoringLastUpdate())
+ return;
+ mRefreshRateIndicatorHandler->handleSysfsEvent();
+}