/* Copyright Statement: * * This software/firmware and related documentation ("MediaTek Software") are * protected under relevant copyright laws. The information contained herein is * confidential and proprietary to MediaTek Inc. and/or its licensors. Without * the prior written permission of MediaTek inc. and/or its licensors, any * reproduction, modification, use or disclosure of MediaTek Software, and * information contained herein, in whole or in part, shall be strictly * prohibited. * * MediaTek Inc. (C) 2010. All rights reserved. * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. * * The following software/firmware and/or related documentation ("MediaTek * Software") have been modified by MediaTek Inc. All revisions are subject to * any receiver's applicable license agreements with MediaTek Inc. */ //#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "SurfaceFlinger.h" #include "mediatek/SFProperty.h" #include #include #ifdef MTK_COMPOSER_EXT #include #endif #if ((defined MTK_SF_CPU_POLICY) || (defined MTK_SF_CPU_POLICY_FOR_LEGACY)) #include "mediatek/SfCpuPolicyAdapter/SfCpuPolicyAdapter.h" #endif #ifdef MTK_SF_DEBUG_SUPPORT #include #include "Layer.h" #endif #ifdef MTK_SF_MSYNC #include "mediatek/MSync/MSyncSfApi.h" #endif #ifdef MTK_DYNAMIC_DURATION #include #endif #ifdef MTK_SF_KICK_IDLE #include "mediatek/KickIdleHelper.h" #endif namespace android { #ifdef MTK_COMPOSER_EXT class MtkComposerExtCallbackHandler : public ::ComposerExt::ConfigCallback { public: MtkComposerExtCallbackHandler(SurfaceFlinger& flinger) : mFlinger(flinger) { } void NotifyTestCallback(bool value) { ALOGI("NotifyTestCallback, %p, value %d", &mFlinger, value); } bool NotifyTestCallbackWithReturnValue(bool value) { ALOGI("NotifyTestCallbackWithReturnValue, %p, value %d", &mFlinger, value); return value; } void NotifyHwcHwBinderTidCallback(int tid) { ALOGI("NotifyHwcHwBinderTidCallback, %p, tid %d", &mFlinger, tid); #if ((defined MTK_SF_CPU_POLICY) || (defined MTK_SF_CPU_POLICY_FOR_LEGACY)) mFlinger.notifyHwcHwbinderTid(tid); #endif } void NotifyHwcComposition(ComposerExt::HwcCompositionStruct composition) { ALOGI("%s(), id %" PRIu64 ", mode %d", __FUNCTION__, composition.disp_id, composition.composition_mode); ATRACE_NAME(android::base::StringPrintf("MBRAIN: NotifyHwcComposition(), id %" PRIu64 ", mode %d", composition.disp_id, composition.composition_mode).c_str()); #ifdef MTK_DYNAMIC_DURATION MtkDuration::getInstance().setDecoupleMode(static_cast(composition.disp_id) , static_cast(composition.composition_mode) > 0 ? true : false); #endif } uint32_t NotifyExtraVsyncPresent(const ComposerExt::ExtraVsyncRequestStruct& request) { ALOGI("disp_id =%" PRIu64 ", num_vsync=%" PRIu32, request.disp_id, request.num_vsync); ATRACE_NAME(android::base::StringPrintf("MBRAIN: NotifyExtraVsyncPresent(), disp_id =%" PRIu64 ", num_vsync=%" PRIu32, request.disp_id, request.num_vsync).c_str()); for (const auto& layerId: request.layer_id) { ALOGV("layerId=%" PRIu64, layerId); } #ifdef MTK_DYNAMIC_DURATION return MtkDuration::getInstance().setExtraVsyncCount(request.disp_id, request.num_vsync); #else return request.num_vsync; #endif } private: SurfaceFlinger& mFlinger; }; MtkComposerExtCallbackHandler* mMtkComposerExtCallbackHandler = nullptr; void SurfaceFlinger::initMtkComposerExt() { mMtkComposerExtCallbackHandler = new MtkComposerExtCallbackHandler(*this); int ret = ::ComposerExt::ClientInterface::create("SurfaceFlinger" + std::to_string(0), mMtkComposerExtCallbackHandler, &mMtkComposerExtIntf, false); if (ret || !mMtkComposerExtIntf) { ALOGE("ComposerExt HIDL not present\n"); mMtkComposerExtIntf = nullptr; } #ifdef MTK_SF_KICK_IDLE if (mMtkComposerExtIntf != nullptr) { KickIdleHelper::getInstance().setComposerExtInf((void*) mMtkComposerExtIntf); } #endif #ifdef MTK_DYNAMIC_DURATION if (mMtkComposerExtIntf != nullptr) { int isExtraVsyncSupported = 0; mMtkComposerExtIntf->isFeatureSupported(ComposerExt::HwcFeature::kExtraVsyncPresent, &isExtraVsyncSupported); ALOGI("isExtraVsyncSupported %s", isExtraVsyncSupported ? "yes" : "no"); MtkDuration::getInstance().setIsExtraVsyncSupported(isExtraVsyncSupported > 0); } #endif } #endif #ifdef MTK_COMPOSER_EXT #if ((defined MTK_SF_CPU_POLICY) || (defined MTK_SF_CPU_POLICY_FOR_LEGACY)) void SurfaceFlinger::notifyHwcHwbinderTid(const int& tid) { if (mSfCpuPolicy) { mSfCpuPolicy->notifyHwcHwbinderTid(tid); } } #endif #endif #if ((defined MTK_SF_CPU_POLICY) || (defined MTK_SF_CPU_POLICY_FOR_LEGACY)) void SurfaceFlinger::notifyVpLpEnable(bool enable) { if (mSfCpuPolicy) { mSfCpuPolicy->notifyVpLpEnable(enable); } } void SurfaceFlinger::notifyLayerConnect(const void * token, const std::string& name){ if (mSfCpuPolicy) { mSfCpuPolicy->notifyLayerConnect(token, name); } } void SurfaceFlinger::notifyLayerDisconnect(const void * token) { if (mSfCpuPolicy) { mSfCpuPolicy->notifyLayerDisconnect(token); } } void SurfaceFlinger::notifyLayerSetBuffer(const void * token, const sp& buffer){ if (mSfCpuPolicy) { mSfCpuPolicy->notifyLayerSetBuffer(token, buffer); } } #endif #ifdef MTK_SF_DEBUG_SUPPORT void SurfaceFlinger::mtkDump(std::string& result) { // for run-time enable property SFProperty::getInstance().setMTKProperties(result); } void SurfaceFlinger::mtkDumpLayerDebug(std::string& result) const { ALOGI("mtkDumpLayerDebug"); for (const auto& [token, display] : mDisplays) { const DisplayDevice* disp_ref = display.get(); mDrawingState.traverseInZOrder([&](Layer* layer) { gui::LayerDebugInfo ldi = layer->getLayerDebugInfo(disp_ref); base::StringAppendF(&result, "%s", to_string(ldi).c_str());}); } } status_t SurfaceFlinger::getProcessName(int pid, std::string& name) { FILE *fp = fopen(String8::format("/proc/%d/cmdline", pid), "r"); if (fp != NULL) { const size_t size = 64; char proc_name[size] = {0}; char* result = fgets(proc_name, size - 1, fp); int ret = fclose(fp); if (CC_UNLIKELY(ret != 0)) { ALOGE("%s(), fclose fail", __FUNCTION__); } if (CC_LIKELY(result != nullptr)) { name = proc_name; return NO_ERROR; } } return INVALID_OPERATION; } bool SurfaceFlinger::mtkCheckTransactCodeCredentials(uint32_t code) { switch (code) { case 100001: case 100002: return true; default: break; } return false; } bool SurfaceFlinger::mtkIsTransact(uint32_t code) { switch (code) { case 100001: case 100002: return true; default: break; } return false; } status_t SurfaceFlinger::mtkOnTransact(uint32_t code, const Parcel& data, Parcel* /*reply*/, uint32_t /*flags*/) { switch (code) { case 100001: { int n = data.readInt32(); ALOGI("mtkOnTransact(%u) n=%d", code, n); break; } case 100002: { const int isDumpLayers = data.readInt32(); if (isDumpLayers == 0) { mIsDumpLayers = false; } else { mIsDumpLayers = true; } break; } default: break; } return NO_ERROR; } void SurfaceFlinger::BufferCountTracker::unTrack(Layer* layer) { std::lock_guard lock(mLock); if (0 == mWhereByLayer.erase(layer)) { ALOGE("LayerTracker: not in map, name=%s, HandleAlive=%d", layer->getName().c_str(), layer->isHandleAlive()); } } void SurfaceFlinger::BufferCountTracker::dumpLayers() { static nsecs_t sLastDumpLayerTrackerTime = 0; nsecs_t now = systemTime(); if (ns2ms(now - sLastDumpLayerTrackerTime) > 15000) { sLastDumpLayerTrackerTime = now; std::lock_guard lock(mLock); std::vector vecDumpString; for (auto [layer, where] : mWhereByLayer) { vecDumpString.push_back(android::base::StringPrintf("LayerTracker: %s, Where: %s, HandleAlive=%d", layer->getName().c_str(), where.c_str(), layer->isHandleAlive())); } std::thread thread([=]() { for (auto dumpString : vecDumpString) { ALOGE("%s", dumpString.c_str()); } }); thread.detach(); } } #endif #ifdef MTK_SF_MSYNC_3 void SurfaceFlinger::changeToForeground() { #ifdef MTK_SF_CPU_POLICY if (SfCpuPolicyAdapter::isEnabled()) { ATRACE_NAME("SF: changeToForeground & notifySpeedUpRE"); SfCpuPolicyAdapter::getInstance(*mFrameTimeline).changeToForeground(); // 370 is upper bound for uclmap.min perf range 0-1024 SfCpuPolicyAdapter::getInstance(*mFrameTimeline).notifySpeedUpRE(370); } #endif } #endif #ifdef MTK_SF_HINT_DISPLAY_INFO void SurfaceFlinger::hintDisplayInfo(const int& policy, const bool& enable) { switch(policy) { case Hwc2::impl::PowerAdvisor::MULTI_DISPLAY: { mPowerAdvisor->hintMultiDisplay(enable, mHintFps); break; } } } #endif #ifdef MTK_SF_HINT_LOW_POWER #include void SurfaceFlinger::hintLowPower(bool enabled) { mPowerAdvisor->hintSFLowPower(enabled); const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); if (display) { display->changeRefreshRate(enabled); } } bool SurfaceFlinger::setPELT32(bool enabled) { return mScheduler->setPELT32(enabled); } #endif #ifdef MTK_VDS_HDCP void SurfaceFlinger::setNextDisplayUsage(bool isWFD, bool isSecure) { ALOGV("setNextDisplayUsage %d, %d", (isWFD?1:0), (isSecure?1:0)); #ifdef MTK_COMPOSER_EXT if (mMtkComposerExtIntf) { uint32_t vdsUsage = static_cast(ComposerExt::DisplayUsage::kUnknown); if (isWFD) vdsUsage |= static_cast(ComposerExt::DisplayUsage::kIsWFD); if (isSecure) vdsUsage |= static_cast(ComposerExt::DisplayUsage::kIsSecure); mMtkComposerExtIntf->setNextDisplayUsage(static_cast(vdsUsage)); ALOGI("mMtkComposerExtIntf->setNextDisplayUsage(%" PRIu32 ")", vdsUsage); } else { ALOGI("mMtkComposerExtIntf null"); } #endif } #endif #ifdef MTK_SF_UPDATE_DISPLAY_CAP bool SurfaceFlinger::updateDisplayCapability() { static bool supportDsiSwitch = base::GetBoolProperty("ro.vendor.mtk_hwc_dsi_switch", false); if (!supportDsiSwitch) return false; ATRACE_CALL(); for (const auto& [token, display] : mDisplays) { if (const auto halDispId = HalDisplayId::tryCast(display->getId())) { getHwComposer().updateDisplayCapability(halDispId.value()); } else { ALOGE("!halDispId"); } } return true; } #endif #ifdef MTK_SF_MSYNC bool SurfaceFlinger::isMsyncOn() const { return mMSyncSfApi && mMSyncSfApi->isOn(); } #endif #ifdef MTK_SF_GUI_DEBUG_SUPPORT void SurfaceFlinger::fastMtkDumpLayerDebug(std::vector& layerInfo) const { ALOGI("fastMtkDumpLayerDebug"); for (const auto& [token, display] : mDisplays) { const DisplayDevice* disp_ref = display.get(); mDrawingState.traverseInZOrder([&](Layer* layer) { gui::LayerDebugInfo ldi = layer->getLayerDebugInfo(disp_ref); layerInfo.push_back(ldi);}); } } #endif #ifdef MTK_SF_MBRAIN_FPS_SUPPORT int64_t SurfaceFlinger::getDisplayFrameCount() const { return mDisplayFrameCount; } #endif }; // namespace android