/* 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" #ifdef MTK_COMPOSER_EXT #include #endif #ifdef MTK_SF_MSYNC #include "mediatek/MSync/MSyncSfApi.h" #endif #ifdef MTK_SF_CPU_POLICY #include "mediatek/SfCpuPolicyAdapter/SfCpuPolicyAdapter.h" #endif #ifdef MTK_SF_OVL_ONLY_FOR_WIFI_DISPLAY // This name will send form WifiDisplayAdapter.java // function name "addDisplayDeviceLocked" to create WFD #define WIFI_DISPLAY_PATTERN "isWifiDpyForHWC" #endif #ifdef MTK_SF_NOTIFY_EXPECTED_PRESENT_TIME #ifdef MTK_COMPOSER_EXT #include "Layer.h" static std::vector gEarlyPresentList = { "com.tencent.tmgp.pubgmhd" // , "com.tencent.tmgp" // , "com.tencent.lolm" // , "com.miHoYo" // , "com.netease.hyxd" // , "com.oplus.camera" }; #endif #endif namespace android { #ifdef MTK_SF_OVL_ONLY_FOR_WIFI_DISPLAY bool SurfaceFlinger::specificKindDisplay(const std::string& dpyName) const { if (mOvlOnlyForWifiDisplay == false) { return false; } // For Wifi display if (std::string::npos != dpyName.find(WIFI_DISPLAY_PATTERN)) { ALOGI("%s dpyName:%s is WIFI display", __func__, dpyName.c_str()); return true; } else { ALOGI("%s dpyName:%s is not WIFI display", __func__, dpyName.c_str()); } return false; } #endif #ifdef MTK_SF_DEBUG_SUPPORT void SurfaceFlinger::mtkDump(std::string& result) { // for run-time enable property SFProperty::getInstance().setMTKProperties(result, mDebugRegion); } 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; } #endif #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); } void NotifyHwcHwBinderTidCallback(int tid) { ALOGI("NotifyHwcHwBinderTidCallback, %p, tid %d", &mFlinger, tid); #ifdef MTK_SF_CPU_POLICY mFlinger.notifyHwcHwbinderTid(tid); #endif } private: SurfaceFlinger& mFlinger; }; MtkComposerExtCallbackHandler* mMtkComposerExtCallbackHandler = nullptr; void SurfaceFlinger::initMtkComposerExt() { if (mMtkComposerExtIntf) { return; } mMtkComposerExtCallbackHandler = new MtkComposerExtCallbackHandler(*this); int ret = ::ComposerExt::ClientInterface::create("SurfaceFlinger" + std::to_string(0), mMtkComposerExtCallbackHandler, &mMtkComposerExtIntf); if (ret || !mMtkComposerExtIntf) { ALOGE("ComposerExt HIDL not present\n"); mMtkComposerExtIntf = nullptr; } } #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_ATRACE_PRESENT_FENCE class FenceMonitor { public: explicit FenceMonitor(const char* name) : mName(name) { std::thread thread(&FenceMonitor::loop, this); pthread_setname_np(thread.native_handle(), mName); thread.detach(); } void queueFence(const sp& fence) { char message[64]; std::lock_guard lock(mMutex); if (fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) { snprintf(message, sizeof(message), "%s fence %d has signaled", mName, fence->get()); ATRACE_NAME(message); // Need an increment on both to make the trace number correct. return; } snprintf(message, sizeof(message), "Trace %s fence %d", mName, fence->get()); ATRACE_NAME(message); mQueue.push_back(fence); mCondition.notify_one(); ATRACE_INT(mName, int32_t(mQueue.size())); } private: #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-noreturn" void loop() { while (true) { threadLoop(); } } #pragma clang diagnostic pop void threadLoop() { sp fence; { std::unique_lock lock(mMutex); while (mQueue.empty()) { mCondition.wait(lock); } fence = mQueue[0]; } { char message[64]; snprintf(message, sizeof(message), "waiting for %s %d", mName, fence->get()); ATRACE_NAME(message); status_t result = fence->waitForever(message); if (result != OK) { ALOGE("Error waiting for fence: %d", result); } } { std::lock_guard lock(mMutex); mQueue.pop_front(); ATRACE_INT(mName, int32_t(mQueue.size())); } } const char* mName; std::deque> mQueue; std::condition_variable mCondition; std::mutex mMutex; }; void SurfaceFlinger::trackPresentFence(const sp& fence) { static FenceMonitor presentFenceMonitor("presentFence"); presentFenceMonitor.queueFence(fence); } #endif #ifdef MTK_SF_HINT_DISPLAY_INFO void SurfaceFlinger::hintDisplayInfo(const int& policy, const bool& enable) { switch(policy) { case Hwc2::impl::PowerAdvisor::MULTI_DISPLAY: { const auto defaultdisplay = getDefaultDisplayDeviceLocked(); if (defaultdisplay && mRefreshRateConfigs) { int32_t fps = static_cast(mRefreshRateConfigs->getRefreshRateFromModeId( defaultdisplay->getActiveMode()->getId()).getFps().getIntValue()); mPowerAdvisor.hintMultiDisplay(enable, fps); } break; } } } #endif #ifdef MTK_SF_MSYNC bool SurfaceFlinger::isMsyncOn() const { return mMSyncSfApi && mMSyncSfApi->isOn(); } #endif #ifdef MTK_COMPOSER_EXT #ifdef MTK_SF_CPU_POLICY void SurfaceFlinger::notifyHwcHwbinderTid(const int& tid) { if (SfCpuPolicyAdapter::isEnabled()) { SfCpuPolicyAdapter::getInstance(*mFrameTimeline).notifyHwcHwbinderTid(tid); } } #endif #endif #ifdef MTK_SF_CPU_POLICY void SurfaceFlinger::notifyVpLpEnable(bool enable) { if (SfCpuPolicyAdapter::isEnabled()) { SfCpuPolicyAdapter::getInstance(*mFrameTimeline).notifyVpLpEnable(enable); } } void SurfaceFlinger::notifyLayerConnect(const void * token, const std::string& name){ if (SfCpuPolicyAdapter::isEnabled()) { SfCpuPolicyAdapter::getInstance(*mFrameTimeline).notifyLayerConnect(token, name); } } void SurfaceFlinger::notifyLayerDisconnect(const void * token) { if (SfCpuPolicyAdapter::isEnabled()) { SfCpuPolicyAdapter::getInstance(*mFrameTimeline).notifyLayerDisconnect(token); } } void SurfaceFlinger::notifyLayerSetBuffer(const void * token, const sp& buffer){ if (SfCpuPolicyAdapter::isEnabled()) { SfCpuPolicyAdapter::getInstance(*mFrameTimeline).notifyLayerSetBuffer(token, buffer); } } #endif #ifdef MTK_SF_NOTIFY_EXPECTED_PRESENT_TIME #ifdef MTK_COMPOSER_EXT bool SurfaceFlinger::needSkipNotifyPresentTime(Layer *layer) { if (layer == nullptr) { ALOGE("needSkipNotifyPresentTime layer should not be null"); return false; } if (layer->getDebugName() == nullptr) { ALOGE("needSkipNotifyPresentTime layer name should not be null"); return false; } if (layer->getNotifyState() == Layer::NotifyState::UNKNOWN) { layer->setNotifyState(Layer::NotifyState::NOTIFY); for (const auto& name : gEarlyPresentList) { if (strstr(layer->getDebugName(), name) != nullptr) { layer->setNotifyState(Layer::NotifyState::SKIP); break; } } } if (layer->getNotifyState() == Layer::NotifyState::NOTIFY) { return false; } else { return true; } } #endif #endif }; // namespace android