diff options
-rw-r--r-- | hwc3/ComposerClient.cpp | 17 | ||||
-rw-r--r-- | hwc3/impl/HalImpl.cpp | 29 | ||||
-rw-r--r-- | hwc3/impl/HalImpl.h | 3 | ||||
-rw-r--r-- | libhwc2.1/libdevice/ExynosDevice.cpp | 16 | ||||
-rw-r--r-- | libhwc2.1/libdevice/ExynosDevice.h | 7 | ||||
-rw-r--r-- | libhwc2.1/libdevice/ExynosDisplay.cpp | 145 | ||||
-rw-r--r-- | libhwc2.1/libdevice/ExynosDisplay.h | 41 | ||||
-rw-r--r-- | libhwc2.1/libdevice/ExynosLayer.cpp | 10 | ||||
-rw-r--r-- | libhwc2.1/libdevice/ExynosLayer.h | 3 | ||||
-rw-r--r-- | libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp | 9 | ||||
-rw-r--r-- | libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h | 4 | ||||
-rw-r--r-- | libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h | 16 | ||||
-rw-r--r-- | libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp | 4 | ||||
-rw-r--r-- | libhwc2.1/libdrmresource/drm/drmeventlistener.cpp | 70 | ||||
-rw-r--r-- | libhwc2.1/libdrmresource/include/drmeventlistener.h | 30 | ||||
-rw-r--r-- | libhwc2.1/libhwcService/ExynosHWCService.cpp | 13 | ||||
-rw-r--r-- | libhwc2.1/libhwcService/ExynosHWCService.h | 2 | ||||
-rw-r--r-- | libhwc2.1/libhwcService/IExynosHWC.cpp | 23 | ||||
-rw-r--r-- | libhwc2.1/libhwcService/IExynosHWC.h | 1 |
19 files changed, 403 insertions, 40 deletions
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp index 7f73d0f..edd8771 100644 --- a/hwc3/ComposerClient.cpp +++ b/hwc3/ComposerClient.cpp @@ -433,15 +433,20 @@ ndk::ScopedAStatus ComposerClient::setIdleTimerEnabled(int64_t display, int32_t return TO_BINDER_STATUS(err); } -ndk::ScopedAStatus ComposerClient::setRefreshRateChangedCallbackDebugEnabled(int64_t /* display */, - bool /* enabled */) { - // TODO(b/267825022) Add implementation for the HAL and pass appropriate binder status - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +ndk::ScopedAStatus ComposerClient::setRefreshRateChangedCallbackDebugEnabled(int64_t display, + bool enabled) { + DEBUG_DISPLAY_FUNC(display); + auto err = mHal->setRefreshRateChangedCallbackDebugEnabled(display, enabled); + return TO_BINDER_STATUS(err); } void ComposerClient::HalEventCallback::onRefreshRateChangedDebug( - const RefreshRateChangedDebugData&) { - // TODO(b/267825022) Add implementation for the HAL + const RefreshRateChangedDebugData& data) { + DEBUG_DISPLAY_FUNC(data.display); + auto ret = mCallback->onRefreshRateChangedDebug(data); + if (!ret.isOk()) { + LOG(ERROR) << "failed to send onRefreshRateChangedDebug:" << ret.getDescription(); + } } void ComposerClient::HalEventCallback::onHotplug(int64_t display, bool connected) { diff --git a/hwc3/impl/HalImpl.cpp b/hwc3/impl/HalImpl.cpp index fb41a77..e48d390 100644 --- a/hwc3/impl/HalImpl.cpp +++ b/hwc3/impl/HalImpl.cpp @@ -99,6 +99,20 @@ void seamlessPossible(hwc2_callback_data_t callbackData, hwc2_display_t hwcDispl hal->getEventCallback()->onSeamlessPossible(display); } +void refreshRateChangedDebug(hwc2_callback_data_t callbackData, hwc2_display_t hwcDisplay, + hwc2_vsync_period_t hwcVsyncPeriodNanos) { + auto hal = static_cast<HalImpl*>(callbackData); + int64_t display; + int32_t vsyncPeriodNanos; + + h2a::translate(hwcDisplay, display); + h2a::translate(hwcVsyncPeriodNanos, vsyncPeriodNanos); + hal->getEventCallback()->onRefreshRateChangedDebug(RefreshRateChangedDebugData{ + .display = display, + .vsyncPeriodNanos = vsyncPeriodNanos, + }); +} + } // nampesapce hook HalImpl::HalImpl(std::unique_ptr<ExynosDevice> device) : mDevice(std::move(device)) { @@ -130,6 +144,7 @@ void HalImpl::initCaps() { } mCaps.insert(Capability::BOOT_DISPLAY_CONFIG); + mCaps.insert(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG); } int32_t HalImpl::getHalDisplay(int64_t display, ExynosDisplay*& halDisplay) { @@ -193,6 +208,9 @@ void HalImpl::registerEventCallback(EventCallback* callback) { // register HWC3 Callback mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onVsyncIdle, this, reinterpret_cast<hwc2_function_pointer_t>(hook::vsyncIdle)); + mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onRefreshRateChangedDebug, this, + reinterpret_cast<hwc2_function_pointer_t>( + hook::refreshRateChangedDebug)); } void HalImpl::unregisterEventCallback() { @@ -204,6 +222,8 @@ void HalImpl::unregisterEventCallback() { // unregister HWC3 Callback mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onVsyncIdle, this, nullptr); + mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onRefreshRateChangedDebug, this, + nullptr); mEventCallback = nullptr; } @@ -1064,10 +1084,11 @@ int32_t HalImpl::getDisplayMultiThreadedPresentSupport(const int64_t& display, b return halDisplay->getDisplayMultiThreadedPresentSupport(outSupport); } -int32_t HalImpl::setRefreshRateChangedCallbackDebugEnabled(int64_t /* display*/, - bool /* enabled */) { - // TODO(b/267825022) Add implementation for the HAL - return EX_UNSUPPORTED_OPERATION; +int32_t HalImpl::setRefreshRateChangedCallbackDebugEnabled(int64_t display, bool enabled) { + ExynosDisplay* halDisplay; + RET_IF_ERR(getHalDisplay(display, halDisplay)); + + return halDisplay->setRefreshRateChangedCallbackDebugEnabled(enabled); } } // namespace aidl::android::hardware::graphics::composer3::impl diff --git a/hwc3/impl/HalImpl.h b/hwc3/impl/HalImpl.h index 6af1b17..9cb8f1d 100644 --- a/hwc3/impl/HalImpl.h +++ b/hwc3/impl/HalImpl.h @@ -158,8 +158,7 @@ class HalImpl : public IComposerHal { const std::optional<ClockMonotonicTimestamp> expectedPresentTime) override; EventCallback* getEventCallback() { return mEventCallback; } - int32_t setRefreshRateChangedCallbackDebugEnabled(int64_t /* display */, - bool /* enabled */) override; + int32_t setRefreshRateChangedCallbackDebugEnabled(int64_t display, bool enabled) override; private: void initCaps(); diff --git a/libhwc2.1/libdevice/ExynosDevice.cpp b/libhwc2.1/libdevice/ExynosDevice.cpp index f2eddbf..b4de1ae 100644 --- a/libhwc2.1/libdevice/ExynosDevice.cpp +++ b/libhwc2.1/libdevice/ExynosDevice.cpp @@ -1209,3 +1209,19 @@ void ExynosDevice::onVsyncIdle(hwc2_display_t displayId) { hwc2_display_t hwcDisplay)>(callbackInfo.funcPointer); callbackFunc(callbackInfo.callbackData, displayId); } + +void ExynosDevice::onRefreshRateChangedDebug(hwc2_display_t displayId, uint32_t vsyncPeriod) { + Mutex::Autolock lock(mDeviceCallbackMutex); + const auto &refreshRateCallback = + mHwc3CallbackInfos.find(IComposerCallback::TRANSACTION_onRefreshRateChangedDebug); + + if (refreshRateCallback == mHwc3CallbackInfos.end()) return; + + const auto &callbackInfo = refreshRateCallback->second; + if (callbackInfo.funcPointer == nullptr || callbackInfo.callbackData == nullptr) return; + + auto callbackFunc = + reinterpret_cast<void (*)(hwc2_callback_data_t callbackData, hwc2_display_t hwcDisplay, + hwc2_vsync_period_t)>(callbackInfo.funcPointer); + callbackFunc(callbackInfo.callbackData, displayId, vsyncPeriod); +} diff --git a/libhwc2.1/libdevice/ExynosDevice.h b/libhwc2.1/libdevice/ExynosDevice.h index 8b3d9e1..3569643 100644 --- a/libhwc2.1/libdevice/ExynosDevice.h +++ b/libhwc2.1/libdevice/ExynosDevice.h @@ -17,8 +17,8 @@ #ifndef _EXYNOSDEVICE_H #define _EXYNOSDEVICE_H -#include <aidl/com/google/hardware/pixel/display/BnDisplay.h> #include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> +#include <aidl/com/google/hardware/pixel/display/BnDisplay.h> #include <cutils/atomic.h> #include <displaycolor/displaycolor.h> #include <hardware/hwcomposer2.h> @@ -36,6 +36,7 @@ #include <map> #include <thread> +#include "ExynosDeviceInterface.h" #include "ExynosHWC.h" #include "ExynosHWCHelper.h" #include "ExynosHWCModule.h" @@ -143,10 +144,8 @@ enum { GEOMETRY_ERROR_CASE = 1ULL << 63, }; -class ExynosDevice; class ExynosDisplay; class ExynosResourceManager; -class ExynosDeviceInterface; class ExynosDevice { public: @@ -346,6 +345,8 @@ class ExynosDevice { return HWC2_ERROR_UNSUPPORTED; } + void onRefreshRateChangedDebug(hwc2_display_t displayId, uint32_t vsyncPeriod); + protected: void initDeviceInterface(uint32_t interfaceType); protected: 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(); +} diff --git a/libhwc2.1/libdevice/ExynosDisplay.h b/libhwc2.1/libdevice/ExynosDisplay.h index aaae5cb..65dd936 100644 --- a/libhwc2.1/libdevice/ExynosDisplay.h +++ b/libhwc2.1/libdevice/ExynosDisplay.h @@ -27,6 +27,7 @@ #include <chrono> #include <set> +#include "DeconHeader.h" #include "ExynosDisplayInterface.h" #include "ExynosHWC.h" #include "ExynosHWCDebug.h" @@ -34,8 +35,8 @@ #include "ExynosHwc3Types.h" #include "ExynosMPP.h" #include "ExynosResourceManager.h" +#include "drmeventlistener.h" #include "worker.h" -#include "DeconHeader.h" #define HWC_CLEARDISPLAY_WITH_COLORMAP #define HWC_PRINT_FRAME_NUM 10 @@ -449,10 +450,17 @@ class ExynosDisplay { * Geometry change info is described by bit map. * This flag is cleared when resource assignment for all displays * is done. + * Geometry changed to layer REFRESH_RATE_INDICATOR will be excluded. */ uint64_t mGeometryChanged; /** + * The number of buffer updates in the current frame. + * Buffer update for layer REFRESH_RATE_INDICATOR will be excluded. + */ + uint32_t mBufferUpdates; + + /** * Rendering step information that is seperated by * VALIDATED, ACCEPTED_CHANGE, PRESENTED. */ @@ -1190,6 +1198,7 @@ class ExynosDisplay { void setHWCControl(uint32_t ctrl, int32_t val); void setGeometryChanged(uint64_t changedBit); void clearGeometryChanged(); + bool isFrameUpdate(); virtual void setDDIScalerEnable(int width, int height); virtual int getDDIScalerMode(int width, int height); @@ -1293,7 +1302,7 @@ class ExynosDisplay { private: bool skipStaticLayerChanged(ExynosCompositionInfo& compositionInfo); - bool skipSignalIdleForVideoLayer(); + bool skipSignalIdle(); /// minimum possible dim rate in the case hbm peak is 1000 nits and norml // display brightness is 2 nits @@ -1589,6 +1598,34 @@ class ExynosDisplay { public: std::unique_ptr<OperationRateManager> mOperationRateManager; bool isOperationRateSupported() { return mOperationRateManager != nullptr; } + + class RefreshRateIndicatorHandler : public DrmSysfsEventHandler { + public: + RefreshRateIndicatorHandler(ExynosDisplay* display); + int32_t init(); + virtual void handleSysfsEvent() override; + virtual int getFd() override { return mFd.get(); }; + bool isIgnoringLastUpdate() { return mIgnoringLastUpdate; } + void updateRefreshRate(int refreshRate); + + private: + void updateRefreshRateLocked(int refreshRate) REQUIRES(mMutex); + + ExynosDisplay* mDisplay; + int mLastRefreshRate GUARDED_BY(mMutex); + nsecs_t mLastCallbackTime GUARDED_BY(mMutex); + std::atomic_bool mIgnoringLastUpdate = false; + UniqueFd mFd; + std::mutex mMutex; + + static constexpr auto kRefreshRateStatePathFormat = + "/sys/class/backlight/panel%d-backlight/state"; + }; + + std::shared_ptr<RefreshRateIndicatorHandler> mRefreshRateIndicatorHandler; + int32_t setRefreshRateChangedCallbackDebugEnabled(bool enabled); + void updateRefreshRateIndicator(); + nsecs_t getLastLayerUpdateTime(); }; #endif //_EXYNOSDISPLAY_H diff --git a/libhwc2.1/libdevice/ExynosLayer.cpp b/libhwc2.1/libdevice/ExynosLayer.cpp index 436f7a2..2c6feaf 100644 --- a/libhwc2.1/libdevice/ExynosLayer.cpp +++ b/libhwc2.1/libdevice/ExynosLayer.cpp @@ -59,6 +59,7 @@ ExynosLayer::ExynosLayer(ExynosDisplay* display) mNextLastFpsTime(0), mLastLayerBuffer(NULL), mLayerBuffer(NULL), + mLastUpdateTime(0), mDamageNum(0), mBlending(HWC2_BLEND_MODE_NONE), mPlaneAlpha(1.0), @@ -419,6 +420,11 @@ int32_t ExynosLayer::setLayerBuffer(buffer_handle_t buffer, int32_t acquireFence Mutex::Autolock lock(mDisplay->mDRMutex); mLayerBuffer = buffer; checkFps(mLastLayerBuffer != mLayerBuffer); + if (mLayerBuffer != mLastLayerBuffer) { + mLastUpdateTime = systemTime(CLOCK_MONOTONIC); + if (mCompositionType != HWC2_COMPOSITION_REFRESH_RATE_INDICATOR) + mDisplay->mBufferUpdates++; + } } mPrevAcquireFence = fence_close(mPrevAcquireFence, mDisplay, FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_UNDEFINED); @@ -1157,8 +1163,10 @@ void ExynosLayer::printLayer() void ExynosLayer::setGeometryChanged(uint64_t changedBit) { + mLastUpdateTime = systemTime(CLOCK_MONOTONIC); mGeometryChanged |= changedBit; - mDisplay->setGeometryChanged(changedBit); + if (mCompositionType != HWC2_COMPOSITION_REFRESH_RATE_INDICATOR) + mDisplay->setGeometryChanged(changedBit); } int ExynosLayer::allocMetaParcel() diff --git a/libhwc2.1/libdevice/ExynosLayer.h b/libhwc2.1/libdevice/ExynosLayer.h index c180fb3..4dc2423 100644 --- a/libhwc2.1/libdevice/ExynosLayer.h +++ b/libhwc2.1/libdevice/ExynosLayer.h @@ -77,6 +77,7 @@ typedef struct pre_processed_layer_info enum { HWC2_COMPOSITION_DISPLAY_DECORATION = toUnderlying(Composition::DISPLAY_DECORATION), + HWC2_COMPOSITION_REFRESH_RATE_INDICATOR = toUnderlying(Composition::REFRESH_RATE_INDICATOR), /*add after hwc2_composition_t, margin number here*/ HWC2_COMPOSITION_EXYNOS = 32, }; @@ -178,6 +179,8 @@ class ExynosLayer : public ExynosMPPSource { */ buffer_handle_t mLayerBuffer; + nsecs_t mLastUpdateTime; + /** * Surface Damage */ diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp index febd76d..eab4cd1 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp +++ b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp @@ -312,3 +312,12 @@ void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleIdleEnterEvent(char primaryDisplay->handleDisplayIdleEnter(idleTeVrefresh); } } + +int32_t ExynosDeviceDrmInterface::registerSysfsEventHandler( + std::shared_ptr<DrmSysfsEventHandler> handler) { + return mDrmDevice->event_listener()->RegisterSysfsHandler(std::move(handler)); +} + +int32_t ExynosDeviceDrmInterface::unregisterSysfsEventHandler(int sysfsFd) { + return mDrmDevice->event_listener()->UnRegisterSysfsHandler(sysfsFd); +} diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h index 9aa2798..69fc4f0 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h +++ b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h @@ -31,6 +31,10 @@ class ExynosDeviceDrmInterface : public ExynosDeviceInterface { virtual int32_t initDisplayInterface( std::unique_ptr<ExynosDisplayInterface> &dispInterface) override; virtual void updateRestrictions() override; + virtual int32_t registerSysfsEventHandler( + std::shared_ptr<DrmSysfsEventHandler> handler) override; + virtual int32_t unregisterSysfsEventHandler(int sysfsFd) override; + protected: class ExynosDrmEventHandler : public DrmEventHandler, public DrmHistogramEventHandler, diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h b/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h index 747f016..dd976b0 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h +++ b/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h @@ -17,8 +17,9 @@ #ifndef _EXYNOSDEVICEINTERFACE_H #define _EXYNOSDEVICEINTERFACE_H -#include "ExynosHWCHelper.h" #include "ExynosDisplayInterface.h" +#include "ExynosHWCHelper.h" +#include "drmeventlistener.h" struct hwc_dpp_size_range { uint32_t min; @@ -82,12 +83,21 @@ class ExynosDeviceInterface { virtual ~ExynosDeviceInterface(){}; virtual void init(ExynosDevice *exynosDevice) = 0; virtual int32_t initDisplayInterface( - std::unique_ptr<ExynosDisplayInterface> &dispInterface) - { return 0;}; + std::unique_ptr<ExynosDisplayInterface> __unused &dispInterface) { + return 0; + }; /* Fill mDPUInfo according to interface type */ virtual void updateRestrictions() = 0; virtual bool getUseQuery() { return mUseQuery; }; + virtual int32_t registerSysfsEventHandler( + std::shared_ptr<DrmSysfsEventHandler> __unused handler) { + return android::INVALID_OPERATION; + } + virtual int32_t unregisterSysfsEventHandler(int __unused sysfsFd) { + return android::INVALID_OPERATION; + } + uint32_t getNumDPPChs() { return mDPUInfo.dpuInfo.dpp_chs.size(); }; uint32_t getNumSPPChs() { return mDPUInfo.dpuInfo.spp_chs.size(); }; uint32_t getSPPChId(uint32_t index) { return mDPUInfo.dpuInfo.spp_chs.at(index).id; }; diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp index 3746a46..7f565e4 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp +++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp @@ -1698,7 +1698,9 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() android::String8 result; bool hasSecureFrameBuffer = false; - mFrameCounter++; + if (mExynosDisplay->isFrameUpdate()) { + mFrameCounter++; + } funcReturnCallback retCallback([&]() { if ((ret == NO_ERROR) && !drmReq.getError()) { mFBManager.flip(hasSecureFrameBuffer); diff --git a/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp b/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp index 3132bc5..bd12d30 100644 --- a/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp +++ b/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp @@ -17,19 +17,21 @@ #define LOG_TAG "hwc-drm-event-listener" #include "drmeventlistener.h" -#include "drmdevice.h" -#include <drm/samsung_drm.h> #include <assert.h> +#include <drm/samsung_drm.h> #include <errno.h> -#include <linux/netlink.h> -#include <sys/socket.h> - #include <hardware/hardware.h> #include <hardware/hwcomposer.h> +#include <inttypes.h> +#include <linux/netlink.h> #include <log/log.h> +#include <sys/socket.h> +#include <utils/String8.h> #include <xf86drm.h> +#include "drmdevice.h" + namespace android { DrmEventListener::DrmEventListener(DrmDevice *drm) @@ -143,6 +145,43 @@ void DrmEventListener::UnRegisterPanelIdleHandler(DrmPanelIdleEventHandler *hand panel_idle_handler_ = NULL; } +int DrmEventListener::RegisterSysfsHandler(std::shared_ptr<DrmSysfsEventHandler> handler) { + if (!handler) + return -EINVAL; + if (handler->getFd() < 0) + return -EINVAL; + std::scoped_lock lock(mutex_); + if (sysfs_handlers_.find(handler->getFd()) != sysfs_handlers_.end()) { + ALOGE("%s: DrmSysfsEventHandler for fd:%d has been added to epoll", __func__, handler->getFd()); + return -EINVAL; + } + + struct epoll_event ev; + ev.events = EPOLLPRI; + ev.data.fd = handler->getFd(); + if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, handler->getFd(), &ev) < 0) { + ALOGE("%s: Failed to add fd into epoll: %s", __func__, strerror(errno)); + return -errno; + } + sysfs_handlers_.emplace(handler->getFd(), std::move(handler)); + return 0; +} + +int DrmEventListener::UnRegisterSysfsHandler(int sysfs_fd) { + std::scoped_lock lock(mutex_); + auto it = sysfs_handlers_.find(sysfs_fd); + if (it == sysfs_handlers_.end()) { + ALOGE("%s: DrmSysfsEventHandler for fd:%d not found", __func__, sysfs_fd); + return -EINVAL; + } + if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, sysfs_fd, nullptr) < 0) { + ALOGE("%s: Failed to remove fd from epoll: %s", __func__, strerror(errno)); + return -errno; + } + sysfs_handlers_.erase(it); + return 0; +} + bool DrmEventListener::IsDrmInTUI() { char buffer[1024]; int ret; @@ -267,6 +306,23 @@ void DrmEventListener::TUIEventHandler() { tui_handler_->handleTUIEvent(); } +void DrmEventListener::SysfsEventHandler(int fd) { + std::shared_ptr<DrmSysfsEventHandler> handler; + { + std::scoped_lock lock(mutex_); + // Copy the shared_ptr to avoid the handler object gets destroyed + // while it's handling the event without holding mutex_ + auto it = sysfs_handlers_.find(fd); + if (it != sysfs_handlers_.end()) + handler = it->second; + } + if (handler) { + handler->handleSysfsEvent(); + } else { + ALOGW("Unhandled sysfs event from fd:%d", fd); + } +} + void DrmEventListener::Routine() { struct epoll_event events[maxFds]; int nfds, n; @@ -280,11 +336,13 @@ void DrmEventListener::Routine() { if (events[n].data.fd == uevent_fd_.get()) { UEventHandler(); } else if (events[n].data.fd == drm_->fd()) { - DRMEventHandler(); + DRMEventHandler(); } } else if (events[n].events & EPOLLPRI) { if (tuievent_fd_.get() >= 0 && events[n].data.fd == tuievent_fd_.get()) { TUIEventHandler(); + } else { + SysfsEventHandler(events[n].data.fd); } } } diff --git a/libhwc2.1/libdrmresource/include/drmeventlistener.h b/libhwc2.1/libdrmresource/include/drmeventlistener.h index 474b116..e85ca0a 100644 --- a/libhwc2.1/libdrmresource/include/drmeventlistener.h +++ b/libhwc2.1/libdrmresource/include/drmeventlistener.h @@ -17,11 +17,13 @@ #ifndef ANDROID_DRM_EVENT_LISTENER_H_ #define ANDROID_DRM_EVENT_LISTENER_H_ +#include <sys/epoll.h> + +#include <map> + #include "autofd.h" #include "worker.h" -#include <sys/epoll.h> - namespace android { class DrmDevice; @@ -62,9 +64,19 @@ class DrmPanelIdleEventHandler { virtual void handleIdleEnterEvent(char const *event) = 0; }; +class DrmSysfsEventHandler { + public: + DrmSysfsEventHandler() {} + virtual ~DrmSysfsEventHandler() {} + + virtual void handleSysfsEvent() = 0; + virtual int getFd() = 0; +}; + class DrmEventListener : public Worker { - static constexpr const char kTUIStatusPath[] = "/sys/devices/platform/exynos-drm/tui_status"; - static const uint32_t maxFds = 3; + static constexpr const char kTUIStatusPath[] = "/sys/devices/platform/exynos-drm/tui_status"; + static const uint32_t maxFds = 4; + public: DrmEventListener(DrmDevice *drm); virtual ~DrmEventListener(); @@ -79,11 +91,13 @@ class DrmEventListener : public Worker { void UnRegisterTUIHandler(DrmTUIEventHandler *handler); void RegisterPanelIdleHandler(DrmPanelIdleEventHandler *handler); void UnRegisterPanelIdleHandler(DrmPanelIdleEventHandler *handler); + int RegisterSysfsHandler(std::shared_ptr<DrmSysfsEventHandler> handler); + int UnRegisterSysfsHandler(int sysfs_fd); bool IsDrmInTUI(); - static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, - unsigned int tv_usec, void *user_data); + static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, + void *user_data); protected: virtual void Routine(); @@ -92,6 +106,7 @@ class DrmEventListener : public Worker { void UEventHandler(); void DRMEventHandler(); void TUIEventHandler(); + void SysfsEventHandler(int fd); UniqueFd epoll_fd_; UniqueFd uevent_fd_; @@ -102,7 +117,10 @@ class DrmEventListener : public Worker { std::unique_ptr<DrmHistogramEventHandler> histogram_handler_; std::unique_ptr<DrmTUIEventHandler> tui_handler_; std::unique_ptr<DrmPanelIdleEventHandler> panel_idle_handler_; + std::mutex mutex_; + std::map<int, std::shared_ptr<DrmSysfsEventHandler>> sysfs_handlers_; }; + } // namespace android #endif diff --git a/libhwc2.1/libhwcService/ExynosHWCService.cpp b/libhwc2.1/libhwcService/ExynosHWCService.cpp index df2d65f..fd8278b 100644 --- a/libhwc2.1/libhwcService/ExynosHWCService.cpp +++ b/libhwc2.1/libhwcService/ExynosHWCService.cpp @@ -503,4 +503,17 @@ int32_t ExynosHWCService::setDisplayMultiThreadedPresent(const int32_t& displayI return NO_ERROR; } +int32_t ExynosHWCService::triggerRefreshRateIndicatorUpdate(uint32_t displayId, + uint32_t refreshRate) { + auto display = mHWCCtx->device->getDisplay(displayId); + + if (display == nullptr) return -EINVAL; + + ALOGD("ExynosHWCService::%s() displayID(%u) refreshRate(%u)", __func__, displayId, refreshRate); + if (display->mRefreshRateIndicatorHandler) { + display->mRefreshRateIndicatorHandler->updateRefreshRate(refreshRate); + } + return NO_ERROR; +} + } //namespace android diff --git a/libhwc2.1/libhwcService/ExynosHWCService.h b/libhwc2.1/libhwcService/ExynosHWCService.h index d9cfe1c..abb525f 100644 --- a/libhwc2.1/libhwcService/ExynosHWCService.h +++ b/libhwc2.1/libhwcService/ExynosHWCService.h @@ -81,6 +81,8 @@ public: virtual int32_t setDisplayMultiThreadedPresent(const int32_t& display_id, const bool& enable) override; + virtual int32_t triggerRefreshRateIndicatorUpdate(uint32_t displayId, + uint32_t refreshRate) override; private: friend class Singleton<ExynosHWCService>; diff --git a/libhwc2.1/libhwcService/IExynosHWC.cpp b/libhwc2.1/libhwcService/IExynosHWC.cpp index 1efe9fc..f092696 100644 --- a/libhwc2.1/libhwcService/IExynosHWC.cpp +++ b/libhwc2.1/libhwcService/IExynosHWC.cpp @@ -65,6 +65,7 @@ enum { TRIGGER_DISPLAY_IDLE_ENTER = 1008, SET_DISPLAY_DBM = 1009, SET_DISPLAY_MULTI_THREADED_PRESENT = 1010, + TRIGGER_REFRESH_RATE_INDICATOR_UPDATE = 1011, }; class BpExynosHWCService : public BpInterface<IExynosHWCService> { @@ -446,7 +447,7 @@ public: data.writeUint32(displayIndex); data.writeUint32(idleTeRefreshRate); - auto result = remote()->transact(SET_DISPLAY_RCDLAYER_ENABLED, data, &reply); + auto result = remote()->transact(TRIGGER_DISPLAY_IDLE_ENTER, data, &reply); ALOGE_IF(result != NO_ERROR, "TRIGGER_DISPLAY_IDLE_ENTER transact error(%d)", result); return result; } @@ -471,6 +472,19 @@ public: if (result) ALOGE("SET_DISPLAY_MULTI_THREADED_PRESENT transact error(%d)", result); return result; } + + virtual int32_t triggerRefreshRateIndicatorUpdate(uint32_t displayId, + uint32_t refreshRate) override { + Parcel data, reply; + data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor()); + data.writeUint32(displayId); + data.writeUint32(refreshRate); + + auto result = remote()->transact(TRIGGER_REFRESH_RATE_INDICATOR_UPDATE, data, &reply); + ALOGE_IF(result != NO_ERROR, "TRIGGER_REFRESH_RATE_INDICATOR_UPDATE transact error(%d)", + result); + return result; + } }; IMPLEMENT_META_INTERFACE(ExynosHWCService, "android.hal.ExynosHWCService"); @@ -734,6 +748,13 @@ status_t BnExynosHWCService::onTransact( return NO_ERROR; } break; + case TRIGGER_REFRESH_RATE_INDICATOR_UPDATE: { + CHECK_INTERFACE(IExynosHWCService, data, reply); + uint32_t displayId = data.readUint32(); + uint32_t refreshRate = data.readUint32(); + return triggerRefreshRateIndicatorUpdate(displayId, refreshRate); + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libhwc2.1/libhwcService/IExynosHWC.h b/libhwc2.1/libhwcService/IExynosHWC.h index 75d95cb..bf51c85 100644 --- a/libhwc2.1/libhwcService/IExynosHWC.h +++ b/libhwc2.1/libhwcService/IExynosHWC.h @@ -76,6 +76,7 @@ public: virtual int32_t setDisplayDbm(int32_t display_id, uint32_t on) = 0; virtual int32_t setDisplayMultiThreadedPresent(const int32_t& displayId, const bool& enable) = 0; + virtual int32_t triggerRefreshRateIndicatorUpdate(uint32_t displayId, uint32_t refreshRate) = 0; }; /* Native Interface */ |