/* 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) 2021. 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. */ #undef LOG_TAG #define LOG_TAG "MSyncSfApi" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "MSyncSfApi.h" #include #include #include #include #include #include "DisplayDevice.h" #include "Layer.h" #include "Scheduler/MessageQueue.h" #include "SurfaceFlinger.h" #include "FrontEnd/LayerHandle.h" #ifdef MTK_COMPOSER_EXT #include #endif #define LIBRARY_NAME "libmtk_sf_msync_2_0.so" using std::endl; namespace android { #ifdef MTK_SF_MSYNC MSyncSfApi::MSyncSfApi(const sp& flinger, bool useList) : mFlinger(flinger) { mSoHandle = dlopen(LIBRARY_NAME, RTLD_LAZY); if (mSoHandle) { int ret = loadMSyncApi(); if (ret) { ALOGE("loadMSyncApi() fail, ret %d", ret); } else { if (mFuncCreateMSyncController) { mMSyncController = mFuncCreateMSyncController(useList, [](const sp& binder) { sp layer = nullptr; if (binder) { layer = LayerHandle::getLayer(binder); } return layer.get(); }, [this](const sp& binder) { if (binder) { return mFlinger->mBufferCountTracker.getBufferCount(binder->localBinder()); } return 0; }, [this](std::function func) { mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) { if (layer->isVisible()) { func(layer); } }); }, [this](std::function func) { std::vector layerPtrs; mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) { if (layer->isVisible() && layer->getType() && strncmp(layer->getType(), "Buffer", strlen("Buffer")) == 0) { const Rect layerScreenBound = layer->getScreenBounds(); const float layerArea = layerScreenBound.getWidth() * layerScreenBound.getHeight(); const auto frameRateSelectionPriority = layer->getFrameRateSelectionPriority(); const bool focused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority); func(layer, layerArea, focused); } }); }, [this]() { if (auto schedule = mFlinger->mScheduler->getVsyncSchedule()) { return schedule->period().ns(); } return static_cast(0); }, [this](bool bTriggerVsyncCallback) { //if (auto schedule = mFlinger->mScheduler->getVsyncSchedule()) { mFlinger->mScheduler->msyncVsyncCallback(bTriggerVsyncCallback); //} }, [this]() { mFlinger->mScheduler->scheduleFrame(); }, [this]() { #ifdef MTK_COMPOSER_EXT if (mFlinger->mMtkComposerExtIntf) { ::ComposerExt::ClientInterface* intf = mFlinger->mMtkComposerExtIntf; const auto hwcDisplayId = mFlinger->getHwComposer().getPrimaryHwcDisplayId(); //if (hwcDisplayId) { int ret = intf->msyncSetEnable(hwcDisplayId, ComposerExt::MSyncEnableType::kOn); ALOGE_IF(ret, "msyncSetEnable kOn fail"); //} else { // ALOGE("internal hwcDisplayId invalid"); //} } #else ALOGE("msync, MTK_COMPOSER_EXT not defined, %p", this); #endif }, [this]() { #ifdef MTK_COMPOSER_EXT if (mFlinger->mMtkComposerExtIntf) { ::ComposerExt::ClientInterface* intf = mFlinger->mMtkComposerExtIntf; const auto hwcDisplayId = mFlinger->getHwComposer().getPrimaryHwcDisplayId(); //if (hwcDisplayId) { int ret = intf->msyncSetEnable(hwcDisplayId, ComposerExt::MSyncEnableType::kOff); ALOGE_IF(ret, "msyncSetEnable kOff fail"); //} else { // ALOGE("internal hwcDisplayId invalid"); //} } #else ALOGE("msync, MTK_COMPOSER_EXT not defined, %p", this); #endif }); } } } else { ALOGE("failed to open library[%s]", LIBRARY_NAME); } } MSyncSfApi::~MSyncSfApi() { if (mMSyncController != nullptr) { mFuncDestroyMSyncController(mMSyncController); } if (mSoHandle != nullptr) { dlclose(mSoHandle); } } void MSyncSfApi::dump(std::string& result) const { if (mFuncDump) { mFuncDump(mMSyncController, result); } } void MSyncSfApi::reloadConfigThenDump(std::string& result) { if (mFuncReloadConfigThenDump) { mFuncReloadConfigThenDump(mMSyncController, result); } } void MSyncSfApi::registerLayer(const Layer* layer) { if (mFuncRegisterLayer) { mFuncRegisterLayer(mMSyncController, layer, layer->getName()); } } void MSyncSfApi::destroyLayer(const Layer* layer) { if (mFuncDestroyLayer) { mFuncDestroyLayer(mMSyncController, layer); } } void MSyncSfApi::commit() { if (mFuncCommit) { mFuncCommit(mMSyncController); } } void MSyncSfApi::composite(sp display, const std::vector>& displays) { if (!mFuncComposite) { return; } //ATRACE_NAME("msync2_sf: composite"); bool hasExternalDisp = false; bool hasGpuVirtualDisp = false; for (auto& disp : displays) { if (disp->isVirtual()) { if (GpuVirtualDisplayId::tryCast(disp->getVirtualId())) { //ALOGI("%s: hasGpuVirtualDisp", __func__); hasGpuVirtualDisp = true; } } else if (!disp->isPrimary()) { // external not support hasExternalDisp = true; break; } } mFuncComposite(mMSyncController, hasExternalDisp, hasGpuVirtualDisp, static_cast(display->getWidth() * display->getHeight())); } bool MSyncSfApi::isOn() const { if (mFuncIsOn) { return mFuncIsOn(mMSyncController); } return false; } void MSyncSfApi::setMSyncEnable(bool enable) { if (mFuncSetMSyncEnable) { mFuncSetMSyncEnable(mMSyncController, enable); } } void MSyncSfApi::setTargetLayer(const void* layerPtr) { if (mFuncSetTargetLayer) { mFuncSetTargetLayer(mMSyncController, layerPtr); } } void MSyncSfApi::setHasOtherUI(bool bHasOtherUI) { if (mFuncSetHasOtherUI) { mFuncSetHasOtherUI(mMSyncController, bHasOtherUI); } } void MSyncSfApi::setPreviousPresentFence(const sp& previousPresentFence) { if (mFuncSetPreviousPresentFence) { mFuncSetPreviousPresentFence(mMSyncController, previousPresentFence); } } void MSyncSfApi::setSFInProgress(bool bSFInProgress) { if (mFuncSetSFInProgress) { mFuncSetSFInProgress(mMSyncController, bSFInProgress); } } bool MSyncSfApi::isQ2QFull() { if (mFuncIsQ2QFull) { return mFuncIsQ2QFull(mMSyncController); } return false; } void MSyncSfApi::setTransactionState(const std::vector, bool, bool, sp>>& states, nsecs_t lastVsyncWakeupTime) { if (!mFuncSetTransactionState) { return; } /*std::vector, bool, bool, sp>> layerStates; for (const Msync2TransactionState& state : states) { //const layer_state_t& s = state.state; layerStates.emplace_back(s.surface, s.hasBufferChanges(), s.bufferData && s.bufferData->flags.test( BufferData::BufferDataChange::fenceChanged), s.bufferData ? s.bufferData->acquireFence : nullptr); sp layer = Layer::fromHandle(s.surface).promote(); std::string result = base::StringPrintf("Msync2: setTransactionState, name=%s, hasBufferChanges=%d", layer->getName().c_str(), s.hasBufferChanges()); ALOGI("%s", result.c_str()); ATRACE_NAME(result.c_str()); }*/ mFuncSetTransactionState(mMSyncController, states, lastVsyncWakeupTime); } void MSyncSfApi::onActiveModeUpdated() { if (mFuncOnActiveModeUpdated) { mFuncOnActiveModeUpdated(mMSyncController); } } void MSyncSfApi::setHasPendingBuffer(const Layer* layer) { if (mFuncSetHasPendingBuffer) { mFuncSetHasPendingBuffer(mMSyncController, layer); } } #define FN_DLSYM(funcVar, funcType, funcName) ({ \ funcVar = reinterpret_cast(dlsym(mSoHandle, funcName)); \ if (funcVar == nullptr) { \ ALOGW("failed to find " funcName); \ return -EFAULT; \ } \ }) \ int MSyncSfApi::loadMSyncApi() { if (mSoHandle != nullptr) { FN_DLSYM(mFuncCreateMSyncController, FuncCreateMSyncController, "createMSyncController"); FN_DLSYM(mFuncDestroyMSyncController, FuncDestroyMSyncController, "destroyMSyncController"); FN_DLSYM(mFuncDump, FuncDump, "dump"); FN_DLSYM(mFuncReloadConfigThenDump, FuncReloadConfigThenDump, "reloadConfigThenDump"); FN_DLSYM(mFuncRegisterLayer, FuncRegisterLayer, "registerLayer"); FN_DLSYM(mFuncDestroyLayer, FuncDestroyLayer, "destroyLayer"); FN_DLSYM(mFuncCommit, FuncCommit, "commit"); FN_DLSYM(mFuncComposite, FuncComposite, "composite"); FN_DLSYM(mFuncSetTransactionState, FuncSetTransactionState, "setTransactionState"); FN_DLSYM(mFuncOnActiveModeUpdated, FuncOnActiveModeUpdated, "onActiveModeUpdated"); FN_DLSYM(mFuncSetHasPendingBuffer, FuncSetHasPendingBuffer, "setHasPendingBuffer"); FN_DLSYM(mFuncIsOn, FuncIsOn, "isOn"); FN_DLSYM(mFuncSetMSyncEnable, FuncSetMSyncEnable, "setMSyncEnable"); FN_DLSYM(mFuncSetTargetLayer, FuncSetTargetLayer, "setTargetLayer"); FN_DLSYM(mFuncSetHasOtherUI, FuncSetHasOtherUI, "setHasOtherUI"); FN_DLSYM(mFuncSetPreviousPresentFence, FuncSetPreviousPresentFence, "setPreviousPresentFence"); FN_DLSYM(mFuncSetSFInProgress, FuncSetSFInProgress, "setSFInProgress"); FN_DLSYM(mFuncIsQ2QFull, FuncIsQ2QFull, "isQ2QFull"); } else { return -ENOENT; } return 0; } void MSyncSfApi::setMSyncParamTable(const Parcel& data) { // adb shell service call SurfaceFlinger 9526104 i32 'number of record' [i32 'level_id' i32 'level_fps' i32 'max_fps' i32 'min_fps'] #ifdef MTK_COMPOSER_EXT if (mFlinger->mMtkComposerExtIntf) { int numRecords = 0; numRecords = data.readInt32(); if (numRecords == 0) { ALOGE("%s: the number of records is 0, just eturn", __func__); return; } ::ComposerExt::ClientInterface* intf = mFlinger->mMtkComposerExtIntf; const auto hwcDisplayId = mFlinger->getHwComposer().getPrimaryHwcDisplayId(); /*if (hwcDisplayId)*/ { ComposerExt::MSyncParamTableStruct mptb; mptb.disp_id = hwcDisplayId; mptb.level_num = static_cast(numRecords); for (int i = 0; i < numRecords; i++) { ComposerExt::MSyncLevelTableStruct mltb; mltb.level_id = static_cast(data.readInt32()); mltb.level_fps = static_cast(data.readInt32()); mltb.max_fps = static_cast(data.readInt32()); mltb.min_fps = static_cast(data.readInt32()); mptb.level_tables.push_back(mltb); } mptb.max_fps = mptb.level_tables[0].max_fps; mptb.min_fps = mptb.level_tables[static_cast(numRecords-1)].min_fps; ALOGI("%s: max_fps=%u, min_fps=%u, level_num=%u", __func__, mptb.max_fps, mptb.min_fps, mptb.level_num); for (size_t i = 0; i < mptb.level_tables.size(); i++) { ALOGI("%s: level_id=%u, level_fps=%u, max_fps=%u, min_fps=%u", __func__, mptb.level_tables[i].level_id, mptb.level_tables[i].level_fps, mptb.level_tables[i].max_fps, mptb.level_tables[i].min_fps); } int ret = intf->msyncSetParamTable(mptb); ALOGE_IF(ret, "%s: msyncSetParamTable fail", __func__); } /*else { ALOGE("%s: internal hwcDisplayId invalid", __func__); }*/ } else { ALOGE("%s: Cannot find hwcomposer ext", __func__); } #else ALOGE("%s: msync, MTK_COMPOSER_EXT not defined", __func__); #endif } void MSyncSfApi::getMSyncParamTable(Parcel* reply) { // adb shell service call SurfaceFlinger 9526105 #ifdef MTK_COMPOSER_EXT if (mFlinger->mMtkComposerExtIntf) { ::ComposerExt::ClientInterface* intf = mFlinger->mMtkComposerExtIntf; const auto hwcDisplayId = mFlinger->getHwComposer().getPrimaryHwcDisplayId(); /*if (hwcDisplayId)*/ { ComposerExt::MSyncParamTableStruct tb; int ret = intf->msyncGetDefaultParamTable(hwcDisplayId, tb); ALOGE_IF(ret, "%s: msyncGetDefaultParamTable fail", __func__); ALOGI("%s: max_fps=%u, min_fps=%u, level_num=%u", __func__, tb.max_fps, tb.min_fps, tb.level_num); if (reply != nullptr) { reply->writeUint32(tb.level_num); } for (size_t i = 0; i < tb.level_tables.size(); i++) { ALOGI("%s: level_id=%u, level_fps=%u, max_fps=%u, min_fps=%u", __func__, tb.level_tables[i].level_id, tb.level_tables[i].level_fps, tb.level_tables[i].max_fps, tb.level_tables[i].min_fps); if (reply != nullptr) { reply->writeUint32(tb.level_tables[i].level_id); reply->writeUint32(tb.level_tables[i].level_fps); reply->writeUint32(tb.level_tables[i].max_fps); reply->writeUint32(tb.level_tables[i].min_fps); } } } /*else { ALOGE("%s: internal hwcDisplayId invalid", __func__); }*/ } else { ALOGE("%s: Cannot find hwcomposer ext", __func__); } #else ALOGE("%s: msync, MTK_COMPOSER_EXT not defined", __func__); #endif } #endif }; // namespace android