423 lines
16 KiB
C++
423 lines
16 KiB
C++
|
|
/* 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 <dlfcn.h>
|
||
|
|
|
||
|
|
#include <binder/IBinder.h>
|
||
|
|
#include <binder/Parcel.h>
|
||
|
|
#include <gui/LayerState.h>
|
||
|
|
#include <ui/Fence.h>
|
||
|
|
|
||
|
|
#include "DisplayDevice.h"
|
||
|
|
#include "Layer.h"
|
||
|
|
#include "Scheduler/MessageQueue.h"
|
||
|
|
#include "SurfaceFlinger.h"
|
||
|
|
|
||
|
|
#ifdef MTK_COMPOSER_EXT
|
||
|
|
#include <composer_ext_intf/client_interface.h>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#define LIBRARY_NAME "libmtk_sf_msync_2_0.so"
|
||
|
|
|
||
|
|
using std::endl;
|
||
|
|
|
||
|
|
namespace android {
|
||
|
|
|
||
|
|
#ifdef MTK_SF_MSYNC
|
||
|
|
|
||
|
|
MSyncSfApi::MSyncSfApi(const sp<SurfaceFlinger>& 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,
|
||
|
|
[this](const sp<IBinder>& binder) {
|
||
|
|
sp<Layer> layer = nullptr;
|
||
|
|
if (binder) {
|
||
|
|
layer = mFlinger->fromHandle(binder).promote();
|
||
|
|
}
|
||
|
|
return layer.get();
|
||
|
|
},
|
||
|
|
[this](std::function<void(const void*)> func) {
|
||
|
|
mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) {
|
||
|
|
if (layer->isVisible()) {
|
||
|
|
func(layer);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
},
|
||
|
|
[this](std::function<void(const void*, float, bool)> func) {
|
||
|
|
std::vector<const void*> 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]() {
|
||
|
|
return mFlinger->mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
|
||
|
|
},
|
||
|
|
[this]() {
|
||
|
|
mFlinger->mEventQueue->msyncTriggerDispatchInvalidate(
|
||
|
|
mFlinger->mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod());
|
||
|
|
},
|
||
|
|
[this]() {
|
||
|
|
mFlinger->mEventQueue->invalidate();
|
||
|
|
},
|
||
|
|
[this]() {
|
||
|
|
#ifdef MTK_COMPOSER_EXT
|
||
|
|
if (mFlinger->mMtkComposerExtIntf) {
|
||
|
|
::ComposerExt::ClientInterface* intf = mFlinger->mMtkComposerExtIntf;
|
||
|
|
const auto hwcDisplayId = mFlinger->getHwComposer().getInternalHwcDisplayId();
|
||
|
|
|
||
|
|
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().getInternalHwcDisplayId();
|
||
|
|
|
||
|
|
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::onMessageInvalidate() {
|
||
|
|
if (mFuncOnMessageInvalidate) {
|
||
|
|
mFuncOnMessageInvalidate(mMSyncController);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void MSyncSfApi::onMessageRefresh(sp<const DisplayDevice> display,
|
||
|
|
const std::vector<sp<DisplayDevice>>& displays) {
|
||
|
|
if (!mFuncOnMessageRefresh) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
ATRACE_CALL();
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
mFuncOnMessageRefresh(mMSyncController,
|
||
|
|
hasExternalDisp,
|
||
|
|
hasGpuVirtualDisp,
|
||
|
|
static_cast<uint32_t>(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<Fence>& previousPresentFence) {
|
||
|
|
if (mFuncSetPreviousPresentFence) {
|
||
|
|
mFuncSetPreviousPresentFence(mMSyncController, previousPresentFence);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void MSyncSfApi::setTransactionState(const Vector<ComposerState>& states) {
|
||
|
|
if (!mFuncSetTransactionState) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<std::tuple<sp<IBinder>, bool, bool, sp<Fence>>> layerStates;
|
||
|
|
for (const ComposerState& state : states) {
|
||
|
|
const layer_state_t& s = state.state;
|
||
|
|
|
||
|
|
layerStates.emplace_back(s.surface,
|
||
|
|
s.hasBufferChanges(),
|
||
|
|
s.what & layer_state_t::eAcquireFenceChanged,
|
||
|
|
s.acquireFence);
|
||
|
|
}
|
||
|
|
mFuncSetTransactionState(mMSyncController, layerStates);
|
||
|
|
}
|
||
|
|
|
||
|
|
void MSyncSfApi::requestInvalidate() {
|
||
|
|
if (mFuncRequestInvalidate) {
|
||
|
|
mFuncRequestInvalidate(mMSyncController);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
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<funcType>(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(mFuncOnMessageInvalidate, FuncOnMessageInvalidate, "onMessageInvalidate");
|
||
|
|
FN_DLSYM(mFuncOnMessageRefresh, FuncOnMessageRefresh, "onMessageRefresh");
|
||
|
|
FN_DLSYM(mFuncSetTransactionState, FuncSetTransactionState, "setTransactionState");
|
||
|
|
FN_DLSYM(mFuncRequestInvalidate, FuncRequestInvalidate, "requestInvalidate");
|
||
|
|
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");
|
||
|
|
} 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().getInternalHwcDisplayId();
|
||
|
|
if (hwcDisplayId) {
|
||
|
|
ComposerExt::MSyncParamTableStruct mptb;
|
||
|
|
mptb.disp_id = *hwcDisplayId;
|
||
|
|
mptb.level_num = static_cast<uint32_t>(numRecords);
|
||
|
|
|
||
|
|
for (int i = 0; i < numRecords; i++) {
|
||
|
|
ComposerExt::MSyncLevelTableStruct mltb;
|
||
|
|
mltb.level_id = static_cast<uint32_t>(data.readInt32());
|
||
|
|
mltb.level_fps = static_cast<uint32_t>(data.readInt32());
|
||
|
|
mltb.max_fps = static_cast<uint32_t>(data.readInt32());
|
||
|
|
mltb.min_fps = static_cast<uint32_t>(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<size_t>(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().getInternalHwcDisplayId();
|
||
|
|
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
|