1
0
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2588 lines
102 KiB

/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Project HWC 2.0 Design
*/
#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
#include "ExynosResourceManager.h"
#include <cutils/properties.h>
#include <numeric>
#include <unordered_set>
#include "ExynosDeviceInterface.h"
#include "ExynosExternalDisplay.h"
#include "ExynosHWCDebug.h"
#include "ExynosLayer.h"
#include "ExynosMPPModule.h"
#include "ExynosPrimaryDisplayModule.h"
#include "ExynosVirtualDisplay.h"
#include "hardware/exynos/acryl.h"
using namespace std::chrono_literals;
constexpr float msecsPerSec = std::chrono::milliseconds(1s).count();
#ifndef USE_MODULE_ATTR
/* Basic supported features */
feature_support_t feature_table[] =
{
{MPP_DPP_G,
MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM
},
{MPP_DPP_GF,
MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM
},
{MPP_DPP_VG,
MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM
},
{MPP_DPP_VGS,
MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_SCALE | MPP_ATTR_DIM
},
{MPP_DPP_VGF,
MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM
},
{MPP_DPP_VGFS,
MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_SCALE | MPP_ATTR_DIM
},
{MPP_DPP_VGRFS,
MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_SCALE |
MPP_ATTR_FLIP_H | MPP_ATTR_FLIP_V | MPP_ATTR_ROT_90 |
MPP_ATTR_DIM | MPP_ATTR_HDR10
},
{MPP_MSC,
MPP_ATTR_FLIP_H | MPP_ATTR_FLIP_V | MPP_ATTR_ROT_90
},
{MPP_G2D,
MPP_ATTR_AFBC | MPP_ATTR_FLIP_H | MPP_ATTR_FLIP_V | MPP_ATTR_ROT_90 |
MPP_ATTR_HDR10 | MPP_ATTR_USE_CAPA
}
};
#endif
using namespace android;
using namespace vendor::graphics;
using namespace SOC_VERSION;
ExynosMPPVector ExynosResourceManager::mOtfMPPs;
ExynosMPPVector ExynosResourceManager::mM2mMPPs;
extern struct exynos_hwc_control exynosHWCControl;
ExynosMPPVector::ExynosMPPVector() {
}
ExynosMPPVector::ExynosMPPVector(const ExynosMPPVector& rhs)
: android::SortedVector<ExynosMPP* >(rhs) {
}
int ExynosMPPVector::do_compare(const void* lhs, const void* rhs) const
{
if (lhs == NULL || rhs == NULL)
return 0;
const ExynosMPP* l = *((ExynosMPP**)(lhs));
const ExynosMPP* r = *((ExynosMPP**)(rhs));
if (l == NULL || r == NULL)
return 0;
if (l->mPhysicalType != r->mPhysicalType) {
return l->mPhysicalType - r->mPhysicalType;
}
if (l->mLogicalType != r->mLogicalType) {
return l->mLogicalType - r->mLogicalType;
}
if (l->mPhysicalIndex != r->mPhysicalIndex) {
return l->mPhysicalIndex - r->mPhysicalIndex;
}
return l->mLogicalIndex - r->mLogicalIndex;
}
/**
* ExynosResourceManager implementation
*
*/
ExynosResourceManager::DstBufMgrThread::DstBufMgrThread(ExynosResourceManager *exynosResourceManager)
: mExynosResourceManager(exynosResourceManager),
mRunning(false),
mBufXres(0),
mBufYres(0)
{
}
ExynosResourceManager::DstBufMgrThread::~DstBufMgrThread()
{
}
ExynosResourceManager::ExynosResourceManager(ExynosDevice *device)
: mForceReallocState(DST_REALLOC_DONE),
mDevice(device),
hasHdrLayer(false),
hasDrmLayer(false),
mFormatRestrictionCnt(0),
mDstBufMgrThread(sp<DstBufMgrThread>::make(this)),
mResourceReserved(0x0)
{
memset(mSizeRestrictionCnt, 0, sizeof(mSizeRestrictionCnt));
memset(mFormatRestrictions, 0, sizeof(mFormatRestrictions));
memset(mSizeRestrictions, 0, sizeof(mSizeRestrictions));
size_t num_mpp_units = sizeof(AVAILABLE_OTF_MPP_UNITS)/sizeof(exynos_mpp_t);
for (size_t i = 0; i < num_mpp_units; i++) {
exynos_mpp_t exynos_mpp = AVAILABLE_OTF_MPP_UNITS[i];
ALOGI("otfMPP type(%d, %d), physical_index(%d), logical_index(%d)",
exynos_mpp.physicalType, exynos_mpp.logicalType,
exynos_mpp.physical_index, exynos_mpp.logical_index);
ExynosMPP* exynosMPP = new ExynosMPPModule(this, exynos_mpp.physicalType,
exynos_mpp.logicalType, exynos_mpp.name, exynos_mpp.physical_index,
exynos_mpp.logical_index, exynos_mpp.pre_assign_info);
exynosMPP->mMPPType = MPP_TYPE_OTF;
mOtfMPPs.add(exynosMPP);
}
num_mpp_units = sizeof(AVAILABLE_M2M_MPP_UNITS)/sizeof(exynos_mpp_t);
for (size_t i = 0; i < num_mpp_units; i++) {
exynos_mpp_t exynos_mpp = AVAILABLE_M2M_MPP_UNITS[i];
ALOGI("m2mMPP type(%d, %d), physical_index(%d), logical_index(%d)",
exynos_mpp.physicalType, exynos_mpp.logicalType,
exynos_mpp.physical_index, exynos_mpp.logical_index);
ExynosMPP* exynosMPP = new ExynosMPPModule(this, exynos_mpp.physicalType,
exynos_mpp.logicalType, exynos_mpp.name, exynos_mpp.physical_index,
exynos_mpp.logical_index, exynos_mpp.pre_assign_info);
exynosMPP->mMPPType = MPP_TYPE_M2M;
mM2mMPPs.add(exynosMPP);
}
ALOGI("mOtfMPPs(%zu), mM2mMPPs(%zu)", mOtfMPPs.size(), mM2mMPPs.size());
if (hwcCheckDebugMessages(eDebugResourceManager)) {
for (uint32_t i = 0; i < mOtfMPPs.size(); i++)
{
HDEBUGLOGD(eDebugResourceManager, "otfMPP[%d]", i);
String8 dumpMPP;
mOtfMPPs[i]->dump(dumpMPP);
HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
}
for (uint32_t i = 0; i < mM2mMPPs.size(); i++)
{
HDEBUGLOGD(eDebugResourceManager, "m2mMPP[%d]", i);
String8 dumpMPP;
mM2mMPPs[i]->dump(dumpMPP);
HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
}
}
mDstBufMgrThread->mRunning = true;
mDstBufMgrThread->run("DstBufMgrThread");
}
ExynosResourceManager::~ExynosResourceManager()
{
for (int32_t i = mOtfMPPs.size(); i-- > 0;) {
ExynosMPP *exynosMPP = mOtfMPPs[i];
delete exynosMPP;
}
mOtfMPPs.clear();
for (int32_t i = mM2mMPPs.size(); i-- > 0;) {
ExynosMPP *exynosMPP = mM2mMPPs[i];
delete exynosMPP;
}
mM2mMPPs.clear();
mDstBufMgrThread->mRunning = false;
mDstBufMgrThread->requestExitAndWait();
}
void ExynosResourceManager::reloadResourceForHWFC()
{
for (int32_t i = mM2mMPPs.size(); i-- > 0;) {
ExynosMPP *exynosMPP = mM2mMPPs[i];
if (exynosMPP->mLogicalType == MPP_LOGICAL_G2D_COMBO &&
(exynosMPP->mPreAssignDisplayInfo & HWC_DISPLAY_VIRTUAL_BIT)) {
exynosMPP->reloadResourceForHWFC();
break;
}
}
}
void ExynosResourceManager::setTargetDisplayLuminance(uint16_t min, uint16_t max)
{
for (int32_t i = mM2mMPPs.size(); i-- > 0;) {
ExynosMPP *exynosMPP = mM2mMPPs[i];
if (exynosMPP->mLogicalType == MPP_LOGICAL_G2D_COMBO &&
(exynosMPP->mPreAssignDisplayInfo & HWC_DISPLAY_VIRTUAL_BIT)) {
exynosMPP->setTargetDisplayLuminance(min, max);
break;
}
}
}
void ExynosResourceManager::setTargetDisplayDevice(int device)
{
for (int32_t i = mM2mMPPs.size(); i-- > 0;) {
ExynosMPP *exynosMPP = mM2mMPPs[i];
if (exynosMPP->mLogicalType == MPP_LOGICAL_G2D_COMBO &&
(exynosMPP->mPreAssignDisplayInfo & HWC_DISPLAY_VIRTUAL_BIT)) {
exynosMPP->setTargetDisplayDevice(device);
break;
}
}
}
int32_t ExynosResourceManager::doPreProcessing()
{
int32_t ret = NO_ERROR;
/* Assign m2mMPP's out buffers */
ExynosDisplay *display = mDevice->getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0));
if (display == NULL)
return -EINVAL;
ret = doAllocDstBufs(display->mXres, display->mYres);
return ret;
}
void ExynosResourceManager::doReallocDstBufs(uint32_t Xres, uint32_t Yres)
{
HDEBUGLOGD(eDebugBuf, "M2M dst alloc call ");
mDstBufMgrThread->reallocDstBufs(Xres, Yres);
}
bool ExynosResourceManager::DstBufMgrThread::needDstRealloc(uint32_t Xres, uint32_t Yres, ExynosMPP *m2mMPP)
{
bool ret = false;
if (((Xres == 720 && Yres == 1480) && (m2mMPP->getDstAllocSize() != DST_SIZE_HD_PLUS)) ||
((Xres == 720 && Yres == 1280) && (m2mMPP->getDstAllocSize() != DST_SIZE_HD)) ||
((Xres == 1080 && Yres == 2220) && (m2mMPP->getDstAllocSize() != DST_SIZE_FHD_PLUS)) ||
((Xres == 1080 && Yres == 1920) && (m2mMPP->getDstAllocSize() != DST_SIZE_FHD)) ||
((Xres == 1440 && Yres == 2960) && (m2mMPP->getDstAllocSize() != DST_SIZE_WQHD_PLUS)) ||
((Xres == 1440 && Yres == 2560) && (m2mMPP->getDstAllocSize() != DST_SIZE_WQHD))) {
ret = true;
}
return ret;
}
void ExynosResourceManager::DstBufMgrThread::reallocDstBufs(uint32_t Xres, uint32_t Yres)
{
bool needRealloc = false;
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if (mM2mMPPs[i]->needPreAllocation())
{
if (needDstRealloc(Xres, Yres, mM2mMPPs[i])) {
HDEBUGLOGD(eDebugBuf, "M2M dst alloc : %d Realloc Start ++++++", mM2mMPPs[i]->mLogicalType);
needRealloc = true;
}
else HDEBUGLOGD(eDebugBuf, "M2M dst alloc : %d MPP's DST Realloc is not needed : Size is same", mM2mMPPs[i]->mLogicalType);
}
}
if (needRealloc) {
Mutex::Autolock lock(mStateMutex);
if (mExynosResourceManager->mForceReallocState == DST_REALLOC_DONE) {
mExynosResourceManager->mForceReallocState = DST_REALLOC_START;
android::Mutex::Autolock lock(mMutex);
mCondition.signal();
} else {
HDEBUGLOGD(eDebugBuf, "M2M dst alloc thread : queue aready.");
}
}
}
bool ExynosResourceManager::DstBufMgrThread::threadLoop()
{
while(mRunning) {
Mutex::Autolock lock(mMutex);
mCondition.wait(mMutex);
ExynosDevice *device = mExynosResourceManager->mDevice;
if (device == NULL)
return false;
ExynosDisplay *display = device->getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0));
if (display == NULL)
return false;
do {
{
HDEBUGLOGD(eDebugBuf, "M2M dst alloc %d, %d, %d, %d : Realloc On going ----------",
mBufXres, display->mXres, mBufYres, display->mYres);
Mutex::Autolock lock(mResInfoMutex);
mBufXres = display->mXres;mBufYres = display->mYres;
}
mExynosResourceManager->doAllocDstBufs(mBufXres, mBufYres);
} while (mBufXres != display->mXres || mBufYres != display->mYres);
{
Mutex::Autolock lock(mStateMutex);
mExynosResourceManager->mForceReallocState = DST_REALLOC_DONE;
HDEBUGLOGD(eDebugBuf, "M2M dst alloc %d, %d, %d, %d : Realloc On Done ----------",
mBufXres, display->mXres, mBufYres, display->mYres);
}
}
return true;
}
int32_t ExynosResourceManager::doAllocDstBufs(uint32_t Xres, uint32_t Yres)
{
ATRACE_CALL();
int32_t ret = NO_ERROR;
/* Assign m2mMPP's out buffers */
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if (mM2mMPPs[i]->needPreAllocation())
{
mM2mMPPs[i]->mFreeOutBufFlag = false;
for (uint32_t index = 0; index < NUM_MPP_DST_BUFS(mM2mMPPs[i]->mLogicalType); index++) {
HDEBUGLOGD(eDebugBuf, "%s allocate dst buffer[%d]%p, x: %d, y: %d",
__func__, index, mM2mMPPs[i]->mDstImgs[index].bufferHandle, Xres, Yres);
uint32_t bufAlign = mM2mMPPs[i]->getOutBufAlign();
ret = mM2mMPPs[i]->allocOutBuf(ALIGN_UP(Xres, bufAlign),
ALIGN_UP(Yres, bufAlign),
DEFAULT_MPP_DST_FORMAT, 0x0, index);
if (ret < 0) {
HWC_LOGE(NULL, "%s:: fail to allocate dst buffer[%d]",
__func__, index);
return ret;
}
mM2mMPPs[i]->mPrevAssignedDisplayType = HWC_DISPLAY_PRIMARY;
}
mM2mMPPs[i]->setDstAllocSize(Xres, Yres);
}
}
return ret;
}
int32_t ExynosResourceManager::checkScenario(ExynosDisplay __unused *display)
{
uint32_t prevResourceReserved = mResourceReserved;
mResourceReserved = 0x0;
/* Check whether camera preview is running */
ExynosDisplay *exynosDisplay = NULL;
for (uint32_t i = 0; i < mDevice->mDisplays.size(); i++) {
exynosDisplay = mDevice->mDisplays[i];
if ((exynosDisplay != NULL) && (exynosDisplay->mPlugState == true)) {
for (uint32_t i = 0; i < exynosDisplay->mLayers.size(); i++) {
ExynosLayer *layer = exynosDisplay->mLayers[i];
VendorGraphicBufferMeta gmeta(layer->mLayerBuffer);
if ((layer->mLayerBuffer != NULL) &&
(gmeta.producer_usage & BufferUsage::CAMERA_OUTPUT)) {
mResourceReserved |= (MPP_LOGICAL_G2D_YUV | MPP_LOGICAL_G2D_RGB);
break;
}
}
}
}
char value[PROPERTY_VALUE_MAX];
bool preview;
property_get("persist.vendor.sys.camera.preview", value, "0");
preview = !!atoi(value);
if (preview)
mResourceReserved |= (MPP_LOGICAL_G2D_YUV | MPP_LOGICAL_G2D_RGB);
if (prevResourceReserved != mResourceReserved) {
mDevice->setGeometryChanged(GEOMETRY_DEVICE_SCENARIO_CHANGED);
}
return NO_ERROR;
}
/**
* @param * display
* @return int
*/
int32_t ExynosResourceManager::assignResource(ExynosDisplay *display)
{
ATRACE_CALL();
int ret = 0;
if ((mDevice == NULL) || (display == NULL))
return -EINVAL;
HDEBUGLOGD(eDebugResourceManager|eDebugSkipResourceAssign, "mGeometryChanged(0x%" PRIx64 "), display(%d)",
mDevice->mGeometryChanged, display->mType);
if (mDevice->mGeometryChanged == 0) {
return NO_ERROR;
}
for (uint32_t i = 0; i < display->mLayers.size(); i++) {
display->mLayers[i]->resetValidateData();
}
display->initializeValidateInfos();
if ((ret = preProcessLayer(display)) != NO_ERROR) {
HWC_LOGE(display, "%s:: preProcessLayer() error (%d)",
__func__, ret);
return ret;
}
if (mDevice->isFirstValidate()) {
HDEBUGLOGD(eDebugResourceManager, "This is first validate");
if (exynosHWCControl.displayMode < DISPLAY_MODE_NUM)
mDevice->mDisplayMode = exynosHWCControl.displayMode;
if ((ret = prepareResources()) != NO_ERROR) {
HWC_LOGE(display, "%s:: prepareResources() error (%d)",
__func__, ret);
return ret;
}
preAssignWindows();
}
if ((ret = updateSupportedMPPFlag(display)) != NO_ERROR) {
HWC_LOGE(display, "%s:: updateSupportedMPPFlag() error (%d)",
__func__, ret);
return ret;
}
if ((ret = assignResourceInternal(display)) != NO_ERROR) {
HWC_LOGE(display, "%s:: assignResourceInternal() error (%d)",
__func__, ret);
return ret;
}
if ((ret = assignWindow(display)) != NO_ERROR) {
HWC_LOGE(display, "%s:: assignWindow() error (%d)",
__func__, ret);
return ret;
}
if (hwcCheckDebugMessages(eDebugResourceManager)) {
HDEBUGLOGD(eDebugResourceManager, "AssignResource result");
String8 result;
display->mClientCompositionInfo.dump(result);
HDEBUGLOGD(eDebugResourceManager, "%s", result.string());
result.clear();
display->mExynosCompositionInfo.dump(result);
HDEBUGLOGD(eDebugResourceManager, "%s", result.string());
for (uint32_t i = 0; i < display->mLayers.size(); i++) {
result.clear();
HDEBUGLOGD(eDebugResourceManager, "%d layer(%p) dump", i, display->mLayers[i]);
display->mLayers[i]->printLayer();
HDEBUGLOGD(eDebugResourceManager, "%s", result.string());
}
}
if (mDevice->isLastValidate(display)) {
if ((ret = finishAssignResourceWork()) != NO_ERROR) {
HWC_LOGE(display, "%s:: finishAssignResourceWork() error (%d)",
__func__, ret);
return ret;
}
}
if (!display->mUseDpu) {
if (display->mClientCompositionInfo.mHasCompositionLayer) {
if ((ret = display->mExynosCompositionInfo.mM2mMPP->assignMPP(display, &display->mClientCompositionInfo)) != NO_ERROR)
{
ALOGE("%s:: %s MPP assignMPP() error (%d)",
__func__, display->mExynosCompositionInfo.mM2mMPP->mName.string(), ret);
return ret;
}
int prevHasCompositionLayer = display->mExynosCompositionInfo.mHasCompositionLayer;
display->mExynosCompositionInfo.mHasCompositionLayer = true;
// if prevHasCompositionLayer is false, setResourcePriority is not called
if (prevHasCompositionLayer == false)
setResourcePriority(display);
}
}
return NO_ERROR;
}
int32_t ExynosResourceManager::setResourcePriority(ExynosDisplay *display)
{
int ret = NO_ERROR;
int check_ret = NO_ERROR;
ExynosMPP *m2mMPP = NULL;
for (uint32_t i = 0; i < display->mLayers.size(); i++) {
ExynosLayer *layer = display->mLayers[i];
if ((layer->mValidateCompositionType == HWC2_COMPOSITION_DEVICE) &&
(layer->mM2mMPP != NULL) &&
(layer->mM2mMPP->mPhysicalType == MPP_G2D) &&
((check_ret = layer->mM2mMPP->prioritize(2)) != NO_ERROR)) {
if (check_ret < 0) {
HWC_LOGE(display, "Fail to set exynoscomposition priority(%d)", ret);
} else {
m2mMPP = layer->mM2mMPP;
layer->resetAssignedResource();
layer->mOverlayInfo |= eResourcePendingWork;
layer->mValidateCompositionType = HWC2_COMPOSITION_DEVICE;
ret = EXYNOS_ERROR_CHANGED;
HDEBUGLOGD(eDebugResourceManager, "\t%s is reserved without display because of panding work",
m2mMPP->mName.string());
m2mMPP->reserveMPP();
layer->mCheckMPPFlag[m2mMPP->mLogicalType] = eMPPHWBusy;
}
}
}
m2mMPP = display->mExynosCompositionInfo.mM2mMPP;
ExynosCompositionInfo &compositionInfo = display->mExynosCompositionInfo;
if (compositionInfo.mHasCompositionLayer == true)
{
if ((m2mMPP == NULL) || (m2mMPP->mAcrylicHandle == NULL)) {
HWC_LOGE(display, "There is exynos composition layers but resource is null (%p)",
m2mMPP);
} else if ((check_ret = m2mMPP->prioritize(2)) != NO_ERROR) {
HDEBUGLOGD(eDebugResourceManager, "%s setting priority error(%d)", m2mMPP->mName.string(), check_ret);
if (check_ret < 0) {
HWC_LOGE(display, "Fail to set exynoscomposition priority(%d)", ret);
} else {
if (display->mExynosCompositionInfo.mFirstIndex >= 0) {
uint32_t firstIndex = (uint32_t)display->mExynosCompositionInfo.mFirstIndex;
uint32_t lastIndex = (uint32_t)display->mExynosCompositionInfo.mLastIndex;
for (uint32_t i = firstIndex; i <= lastIndex; i++) {
ExynosLayer *layer = display->mLayers[i];
layer->resetAssignedResource();
layer->mOverlayInfo |= eResourcePendingWork;
layer->mValidateCompositionType = HWC2_COMPOSITION_DEVICE;
layer->mCheckMPPFlag[m2mMPP->mLogicalType] = eMPPHWBusy;
}
}
compositionInfo.initializeInfos(display);
ret = EXYNOS_ERROR_CHANGED;
m2mMPP->resetUsedCapacity();
HDEBUGLOGD(eDebugResourceManager, "\t%s is reserved without display because of pending work",
m2mMPP->mName.string());
m2mMPP->reserveMPP();
}
} else {
HDEBUGLOGD(eDebugResourceManager, "%s setting priority is ok", m2mMPP->mName.string());
}
}
return ret;
}
int32_t ExynosResourceManager::assignResourceInternal(ExynosDisplay *display)
{
int ret = NO_ERROR;
int retry_count = 0;
Mutex::Autolock lock(mDstBufMgrThread->mStateMutex);
/*
* First add layers that SF requested HWC2_COMPOSITION_CLIENT type
* to client composition
*/
for (uint32_t i = 0; i < display->mLayers.size(); i++) {
ExynosLayer *layer = display->mLayers[i];
if (layer->mCompositionType == HWC2_COMPOSITION_CLIENT) {
layer->mOverlayInfo |= eSkipLayer;
layer->mValidateCompositionType = HWC2_COMPOSITION_CLIENT;
if (((ret = display->addClientCompositionLayer(i)) != NO_ERROR) &&
(ret != EXYNOS_ERROR_CHANGED)) {
HWC_LOGE(display, "Handle HWC2_COMPOSITION_CLIENT type layers, but addClientCompositionLayer failed (%d)", ret);
return ret;
}
}
}
do {
HDEBUGLOGD(eDebugResourceManager, "%s:: retry_count(%d)", __func__, retry_count);
if ((ret = resetAssignedResources(display)) != NO_ERROR)
return ret;
if ((ret = assignCompositionTarget(display, COMPOSITION_CLIENT)) != NO_ERROR) {
HWC_LOGE(display, "%s:: Fail to assign resource for compositionTarget",
__func__);
return ret;
}
if ((ret = assignLayers(display, ePriorityMax)) != NO_ERROR) {
if (ret == EXYNOS_ERROR_CHANGED) {
retry_count++;
continue;
} else {
HWC_LOGE(display, "%s:: Fail to assign resource for ePriorityMax layer",
__func__);
return ret;
}
}
if ((ret = assignLayers(display, ePriorityHigh)) != NO_ERROR) {
if (ret == EXYNOS_ERROR_CHANGED) {
retry_count++;
continue;
} else {
HWC_LOGE(display, "%s:: Fail to assign resource for ePriorityHigh layer",
__func__);
return ret;
}
}
if ((ret = assignCompositionTarget(display, COMPOSITION_EXYNOS)) != NO_ERROR) {
if (ret == eInsufficientMPP) {
/*
* Change compositionTypes to HWC2_COMPOSITION_CLIENT
*/
uint32_t firstIndex = (uint32_t)display->mExynosCompositionInfo.mFirstIndex;
uint32_t lastIndex = (uint32_t)display->mExynosCompositionInfo.mLastIndex;
for (uint32_t i = firstIndex; i <= lastIndex; i++) {
ExynosLayer *layer = display->mLayers[i];
layer->resetAssignedResource();
layer->mOverlayInfo |= eInsufficientMPP;
layer->mValidateCompositionType = HWC2_COMPOSITION_CLIENT;
if (((ret = display->addClientCompositionLayer(i)) != NO_ERROR) &&
(ret != EXYNOS_ERROR_CHANGED)) {
HWC_LOGE(display, "Change compositionTypes to HWC2_COMPOSITION_CLIENT, but addClientCompositionLayer failed (%d)", ret);
return ret;
}
}
display->mExynosCompositionInfo.initializeInfos(display);
ret = EXYNOS_ERROR_CHANGED;
} else {
return ret;
}
}
if (ret == NO_ERROR) {
for (int32_t i = ePriorityHigh - 1; i > ePriorityNone; i--) {
if ((ret = assignLayers(display, i)) == EXYNOS_ERROR_CHANGED)
break;
if (ret != NO_ERROR)
return ret;
}
}
/* Assignment is done */
if (ret == NO_ERROR) {
ret = setResourcePriority(display);
}
retry_count++;
} while((ret == EXYNOS_ERROR_CHANGED) && (retry_count < ASSIGN_RESOURCE_TRY_COUNT));
if (retry_count == ASSIGN_RESOURCE_TRY_COUNT) {
HWC_LOGE(display, "%s:: assign resources fail", __func__);
ret = eUnknown;
return ret;
} else {
if ((ret = updateExynosComposition(display)) != NO_ERROR)
return ret;
if ((ret = updateClientComposition(display)) != NO_ERROR)
return ret;
}
if (hwcCheckDebugMessages(eDebugCapacity)) {
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if (mM2mMPPs[i]->mPhysicalType == MPP_G2D)
{
String8 dumpMPP;
mM2mMPPs[i]->dump(dumpMPP);
HDEBUGLOGD(eDebugCapacity, "%s", dumpMPP.string());
}
}
}
return ret;
}
int32_t ExynosResourceManager::updateExynosComposition(ExynosDisplay *display)
{
int ret = NO_ERROR;
/* Use Exynos composition as many as possible */
if ((display->mExynosCompositionInfo.mHasCompositionLayer == true) &&
(display->mExynosCompositionInfo.mM2mMPP != NULL)) {
if (display->mDisplayControl.useMaxG2DSrc == 1) {
ExynosMPP *m2mMPP = display->mExynosCompositionInfo.mM2mMPP;
uint32_t lastIndex = display->mExynosCompositionInfo.mLastIndex;
uint32_t firstIndex = display->mExynosCompositionInfo.mFirstIndex;
uint32_t remainNum = m2mMPP->mMaxSrcLayerNum - (lastIndex - firstIndex + 1);
HDEBUGLOGD(eDebugResourceManager, "Update ExynosComposition firstIndex: %d, lastIndex: %d, remainNum: %d++++",
firstIndex, lastIndex, remainNum);
ExynosLayer *layer = NULL;
exynos_image src_img;
exynos_image dst_img;
if (remainNum > 0) {
for (uint32_t i = (lastIndex + 1); i < display->mLayers.size(); i++)
{
layer = display->mLayers[i];
layer->setSrcExynosImage(&src_img);
layer->setDstExynosImage(&dst_img);
layer->setExynosImage(src_img, dst_img);
bool isAssignable = false;
if ((layer->mSupportedMPPFlag & m2mMPP->mLogicalType) != 0)
isAssignable = m2mMPP->isAssignable(display, src_img, dst_img);
bool canChange = (layer->mValidateCompositionType != HWC2_COMPOSITION_CLIENT) &&
((display->mDisplayControl.cursorSupport == false) ||
(layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) &&
(layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignable;
HDEBUGLOGD(eDebugResourceManager, "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, remainNum(%d)",
i, layer->mValidateCompositionType,
layer->mSupportedMPPFlag, isAssignable, canChange, remainNum);
if (canChange) {
layer->resetAssignedResource();
layer->mOverlayInfo |= eUpdateExynosComposition;
if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR)
{
ALOGE("%s:: %s MPP assignMPP() error (%d)",
__func__, m2mMPP->mName.string(), ret);
return ret;
}
layer->setExynosMidImage(dst_img);
display->addExynosCompositionLayer(i);
layer->mValidateCompositionType = HWC2_COMPOSITION_EXYNOS;
remainNum--;
}
if ((canChange == false) || (remainNum == 0))
break;
}
}
if (remainNum > 0) {
for (int32_t i = (firstIndex - 1); i >= 0; i--)
{
layer = display->mLayers[i];
layer->setSrcExynosImage(&src_img);
layer->setDstExynosImage(&dst_img);
layer->setExynosImage(src_img, dst_img);
bool isAssignable = false;
if ((layer->mSupportedMPPFlag & m2mMPP->mLogicalType) != 0)
isAssignable = m2mMPP->isAssignable(display, src_img, dst_img);
bool canChange = (layer->mValidateCompositionType != HWC2_COMPOSITION_CLIENT) &&
((display->mDisplayControl.cursorSupport == false) ||
(layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) &&
(layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignable;
HDEBUGLOGD(eDebugResourceManager, "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, remainNum(%d)",
i, layer->mValidateCompositionType,
layer->mSupportedMPPFlag, isAssignable, canChange, remainNum);
if (canChange) {
layer->resetAssignedResource();
layer->mOverlayInfo |= eUpdateExynosComposition;
if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR)
{
ALOGE("%s:: %s MPP assignMPP() error (%d)",
__func__, m2mMPP->mName.string(), ret);
return ret;
}
layer->setExynosMidImage(dst_img);
display->addExynosCompositionLayer(i);
layer->mValidateCompositionType = HWC2_COMPOSITION_EXYNOS;
remainNum--;
}
if ((canChange == false) || (remainNum == 0))
break;
}
}
HDEBUGLOGD(eDebugResourceManager, "Update ExynosComposition firstIndex: %d, lastIndex: %d, remainNum: %d-----",
display->mExynosCompositionInfo.mFirstIndex, display->mExynosCompositionInfo.mLastIndex, remainNum);
}
/*
* Check if there is only one exynos composition layer
* Then it is not composition and m2mMPP is not required
* if internalMPP can process the layer alone.
*/
ExynosMPP *otfMPP = display->mExynosCompositionInfo.mOtfMPP;
if ((display->mDisplayControl.enableExynosCompositionOptimization == true) &&
(otfMPP != NULL) &&
(display->mExynosCompositionInfo.mFirstIndex >= 0) &&
(display->mExynosCompositionInfo.mFirstIndex == display->mExynosCompositionInfo.mLastIndex))
{
ExynosLayer* layer = display->mLayers[display->mExynosCompositionInfo.mFirstIndex];
if (layer->mSupportedMPPFlag & otfMPP->mLogicalType) {
layer->resetAssignedResource();
layer->mValidateCompositionType = HWC2_COMPOSITION_DEVICE;
display->mExynosCompositionInfo.initializeInfos(display);
// reset otfMPP
if ((ret = otfMPP->resetAssignedState()) != NO_ERROR)
{
ALOGE("%s:: %s MPP resetAssignedState() error (%d)",
__func__, otfMPP->mName.string(), ret);
}
// assign otfMPP again
if ((ret = otfMPP->assignMPP(display, layer)) != NO_ERROR)
{
ALOGE("%s:: %s MPP assignMPP() error (%d)",
__func__, otfMPP->mName.string(), ret);
}
}
}
}
return ret;
}
int32_t ExynosResourceManager::changeLayerFromClientToDevice(ExynosDisplay *display, ExynosLayer *layer,
uint32_t layer_index, exynos_image m2m_out_img, ExynosMPP *m2mMPP, ExynosMPP *otfMPP)
{
int ret = NO_ERROR;
if ((ret = display->removeClientCompositionLayer(layer_index)) != NO_ERROR) {
ALOGD("removeClientCompositionLayer return error(%d)", ret);
return ret;
}
if (otfMPP != NULL) {
if ((ret = otfMPP->assignMPP(display, layer)) != NO_ERROR)
{
ALOGE("%s:: %s MPP assignMPP() error (%d)",
__func__, otfMPP->mName.string(), ret);
return ret;
}
HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned",
layer_index, otfMPP->mName.string());
}
if (m2mMPP != NULL) {
if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR)
{
ALOGE("%s:: %s MPP assignMPP() error (%d)",
__func__, m2mMPP->mName.string(), ret);
return ret;
}
layer->setExynosMidImage(m2m_out_img);
HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned",
layer_index, m2mMPP->mName.string());
}
layer->mValidateCompositionType = HWC2_COMPOSITION_DEVICE;
display->mWindowNumUsed++;
HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: mWindowNumUsed(%d)",
layer_index, display->mWindowNumUsed);
return ret;
}
int32_t ExynosResourceManager::updateClientComposition(ExynosDisplay *display)
{
int ret = NO_ERROR;
if (display->mDisplayControl.enableClientCompositionOptimization == false)
return ret;
if ((exynosHWCControl.forceGpu == 1) ||
(display->mClientCompositionInfo.mHasCompositionLayer == false))
return ret;
/* Check if there is layer that can be handled by overlay */
int32_t firstIndex = display->mClientCompositionInfo.mFirstIndex;
int32_t lastIndex = display->mClientCompositionInfo.mLastIndex;
/* Don't optimize if only low fps layers are composited by GLES */
if ((display->mLowFpsLayerInfo.mHasLowFpsLayer == true) &&
(display->mLowFpsLayerInfo.mFirstIndex == firstIndex) &&
(display->mLowFpsLayerInfo.mLastIndex == lastIndex))
return ret;
for (int32_t i = firstIndex; i <= lastIndex; i++) {
ExynosMPP *m2mMPP = NULL;
ExynosMPP *otfMPP = NULL;
exynos_image m2m_out_img;
uint32_t overlayInfo = 0;
int32_t compositionType = 0;
ExynosLayer *layer = display->mLayers[i];
if ((layer->mOverlayPriority >= ePriorityHigh) &&
(layer->mValidateCompositionType == HWC2_COMPOSITION_DEVICE)) {
display->mClientCompositionInfo.mFirstIndex++;
continue;
}
compositionType = assignLayer(display, layer, i, m2m_out_img, &m2mMPP, &otfMPP, overlayInfo);
if (compositionType == HWC2_COMPOSITION_DEVICE) {
/*
* Don't allocate G2D
* Execute can be fail because of other job
* Prioritizing is required to allocate G2D
*/
if ((m2mMPP != NULL) && (m2mMPP->mPhysicalType == MPP_G2D))
break;
if ((ret = changeLayerFromClientToDevice(display, layer, i, m2m_out_img, m2mMPP, otfMPP)) != NO_ERROR)
return ret;
} else {
break;
}
}
firstIndex = display->mClientCompositionInfo.mFirstIndex;
lastIndex = display->mClientCompositionInfo.mLastIndex;
for (int32_t i = lastIndex; i >= 0; i--) {
ExynosMPP *m2mMPP = NULL;
ExynosMPP *otfMPP = NULL;
exynos_image m2m_out_img;
uint32_t overlayInfo = 0;
int32_t compositionType = 0;
ExynosLayer *layer = display->mLayers[i];
if ((layer->mOverlayPriority >= ePriorityHigh) &&
(layer->mValidateCompositionType == HWC2_COMPOSITION_DEVICE)) {
display->mClientCompositionInfo.mLastIndex--;
continue;
}
compositionType = assignLayer(display, layer, i, m2m_out_img, &m2mMPP, &otfMPP, overlayInfo);
if (compositionType == HWC2_COMPOSITION_DEVICE) {
/*
* Don't allocate G2D
* Execute can be fail because of other job
* Prioritizing is required to allocate G2D
*/
if ((m2mMPP != NULL) && (m2mMPP->mPhysicalType == MPP_G2D))
break;
if ((ret = changeLayerFromClientToDevice(display, layer, i, m2m_out_img, m2mMPP, otfMPP)) != NO_ERROR)
return ret;
} else {
break;
}
}
return ret;
}
int32_t ExynosResourceManager::resetAssignedResources(ExynosDisplay * display, bool forceReset)
{
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
if (mOtfMPPs[i]->mAssignedDisplay != display)
continue;
mOtfMPPs[i]->resetAssignedState();
}
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if (mM2mMPPs[i]->mAssignedDisplay != display)
continue;
if ((forceReset == false) &&
((mM2mMPPs[i]->mLogicalType == MPP_LOGICAL_G2D_RGB) ||
(mM2mMPPs[i]->mLogicalType == MPP_LOGICAL_G2D_COMBO)))
{
/*
* Don't reset assigned state
*/
continue;
}
mM2mMPPs[i]->resetAssignedState();
}
display->mWindowNumUsed = 0;
return NO_ERROR;
}
int32_t ExynosResourceManager::assignCompositionTarget(ExynosDisplay * display, uint32_t targetType)
{
int32_t ret = NO_ERROR;
ExynosCompositionInfo *compositionInfo;
HDEBUGLOGD(eDebugResourceManager, "%s:: display(%d), targetType(%d) +++++",
__func__, display->mType, targetType);
if (targetType == COMPOSITION_CLIENT)
compositionInfo = &(display->mClientCompositionInfo);
else if (targetType == COMPOSITION_EXYNOS)
compositionInfo = &(display->mExynosCompositionInfo);
else
return -EINVAL;
if (compositionInfo->mHasCompositionLayer == false)
{
HDEBUGLOGD(eDebugResourceManager, "\tthere is no composition layers");
return NO_ERROR;
}
exynos_image src_img;
exynos_image dst_img;
display->setCompositionTargetExynosImage(targetType, &src_img, &dst_img);
if (targetType == COMPOSITION_EXYNOS) {
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if ((display->mUseDpu == true) &&
(mM2mMPPs[i]->mLogicalType != MPP_LOGICAL_G2D_RGB))
continue;
if ((display->mUseDpu == false) &&
(mM2mMPPs[i]->mLogicalType != MPP_LOGICAL_G2D_COMBO))
continue;
if (mM2mMPPs[i]->isAssignableState(display, src_img, dst_img)) {
/* assignMPP(display, compositionInfo) is not called hear
* assignMPP() was called already during assigning layer
* Source of M2mMPP should be Layer, not composition target buffer*/
compositionInfo->mM2mMPP = mM2mMPPs[i];
}
}
if (compositionInfo->mM2mMPP == NULL) {
HWC_LOGE(display, "%s:: fail to assign M2mMPP (%d)",__func__, ret);
return eInsufficientMPP;
}
}
if ((compositionInfo->mFirstIndex < 0) ||
(compositionInfo->mLastIndex < 0)) {
HWC_LOGE(display, "%s:: layer index is not valid mFirstIndex(%d), mLastIndex(%d)",
__func__, compositionInfo->mFirstIndex, compositionInfo->mLastIndex);
return -EINVAL;
}
if (display->mUseDpu == false) {
return NO_ERROR;
}
int64_t isSupported = 0;
bool isAssignable = false;
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
isSupported = mOtfMPPs[i]->isSupported(*display, src_img, dst_img);
if (isSupported == NO_ERROR)
isAssignable = mOtfMPPs[i]->isAssignable(display, src_img, dst_img);
HDEBUGLOGD(eDebugResourceManager, "\t\t check %s: supportedBit(0x%" PRIx64 "), isAssignable(%d)",
mOtfMPPs[i]->mName.string(), -isSupported, isAssignable);
if ((isSupported == NO_ERROR) && (isAssignable)) {
if ((ret = mOtfMPPs[i]->assignMPP(display, compositionInfo)) != NO_ERROR)
{
HWC_LOGE(display, "%s:: %s MPP assignMPP() error (%d)",
__func__, mOtfMPPs[i]->mName.string(), ret);
return ret;
}
compositionInfo->setExynosImage(src_img, dst_img);
compositionInfo->setExynosMidImage(dst_img);
compositionInfo->mOtfMPP = mOtfMPPs[i];
display->mWindowNumUsed++;
HDEBUGLOGD(eDebugResourceManager, "%s:: %s is assigned", __func__, mOtfMPPs[i]->mName.string());
return NO_ERROR;
}
}
HDEBUGLOGD(eDebugResourceManager, "%s:: insufficient MPP", __func__);
return eInsufficientMPP;
}
int32_t ExynosResourceManager::validateLayer(uint32_t index, ExynosDisplay *display, ExynosLayer *layer)
{
if ((layer == NULL) || (display == NULL))
return eUnknown;
if (exynosHWCControl.forceGpu == 1) {
if ((layer->mLayerBuffer == NULL) ||
(getDrmMode(layer->mLayerBuffer) == NO_DRM))
return eForceFbEnabled;
}
if ((display->mLayers.size() >= MAX_OVERLAY_LAYER_NUM) &&
(layer->mOverlayPriority < ePriorityHigh))
return eExceedMaxLayerNum;
if ((layer->mLayerBuffer != NULL) &&
(getDrmMode(layer->mLayerBuffer) == NO_DRM) &&
(display->mDREnable == true) &&
(display->mDynamicReCompMode == DEVICE_2_CLIENT))
return eDynamicRecomposition;
if ((layer->mLayerBuffer != NULL) &&
(display->mDisplayId == getDisplayId(HWC_DISPLAY_PRIMARY, 0)) &&
(mForceReallocState != DST_REALLOC_DONE)) {
ALOGI("Device type assign skipping by dst reallocation...... ");
return eReallocOnGoingForDDI;
}
if (layer->mCompositionType == HWC2_COMPOSITION_CLIENT)
return eSkipLayer;
#ifndef HWC_SUPPORT_COLOR_TRANSFORM
if (display->mColorTransformHint != HAL_COLOR_TRANSFORM_IDENTITY) {
HWC_LOGE(display, "unsupported color transform");
return eUnSupportedColorTransform;
}
#else
if ((display->mColorTransformHint < 0) &&
(layer->mOverlayPriority < ePriorityHigh))
return eUnSupportedColorTransform;
#endif
if ((display->mLowFpsLayerInfo.mHasLowFpsLayer == true) &&
(display->mLowFpsLayerInfo.mFirstIndex <= (int32_t)index) &&
((int32_t)index <= display->mLowFpsLayerInfo.mLastIndex))
return eLowFpsLayer;
if(layer->isDimLayer() && layer->mLayerBuffer == NULL) {
return eDimLayer;
}
if (!(display->mType == HWC_DISPLAY_VIRTUAL &&
((ExynosVirtualDisplay *)display)->mIsWFDState == (int)LLWFD))
if (layer->mLayerBuffer == NULL)
return eInvalidHandle;
if (isSrcCropFloat(layer->mPreprocessedInfo.sourceCrop))
return eHasFloatSrcCrop;
if ((layer->mPreprocessedInfo.displayFrame.left < 0) ||
(layer->mPreprocessedInfo.displayFrame.top < 0) ||
(layer->mPreprocessedInfo.displayFrame.right > (int32_t)display->mXres) ||
(layer->mPreprocessedInfo.displayFrame.bottom > (int32_t)display->mYres))
return eInvalidDispFrame;
return NO_ERROR;
}
exynos_image ExynosResourceManager::getAlignedImage(exynos_image image, const ExynosMPP *m2mMpp,
const ExynosMPP *otfMpp) const {
const auto srcCropWidthAlign = otfMpp ? otfMpp->getSrcCropWidthAlign(image) : 1;
const auto srcCropHeightAlign = otfMpp ? otfMpp->getSrcCropHeightAlign(image) : 1;
const auto dstwidthAlign = m2mMpp ? m2mMpp->getDstWidthAlign(image) : 1;
const auto dstHeightAlign = m2mMpp ? m2mMpp->getDstHeightAlign(image) : 1;
const auto widthAlign = std::lcm(srcCropWidthAlign, dstwidthAlign);
const auto heighAlign = std::lcm(srcCropHeightAlign, dstHeightAlign);
image.w = pixel_align(image.w, widthAlign);
image.h = pixel_align(image.h, heighAlign);
return image;
}
void ExynosResourceManager::getCandidateScalingM2mMPPOutImages(
const ExynosDisplay *display, const exynos_image &src_img, const exynos_image &dst_img,
std::vector<exynos_image> &image_lists) {
const bool isPerpendicular = !!(src_img.transform & HAL_TRANSFORM_ROT_90);
const uint32_t srcWidth = isPerpendicular ? src_img.h : src_img.w;
const uint32_t srcHeight = isPerpendicular ? src_img.w : src_img.h;
const bool scaleUp = (srcWidth < dst_img.w && srcHeight < dst_img.h);
const bool scaleDown = (srcWidth > dst_img.w && srcHeight > dst_img.h);
if (!scaleUp && !scaleDown) {
return;
}
/* otfMPP doesn't rotate image, m2mMPP rotates image */
exynos_image dst_scale_img = dst_img;
if (hasHdrInfo(src_img)) {
if (isFormatYUV(src_img.format))
dst_scale_img.format = HAL_PIXEL_FORMAT_YCBCR_P010;
else
dst_scale_img.format = HAL_PIXEL_FORMAT_RGBA_1010102;
} else {
if (isFormatYUV(src_img.format)) {
dst_scale_img.format = DEFAULT_MPP_DST_YUV_FORMAT;
}
}
ExynosMPP *otfMpp = nullptr;
ExynosMPP *m2mMpp = nullptr;
uint32_t otfMppRatio = 1;
uint32_t m2mMppRatio = 1;
if (scaleUp) {
std::find_if(mOtfMPPs.begin(), mOtfMPPs.end(),
[&dst_scale_img, &dst_img, &otfMpp, &otfMppRatio](auto m) {
auto ratio = m->getMaxUpscale(dst_scale_img, dst_img);
if (ratio > 1) {
otfMpp = m;
otfMppRatio = ratio;
return true;
}
return false;
});
const auto reqRatio = max(float(dst_img.w) / float(srcWidth * otfMppRatio),
float(dst_img.h) / float(srcHeight * otfMppRatio));
std::find_if(mM2mMPPs.begin(), mM2mMPPs.end(),
[&src_img, &dst_scale_img, reqRatio, &m2mMpp, &m2mMppRatio](auto m) {
float ratio = float(m->getMaxUpscale(src_img, dst_scale_img));
if (ratio > reqRatio) {
m2mMpp = m;
m2mMppRatio = ratio;
return true;
}
return false;
});
} else {
std::find_if(mM2mMPPs.begin(), mM2mMPPs.end(),
[&src_img, &dst_scale_img, display, &m2mMpp, &m2mMppRatio](auto m) {
auto ratio = m->getMaxDownscale(*display, src_img, dst_scale_img);
if (ratio > 1) {
m2mMpp = m;
m2mMppRatio = ratio;
return true;
}
return false;
});
const float otfSrcWidth = float(srcWidth / m2mMppRatio);
const float scaleRatio_H = otfSrcWidth / float(dst_img.w);
const float otfSrcHeight = float(srcWidth / m2mMppRatio);
const float scaleRatio_V = otfSrcHeight / float(dst_img.h);
const float displayRatio_V = float(dst_img.h) / float(display->mYres);
const float resolution = otfSrcWidth * otfSrcHeight * display->getBtsRefreshRate() / 1000;
std::find_if(mOtfMPPs.begin(), mOtfMPPs.end(),
[&dst_scale_img, &dst_img, resolution, scaleRatio_H, scaleRatio_V,
displayRatio_V, &otfMpp, &otfMppRatio](auto m) {
auto ratio = m->getDownscaleRestriction(dst_scale_img, dst_img);
if (ratio >= scaleRatio_H && ratio >= scaleRatio_V &&
m->checkDownscaleCap(resolution, displayRatio_V)) {
otfMpp = m;
otfMppRatio = ratio;
return true;
}
return false;
});
}
if (!otfMpp && !m2mMpp) {
HDEBUGLOGD(eDebugResourceManager,
"Cannot find available MPP for scaling src %d x %d, dst %d x %d", src_img.w,
src_img.h, dst_img.w, dst_img.h);
return;
}
dst_scale_img.x = 0;
dst_scale_img.y = 0;
dst_scale_img.w = scaleDown ? dst_img.w : srcWidth;
dst_scale_img.h = scaleDown ? dst_img.h : srcHeight;
HDEBUGLOGD(eDebugResourceManager,
"scaling w: %d, h: %d, ratio = otfType %d - %d, m2mType %d - %d", dst_scale_img.w,
dst_scale_img.h, otfMpp ? otfMpp->mLogicalType : -1, otfMppRatio,
m2mMpp ? m2mMpp->mLogicalType : -1, m2mMppRatio);
if (scaleUp) {
if (dst_scale_img.w * otfMppRatio < dst_img.w) {
dst_scale_img.w = uint32_t(ceilf(float(dst_img.w) / float(otfMppRatio)));
}
if (dst_scale_img.h * otfMppRatio < dst_img.h) {
dst_scale_img.h = uint32_t(ceilf(float(dst_img.h) / float(otfMppRatio)));
}
} else {
if (dst_scale_img.w * m2mMppRatio < srcWidth) {
dst_scale_img.w = uint32_t(ceilf(float(srcWidth) / float(m2mMppRatio)));
}
if (dst_scale_img.h * m2mMppRatio < srcHeight) {
dst_scale_img.h = uint32_t(ceilf(float(srcHeight) / float(m2mMppRatio)));
}
}
HDEBUGLOGD(eDebugResourceManager,
"\tsrc[%d, %d, %d,%d], dst[%d, %d, %d,%d], mid[%d, %d, %d, %d]", src_img.x,
src_img.y, src_img.w, src_img.h, dst_img.x, dst_img.y, dst_img.w, dst_img.h,
dst_scale_img.x, dst_scale_img.y, dst_scale_img.w, dst_scale_img.h);
if (isFormatSBWC(dst_scale_img.format)) {
image_lists.emplace_back(getAlignedImage(dst_scale_img, m2mMpp, otfMpp));
/*
* SBWC format could not be supported in specific dst size
* Add uncompressed YUV format to cover this size
*/
dst_scale_img.format = DEFAULT_MPP_DST_UNCOMP_YUV_FORMAT;
}
image_lists.emplace_back(getAlignedImage(dst_scale_img, m2mMpp, otfMpp));
}
int32_t ExynosResourceManager::getCandidateM2mMPPOutImages(ExynosDisplay *display,
ExynosLayer *layer, std::vector<exynos_image> &image_lists)
{
exynos_image src_img;
exynos_image dst_img;
layer->setSrcExynosImage(&src_img);
layer->setDstExynosImage(&dst_img);
/* Position is (0, 0) */
dst_img.x = 0;
dst_img.y = 0;
/* Check original source format first */
dst_img.format = src_img.format;
dst_img.dataSpace = src_img.dataSpace;
/* Copy origin source HDR metadata */
dst_img.metaParcel = src_img.metaParcel;
getCandidateScalingM2mMPPOutImages(display, src_img, dst_img, image_lists);
if (isFormatYUV(src_img.format) && !hasHdrInfo(src_img)) {
dst_img.format = DEFAULT_MPP_DST_YUV_FORMAT;
}
ExynosExternalDisplay *external_display =
(ExynosExternalDisplay*)mDevice->getDisplay(getDisplayId(HWC_DISPLAY_EXTERNAL, 0));
/* For HDR through MSC or G2D case but dataspace is not changed */
if (hasHdrInfo(src_img)) {
if (isFormatYUV(src_img.format))
dst_img.format = HAL_PIXEL_FORMAT_YCBCR_P010;
else
dst_img.format = HAL_PIXEL_FORMAT_RGBA_1010102;
dst_img.dataSpace = src_img.dataSpace;
/*
* Align dst size
* HDR10Plus should able to be processed by VGRFS
* HDR on primary display should be processed by VGRFS
* when external display is connected
* because G2D is used by external display
*/
if (hasHdr10Plus(dst_img) ||
((external_display != NULL) && (external_display->mPlugState) &&
(display->mType == HWC_DISPLAY_PRIMARY))) {
ExynosMPP *otfMppForHDRPlus = nullptr;
auto mpp_it = std::find_if(mOtfMPPs.begin(), mOtfMPPs.end(),
[](auto m) {
return (m->mAttr & MPP_ATTR_HDR10PLUS);
});
otfMppForHDRPlus = mpp_it == mOtfMPPs.end() ? nullptr : *mpp_it;
uint32_t srcCropWidthAlign = 1;
uint32_t srcCropHeightAlign = 1;
if (otfMppForHDRPlus) {
srcCropWidthAlign = otfMppForHDRPlus->getSrcCropWidthAlign(dst_img);
srcCropHeightAlign = otfMppForHDRPlus->getSrcCropHeightAlign(dst_img);
}
dst_img.w = pixel_align(dst_img.w, srcCropWidthAlign);
dst_img.h = pixel_align(dst_img.h, srcCropHeightAlign);
}
}
image_lists.push_back(dst_img);
if (isFormatSBWC(dst_img.format)) {
/*
* SBWC format could not be supported in specific dst size
* Add uncompressed YUV format to cover this size
*/
dst_img.format = DEFAULT_MPP_DST_UNCOMP_YUV_FORMAT;
image_lists.push_back(dst_img);
}
/* For G2D HDR case */
if (hasHdrInfo(src_img)) {
bool isExternalPlugged = false;
isHdrExternal = false;
if (external_display != NULL) {
if (external_display->mPlugState) isExternalPlugged = true;
if (isExternalPlugged && (external_display->mExternalHdrSupported == true))
isHdrExternal = true;
}
if (isHdrExternal && (display->mType == HWC_DISPLAY_EXTERNAL)) {
dst_img.format = HAL_PIXEL_FORMAT_RGBA_1010102;
dst_img.dataSpace = src_img.dataSpace;
} else {
uint32_t dataspace = HAL_DATASPACE_UNKNOWN;
if (display->mColorMode == HAL_COLOR_MODE_NATIVE) {
dataspace = HAL_DATASPACE_DCI_P3;
dataspace &= ~HAL_DATASPACE_TRANSFER_MASK;
dataspace |= HAL_DATASPACE_TRANSFER_GAMMA2_2;
dataspace &= ~HAL_DATASPACE_RANGE_MASK;
dataspace |= HAL_DATASPACE_RANGE_LIMITED;
} else {
dataspace = colorModeToDataspace(display->mColorMode);
}
dst_img.format = HAL_PIXEL_FORMAT_RGBX_8888;
dst_img.dataSpace = (android_dataspace)dataspace;
}
/*
* This image is not pushed for primary display
* if external display is connected
* because G2D is used only for HDR on exernal display
*/
if (!(isExternalPlugged && (display->mType == HWC_DISPLAY_PRIMARY))) {
image_lists.push_back(dst_img);
}
}
if (isFormatYUV(src_img.format) && !hasHdrInfo(src_img)) {
/* Check RGB format */
dst_img.format = DEFAULT_MPP_DST_FORMAT;
if (display->mColorMode == HAL_COLOR_MODE_NATIVE) {
/* Bypass dataSpace */
dst_img.dataSpace = src_img.dataSpace;
} else {
/* Covert data space */
dst_img.dataSpace = colorModeToDataspace(display->mColorMode);
}
image_lists.push_back(dst_img);
}
/*
* image_lists[] would be src of otfMPP.
* Layer color transform should be addressed
* with dataspace conversion.
* It should be addressed by m2mMPP if m2mMPP converts dataspace.
* In other cases, m2mMPP ignores color transform setting and
* otfMPP addresses layer color transform if it is necessary.
*/
for (auto &image: image_lists) {
if (image.dataSpace == src_img.dataSpace)
image.needColorTransform = src_img.needColorTransform;
else
image.needColorTransform = false;
}
return static_cast<int32_t>(image_lists.size());
}
int32_t ExynosResourceManager::assignLayer(ExynosDisplay *display, ExynosLayer *layer, uint32_t layer_index,
exynos_image &m2m_out_img, ExynosMPP **m2mMPP, ExynosMPP **otfMPP, uint32_t &overlayInfo)
{
int32_t ret = NO_ERROR;
uint32_t validateFlag = 0;
exynos_image src_img;
exynos_image dst_img;
layer->setSrcExynosImage(&src_img);
layer->setDstExynosImage(&dst_img);
layer->setExynosImage(src_img, dst_img);
layer->setExynosMidImage(dst_img);
validateFlag = validateLayer(layer_index, display, layer);
if ((display->mUseDpu) &&
(display->mWindowNumUsed >= display->mMaxWindowNum))
validateFlag |= eInsufficientWindow;
HDEBUGLOGD(eDebugResourceManager, "\t[%d] layer: validateFlag(0x%8x), supportedMPPFlag(0x%8x)",
layer_index, validateFlag, layer->mSupportedMPPFlag);
if (hwcCheckDebugMessages(eDebugResourceManager)) {
layer->printLayer();
}
if ((validateFlag == NO_ERROR) || (validateFlag == eInsufficientWindow) ||
(validateFlag == eDimLayer)) {
bool isAssignable = false;
uint64_t isSupported = 0;
/* 1. Find available otfMPP */
if (validateFlag != eInsufficientWindow) {
for (uint32_t j = 0; j < mOtfMPPs.size(); j++) {
if ((layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType) != 0)
isAssignable = mOtfMPPs[j]->isAssignable(display, src_img, dst_img);
HDEBUGLOGD(eDebugResourceManager, "\t\t check %s: flag (%d) supportedBit(%d), isAssignable(%d)",
mOtfMPPs[j]->mName.string(),layer->mSupportedMPPFlag,
(layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType), isAssignable);
if ((layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType) && (isAssignable)) {
isSupported = mOtfMPPs[j]->isSupported(*display, src_img, dst_img);
HDEBUGLOGD(eDebugResourceManager, "\t\t\t isSuported(%" PRIx64 ")", -isSupported);
if (isSupported == NO_ERROR) {
*otfMPP = mOtfMPPs[j];
return HWC2_COMPOSITION_DEVICE;
}
}
}
}
/* 2. Find available m2mMPP */
for (uint32_t j = 0; j < mM2mMPPs.size(); j++) {
if ((display->mUseDpu == true) &&
(mM2mMPPs[j]->mLogicalType == MPP_LOGICAL_G2D_COMBO))
continue;
if ((display->mUseDpu == false) &&
(mM2mMPPs[j]->mLogicalType == MPP_LOGICAL_G2D_RGB))
continue;
/* Only G2D can be assigned if layer is supported by G2D
* when window is not sufficient
*/
if ((validateFlag == eInsufficientWindow) &&
(mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_RGB) &&
(mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_COMBO)) {
HDEBUGLOGD(eDebugResourceManager, "\t\tInsufficient window but exynosComposition is not assigned");
continue;
}
bool isAssignableState = mM2mMPPs[j]->isAssignableState(display, src_img, dst_img);
HDEBUGLOGD(eDebugResourceManager, "\t\t check %s: supportedBit(%d), isAssignableState(%d)",
mM2mMPPs[j]->mName.string(),
(layer->mSupportedMPPFlag & mM2mMPPs[j]->mLogicalType), isAssignableState);
if (isAssignableState) {
if ((mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_RGB) &&
(mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_COMBO)) {
exynos_image otf_dst_img = dst_img;
otf_dst_img.format = DEFAULT_MPP_DST_FORMAT;
std::vector<exynos_image> image_lists;
if ((ret = getCandidateM2mMPPOutImages(display, layer, image_lists)) < 0)
{
HWC_LOGE(display, "Fail getCandidateM2mMPPOutImages (%d)", ret);
return ret;
}
HDEBUGLOGD(eDebugResourceManager, "candidate M2mMPPOutImage num: %zu", image_lists.size());
for (auto &otf_src_img : image_lists) {
dumpExynosImage(eDebugResourceManager, otf_src_img);
exynos_image m2m_src_img = src_img;
/* transform is already handled by m2mMPP */
if (CC_UNLIKELY(otf_src_img.transform != 0 || otf_dst_img.transform != 0)) {
ALOGE("%s:: transform should be handled by m2mMPP. otf_src_img "
"transform %d, otf_dst_img transform %d",
__func__, otf_src_img.transform, otf_dst_img.transform);
otf_src_img.transform = 0;
otf_dst_img.transform = 0;
}
/*
* This is the case that layer color transform should be
* addressed by otfMPP not m2mMPP
*/
if (otf_src_img.needColorTransform)
m2m_src_img.needColorTransform = false;
if (((isSupported = mM2mMPPs[j]->isSupported(*display, m2m_src_img, otf_src_img)) != NO_ERROR) ||
((isAssignable = mM2mMPPs[j]->hasEnoughCapa(display, m2m_src_img, otf_src_img)) == false))
{
HDEBUGLOGD(eDebugResourceManager, "\t\t\t check %s: supportedBit(0x%" PRIx64 "), hasEnoughCapa(%d)",
mM2mMPPs[j]->mName.string(), -isSupported, isAssignable);
continue;
}
/* 3. Find available OtfMPP for output of m2mMPP */
for (uint32_t k = 0; k < mOtfMPPs.size(); k++) {
isSupported = mOtfMPPs[k]->isSupported(*display, otf_src_img, otf_dst_img);
isAssignable = false;
if (isSupported == NO_ERROR)
isAssignable = mOtfMPPs[k]->isAssignable(display, otf_src_img, otf_dst_img);
HDEBUGLOGD(eDebugResourceManager, "\t\t\t check %s: supportedBit(0x%" PRIx64 "), isAssignable(%d)",
mOtfMPPs[k]->mName.string(), -isSupported, isAssignable);
if ((isSupported == NO_ERROR) && isAssignable) {
*m2mMPP = mM2mMPPs[j];
*otfMPP = mOtfMPPs[k];
m2m_out_img = otf_src_img;
return HWC2_COMPOSITION_DEVICE;
}
}
}
} else {
if ((layer->mSupportedMPPFlag & mM2mMPPs[j]->mLogicalType) &&
((isAssignable = mM2mMPPs[j]->hasEnoughCapa(display, src_img, dst_img) == true))) {
*m2mMPP = mM2mMPPs[j];
return HWC2_COMPOSITION_EXYNOS;
} else {
HDEBUGLOGD(eDebugResourceManager, "\t\t\t check %s: layer's mSupportedMPPFlag(0x%8x), hasEnoughCapa(%d)",
mM2mMPPs[j]->mName.string(), layer->mSupportedMPPFlag, isAssignable);
}
}
}
}
}
/* Fail to assign resource */
if (validateFlag != NO_ERROR)
overlayInfo = validateFlag;
else
overlayInfo = eMPPUnsupported;
return HWC2_COMPOSITION_CLIENT;
}
int32_t ExynosResourceManager::assignLayers(ExynosDisplay * display, uint32_t priority)
{
HDEBUGLOGD(eDebugResourceManager, "%s:: display(%d), priority(%d) +++++",
__func__, display->mType, priority);
int32_t ret = NO_ERROR;
bool needReAssign = false;
for (uint32_t i = 0; i < display->mLayers.size(); i++) {
ExynosLayer *layer = display->mLayers[i];
ExynosMPP *m2mMPP = NULL;
ExynosMPP *otfMPP = NULL;
exynos_image m2m_out_img;
uint32_t validateFlag = 0;
int32_t compositionType = 0;
if ((layer->mValidateCompositionType == HWC2_COMPOSITION_CLIENT) ||
(layer->mValidateCompositionType == HWC2_COMPOSITION_EXYNOS))
continue;
if (layer->mOverlayPriority != priority)
continue;
exynos_image src_img;
exynos_image dst_img;
layer->setSrcExynosImage(&src_img);
layer->setDstExynosImage(&dst_img);
layer->setExynosImage(src_img, dst_img);
layer->setExynosMidImage(dst_img);
compositionType = assignLayer(display, layer, i, m2m_out_img, &m2mMPP, &otfMPP, validateFlag);
if (compositionType == HWC2_COMPOSITION_DEVICE) {
if (otfMPP != NULL) {
if ((ret = otfMPP->assignMPP(display, layer)) != NO_ERROR)
{
ALOGE("%s:: %s MPP assignMPP() error (%d)",
__func__, otfMPP->mName.string(), ret);
return ret;
}
HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned",
i, otfMPP->mName.string());
}
if (m2mMPP != NULL) {
if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR)
{
ALOGE("%s:: %s MPP assignMPP() error (%d)",
__func__, m2mMPP->mName.string(), ret);
return ret;
}
layer->setExynosMidImage(m2m_out_img);
HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned",
i, m2mMPP->mName.string());
}
layer->mValidateCompositionType = compositionType;
display->mWindowNumUsed++;
HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: mWindowNumUsed(%d)",
i, display->mWindowNumUsed);
} else if (compositionType == HWC2_COMPOSITION_EXYNOS) {
if (m2mMPP != NULL) {
if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR)
{
ALOGE("%s:: %s MPP assignMPP() error (%d)",
__func__, m2mMPP->mName.string(), ret);
return ret;
}
HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned",
i, m2mMPP->mName.string());
}
layer->mValidateCompositionType = compositionType;
HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: exynosComposition", i);
/* G2D composition */
if (((ret = display->addExynosCompositionLayer(i)) == EXYNOS_ERROR_CHANGED) ||
(ret < 0))
return ret;
else {
/*
* If high fps layer should be composited by GLES then
* disable handling low fps feature and reassign resources
*/
if ((display->mLowFpsLayerInfo.mHasLowFpsLayer == true) &&
(display->mClientCompositionInfo.mHasCompositionLayer == true) &&
((display->mClientCompositionInfo.mFirstIndex < display->mLowFpsLayerInfo.mFirstIndex) ||
(display->mClientCompositionInfo.mLastIndex > display->mLowFpsLayerInfo.mLastIndex))) {
needReAssign = true;
break;
}
}
} else {
/*
* If high fps layer should be composited by GLES then
* disable handling low fps feature and reassign resources
*/
if ((display->mLowFpsLayerInfo.mHasLowFpsLayer == true) &&
(((int32_t)i < display->mLowFpsLayerInfo.mFirstIndex) ||
(display->mLowFpsLayerInfo.mLastIndex < (int32_t)i))) {
needReAssign = true;
break;
}
/* Fail to assign resource, set HWC2_COMPOSITION_CLIENT */
if (validateFlag != NO_ERROR)
layer->mOverlayInfo |= validateFlag;
else
layer->mOverlayInfo |= eMPPUnsupported;
layer->mValidateCompositionType = HWC2_COMPOSITION_CLIENT;
if (((ret = display->addClientCompositionLayer(i)) == EXYNOS_ERROR_CHANGED) ||
(ret < 0))
return ret;
}
}
if (needReAssign) {
if ((display->mClientCompositionInfo.mHasCompositionLayer) &&
(display->mClientCompositionInfo.mOtfMPP != NULL))
display->mClientCompositionInfo.mOtfMPP->resetAssignedState();
if (display->mExynosCompositionInfo.mHasCompositionLayer) {
if (display->mExynosCompositionInfo.mOtfMPP != NULL)
display->mExynosCompositionInfo.mOtfMPP->resetAssignedState();
if (display->mExynosCompositionInfo.mM2mMPP != NULL)
display->mExynosCompositionInfo.mM2mMPP->resetAssignedState();
}
display->initializeValidateInfos();
display->mLowFpsLayerInfo.initializeInfos();
return EXYNOS_ERROR_CHANGED;
}
return ret;
}
int32_t ExynosResourceManager::assignWindow(ExynosDisplay *display)
{
HDEBUGLOGD(eDebugResourceManager, "%s +++++", __func__);
int ret = NO_ERROR;
uint32_t windowIndex = 0;
if (!display->mUseDpu)
return ret;
windowIndex = display->mBaseWindowIndex;
for (uint32_t i = 0; i < display->mLayers.size(); i++) {
ExynosLayer *layer = display->mLayers[i];
HDEBUGLOGD(eDebugResourceManager, "\t[%d] layer type: %d", i, layer->mValidateCompositionType);
if (layer->mValidateCompositionType == HWC2_COMPOSITION_DEVICE) {
layer->mWindowIndex = windowIndex;
HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer windowIndex: %d", i, windowIndex);
} else if ((layer->mValidateCompositionType == HWC2_COMPOSITION_CLIENT) ||
(layer->mValidateCompositionType == HWC2_COMPOSITION_EXYNOS)) {
ExynosCompositionInfo *compositionInfo;
if (layer->mValidateCompositionType == HWC2_COMPOSITION_CLIENT)
compositionInfo = &display->mClientCompositionInfo;
else
compositionInfo = &display->mExynosCompositionInfo;
if ((compositionInfo->mHasCompositionLayer == false) ||
(compositionInfo->mFirstIndex < 0) ||
(compositionInfo->mLastIndex < 0)) {
HWC_LOGE(display, "%s:: Invalid %s CompositionInfo mHasCompositionLayer(%d), "
"mFirstIndex(%d), mLastIndex(%d) ",
__func__, compositionInfo->getTypeStr().string(),
compositionInfo->mHasCompositionLayer,
compositionInfo->mFirstIndex,
compositionInfo->mLastIndex);
continue;
}
if (i != (uint32_t)compositionInfo->mLastIndex)
continue;
compositionInfo->mWindowIndex = windowIndex;
HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] %s Composition windowIndex: %d",
i, compositionInfo->getTypeStr().string(), windowIndex);
} else {
HWC_LOGE(display, "%s:: Invalid layer compositionType layer(%d), compositionType(%d)",
__func__, i, layer->mValidateCompositionType);
continue;
}
windowIndex++;
}
HDEBUGLOGD(eDebugResourceManager, "%s ------", __func__);
return ret;
}
/**
* @param * display
* @return int
*/
int32_t ExynosResourceManager::updateSupportedMPPFlag(ExynosDisplay * display)
{
int64_t ret = 0;
HDEBUGLOGD(eDebugResourceManager, "%s++++++++++", __func__);
for (uint32_t i = 0; i < display->mLayers.size(); i++) {
ExynosLayer *layer = display->mLayers[i];
HDEBUGLOGD(eDebugResourceManager, "[%d] layer ", i);
if (layer->mGeometryChanged == 0)
continue;
exynos_image src_img;
exynos_image dst_img;
exynos_image dst_img_yuv;
layer->setSrcExynosImage(&src_img);
layer->setDstExynosImage(&dst_img);
layer->setDstExynosImage(&dst_img_yuv);
dst_img.format = DEFAULT_MPP_DST_FORMAT;
dst_img_yuv.format = DEFAULT_MPP_DST_YUV_FORMAT;
HDEBUGLOGD(eDebugResourceManager, "\tsrc_img");
dumpExynosImage(eDebugResourceManager, src_img);
HDEBUGLOGD(eDebugResourceManager, "\tdst_img");
dumpExynosImage(eDebugResourceManager, dst_img);
/* Initialize flags */
layer->mSupportedMPPFlag = 0;
layer->mCheckMPPFlag.clear();
/* Check OtfMPPs */
for (uint32_t j = 0; j < mOtfMPPs.size(); j++) {
if ((ret = mOtfMPPs[j]->isSupported(*display, src_img, dst_img)) == NO_ERROR) {
layer->mSupportedMPPFlag |= mOtfMPPs[j]->mLogicalType;
HDEBUGLOGD(eDebugResourceManager, "\t%s: supported", mOtfMPPs[j]->mName.string());
} else {
if (((-ret) == eMPPUnsupportedFormat) &&
((ret = mOtfMPPs[j]->isSupported(*display, src_img, dst_img_yuv)) == NO_ERROR)) {
layer->mSupportedMPPFlag |= mOtfMPPs[j]->mLogicalType;
HDEBUGLOGD(eDebugResourceManager, "\t%s: supported with yuv dst", mOtfMPPs[j]->mName.string());
}
}
if (ret < 0) {
HDEBUGLOGD(eDebugResourceManager, "\t%s: unsupported flag(0x%" PRIx64 ")", mOtfMPPs[j]->mName.string(), -ret);
uint64_t checkFlag = 0x0;
if (layer->mCheckMPPFlag.find(mOtfMPPs[j]->mLogicalType) !=
layer->mCheckMPPFlag.end()) {
checkFlag = layer->mCheckMPPFlag.at(mOtfMPPs[j]->mLogicalType);
}
checkFlag |= (-ret);
layer->mCheckMPPFlag[mOtfMPPs[j]->mLogicalType] = checkFlag;
}
}
/* Check M2mMPPs */
for (uint32_t j = 0; j < mM2mMPPs.size(); j++) {
if ((ret = mM2mMPPs[j]->isSupported(*display, src_img, dst_img)) == NO_ERROR) {
layer->mSupportedMPPFlag |= mM2mMPPs[j]->mLogicalType;
HDEBUGLOGD(eDebugResourceManager, "\t%s: supported", mM2mMPPs[j]->mName.string());
} else {
if (((-ret) == eMPPUnsupportedFormat) &&
((ret = mM2mMPPs[j]->isSupported(*display, src_img, dst_img_yuv)) == NO_ERROR)) {
layer->mSupportedMPPFlag |= mM2mMPPs[j]->mLogicalType;
HDEBUGLOGD(eDebugResourceManager, "\t%s: supported with yuv dst", mM2mMPPs[j]->mName.string());
}
}
if (ret < 0) {
HDEBUGLOGD(eDebugResourceManager, "\t%s: unsupported flag(0x%" PRIx64 ")", mM2mMPPs[j]->mName.string(), -ret);
uint64_t checkFlag = 0x0;
if (layer->mCheckMPPFlag.find(mM2mMPPs[j]->mLogicalType) !=
layer->mCheckMPPFlag.end()) {
checkFlag = layer->mCheckMPPFlag.at(mM2mMPPs[j]->mLogicalType);
}
checkFlag |= (-ret);
layer->mCheckMPPFlag[mM2mMPPs[j]->mLogicalType] = checkFlag;
}
}
HDEBUGLOGD(eDebugResourceManager, "[%d] layer mSupportedMPPFlag(0x%8x)", i, layer->mSupportedMPPFlag);
}
HDEBUGLOGD(eDebugResourceManager, "%s-------------", __func__);
return NO_ERROR;
}
int32_t ExynosResourceManager::resetResources()
{
HDEBUGLOGD(eDebugResourceManager, "%s+++++++++", __func__);
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
mOtfMPPs[i]->resetMPP();
if (hwcCheckDebugMessages(eDebugResourceManager)) {
String8 dumpMPP;
mOtfMPPs[i]->dump(dumpMPP);
HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
}
}
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
mM2mMPPs[i]->resetMPP();
if (hwcCheckDebugMessages(eDebugResourceManager)) {
String8 dumpMPP;
mM2mMPPs[i]->dump(dumpMPP);
HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
}
}
HDEBUGLOGD(eDebugResourceManager, "%s-----------", __func__);
return NO_ERROR;
}
int32_t ExynosResourceManager::preAssignResources()
{
HDEBUGLOGD(eDebugResourceManager, "%s+++++++++", __func__);
uint32_t displayMode = mDevice->mDisplayMode;
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
if (mOtfMPPs[i]->mEnable == false) {
mOtfMPPs[i]->reserveMPP();
continue;
}
if (mOtfMPPs[i]->mPreAssignDisplayList[displayMode] != 0) {
HDEBUGLOGD(eDebugResourceManager, "\t%s check, dispMode(%d), 0x%8x", mOtfMPPs[i]->mName.string(), displayMode, mOtfMPPs[i]->mPreAssignDisplayList[displayMode]);
ExynosDisplay *display = NULL;
for (size_t j = 0; j < mDevice->mDisplays.size(); j++) {
display = mDevice->mDisplays[j];
if (display == nullptr)
continue;
int checkBit = mOtfMPPs[i]->mPreAssignDisplayList[displayMode] & display->getDisplayPreAssignBit();
HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), checkBit(%d)", j, checkBit);
if (checkBit) {
HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), displayId(%d), display(%p)", j, display->mDisplayId, display);
if (display->mDisplayControl.forceReserveMPP ||
(display->mPlugState &&
((display->mType != HWC_DISPLAY_PRIMARY) ||
(display->mPowerModeState != HWC2_POWER_MODE_OFF)))) {
HDEBUGLOGD(eDebugResourceManager, "\t\treserve to display %d", display->mDisplayId);
mOtfMPPs[i]->reserveMPP(display->mDisplayId);
break;
}
}
}
}
}
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if (mM2mMPPs[i]->mEnable == false) {
mM2mMPPs[i]->reserveMPP();
continue;
}
if (mResourceReserved & mM2mMPPs[i]->mLogicalType) {
/* MSC can't be used for rendering */
HDEBUGLOGD(eDebugResourceManager, "\t\tMPP_MSC reserve without display because preview is running");
mM2mMPPs[i]->reserveMPP();
continue;
}
HDEBUGLOGD(eDebugResourceManager, "\t%s check, 0x%8x", mM2mMPPs[i]->mName.string(), mM2mMPPs[i]->mPreAssignDisplayList[displayMode]);
if (mM2mMPPs[i]->mPreAssignDisplayList[displayMode] != 0) {
ExynosDisplay *display = NULL;
for (size_t j = 0; j < mDevice->mDisplays.size(); j++) {
display = mDevice->mDisplays[j];
int checkBit = mM2mMPPs[i]->mPreAssignDisplayList[displayMode] & display->getDisplayPreAssignBit();
HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), checkBit(%d)", j, checkBit);
if (checkBit) {
HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), displayId(%d), display(%p)", j, display->mDisplayId, display);
if ((display != NULL) && (display->mPlugState == true)) {
HDEBUGLOGD(eDebugResourceManager, "\t\treserve to display %d", display->mDisplayId);
mM2mMPPs[i]->reserveMPP(display->mDisplayId);
break;
} else {
HDEBUGLOGD(eDebugResourceManager, "\t\treserve without display");
mM2mMPPs[i]->reserveMPP();
}
}
}
}
}
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
if (hwcCheckDebugMessages(eDebugResourceManager)) {
String8 dumpMPP;
mOtfMPPs[i]->dump(dumpMPP);
HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
}
}
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if (hwcCheckDebugMessages(eDebugResourceManager)) {
String8 dumpMPP;
mM2mMPPs[i]->dump(dumpMPP);
HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.string());
}
}
HDEBUGLOGD(eDebugResourceManager, "%s-----------", __func__);
return NO_ERROR;
}
void ExynosResourceManager::preAssignWindows()
{
ExynosDisplay *display = NULL;
ExynosPrimaryDisplayModule *primaryDisplay =
(ExynosPrimaryDisplayModule *)mDevice->getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0));
primaryDisplay->usePreDefinedWindow(false);
for (size_t i = 1; i < mDevice->mDisplays.size(); i++) {
display = mDevice->mDisplays[i];
if ((display == NULL) || (display->mType != HWC_DISPLAY_EXTERNAL))
continue;
if (display->mPlugState == true) {
primaryDisplay->usePreDefinedWindow(true);
}
}
}
int32_t ExynosResourceManager::preProcessLayer(ExynosDisplay * display)
{
int32_t ret = 0;
hasHdrLayer = false;
hasDrmLayer = false;
for (uint32_t i = 0; i < display->mLayers.size(); i++) {
ExynosLayer *layer = display->mLayers[i];
if ((ret = layer->doPreProcess()) < 0) {
HWC_LOGE(display, "%s:: doPreProcess() error, display(%d), layer %d", __func__, display->mType, i);
return ret;
}
/* mIsHdrLayer is known after preprocess */
if (layer->mIsHdrLayer) hasHdrLayer = true;
if ((layer->mLayerBuffer != NULL) && (getDrmMode(layer->mLayerBuffer) != NO_DRM))
hasDrmLayer = true;
}
// Re-align layer priority for max overlay resources
uint32_t mNumMaxPriorityLayers = 0;
for (int i = (display->mLayers.size()-1); i >= 0; i--) {
ExynosLayer *layer = display->mLayers[i];
HDEBUGLOGD(eDebugResourceManager, "Priority align: i:%d, layer priority:%d, Max:%d, mNumMaxPriorityAllowed:%d", i,
layer->mOverlayPriority, mNumMaxPriorityLayers, display->mNumMaxPriorityAllowed);
if (layer->mOverlayPriority == ePriorityMax) {
if (mNumMaxPriorityLayers >= display->mNumMaxPriorityAllowed) {
layer->mOverlayPriority = ePriorityHigh;
}
mNumMaxPriorityLayers++;
}
}
return NO_ERROR;
}
ExynosMPP* ExynosResourceManager::getExynosMPP(uint32_t type)
{
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
if (mOtfMPPs[i]->mLogicalType == type)
return mOtfMPPs[i];
}
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if (mM2mMPPs[i]->mLogicalType == type)
return mM2mMPPs[i];
}
return NULL;
}
ExynosMPP* ExynosResourceManager::getExynosMPP(uint32_t physicalType, uint32_t physicalIndex)
{
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
if ((mOtfMPPs[i]->mPhysicalType == physicalType) &&
(mOtfMPPs[i]->mPhysicalIndex == physicalIndex))
return mOtfMPPs[i];
}
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if ((mM2mMPPs[i]->mPhysicalType == physicalType) &&
(mM2mMPPs[i]->mPhysicalIndex == physicalIndex))
return mM2mMPPs[i];
}
return NULL;
}
int32_t ExynosResourceManager::updateResourceState()
{
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
if (mOtfMPPs[i]->mAssignedSources.size() == 0)
mOtfMPPs[i]->requestHWStateChange(MPP_HW_STATE_IDLE);
mOtfMPPs[i]->mPrevAssignedState = mOtfMPPs[i]->mAssignedState;
}
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if (mM2mMPPs[i]->mAssignedSources.size() == 0)
mM2mMPPs[i]->requestHWStateChange(MPP_HW_STATE_IDLE);
mM2mMPPs[i]->mPrevAssignedState = mM2mMPPs[i]->mAssignedState;
}
return NO_ERROR;
}
/*
* This function is called every frame.
* This base function does nothing.
* Module that supports setting frame rate should implement this function
* in the module source code (hardware/samsung_slsi/graphics/exynos...).
*/
void ExynosResourceManager::setFrameRateForPerformance(ExynosMPP &mpp,
AcrylicPerformanceRequestFrame *frame)
{
int fps = ceil(msecsPerSec / mpp.mCapacity);
HDEBUGLOGD(eDebugResourceAssigning, "%s setFrameRate %d",
mpp.mName.string(), fps);
frame->setFrameRate(fps);
}
int32_t ExynosResourceManager::deliverPerformanceInfo()
{
int ret = NO_ERROR;
for (uint32_t mpp_physical_type = 0; mpp_physical_type < MPP_P_TYPE_MAX; mpp_physical_type++) {
/* Only G2D gets performance info in current version */
if (mpp_physical_type != MPP_G2D)
continue;
AcrylicPerformanceRequest request;
uint32_t assignedInstanceNum = 0;
uint32_t assignedInstanceIndex = 0;
ExynosMPP *mpp = NULL;
bool canSkipSetting = true;
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
mpp = mM2mMPPs[i];
if (mpp->mPhysicalType != mpp_physical_type)
continue;
/* Performance setting can be skipped
* if all of instance's mPrevAssignedState, mAssignedState
* are MPP_ASSIGN_STATE_FREE
*/
if ((mpp->mPrevAssignedState & MPP_ASSIGN_STATE_ASSIGNED) ||
(mpp->mAssignedState & MPP_ASSIGN_STATE_ASSIGNED))
{
canSkipSetting = false;
}
if (mpp->canSkipProcessing())
continue;
if ((mpp->mAssignedDisplay != NULL) &&
(mpp->mAssignedSources.size() > 0))
{
assignedInstanceNum++;
}
}
if ((canSkipSetting == true) && (assignedInstanceNum != 0)) {
HWC_LOGE(NULL, "%s:: canSKip true but assignedInstanceNum(%d)",
__func__, assignedInstanceNum);
}
request.reset(assignedInstanceNum);
if (canSkipSetting == true)
continue;
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
mpp = mM2mMPPs[i];
if ((mpp->mPhysicalType == mpp_physical_type) &&
(mpp->mAssignedDisplay != NULL) &&
(mpp->mAssignedSources.size() > 0))
{
if (mpp->canSkipProcessing())
continue;
if (assignedInstanceIndex >= assignedInstanceNum) {
HWC_LOGE(NULL,"assignedInstanceIndex error (%d, %d)", assignedInstanceIndex, assignedInstanceNum);
break;
}
AcrylicPerformanceRequestFrame *frame = request.getFrame(assignedInstanceIndex);
if(frame->reset(mpp->mAssignedSources.size()) == false) {
HWC_LOGE(NULL,"%d frame reset fail (%zu)", assignedInstanceIndex, mpp->mAssignedSources.size());
break;
}
setFrameRateForPerformance(*mpp, frame);
for (uint32_t j = 0; j < mpp->mAssignedSources.size(); j++) {
ExynosMPPSource* mppSource = mpp->mAssignedSources[j];
frame->setSourceDimension(j,
mppSource->mSrcImg.w, mppSource->mSrcImg.h,
mppSource->mSrcImg.format);
if (mppSource->mSrcImg.compressed == 1)
frame->setAttribute(j, AcrylicCanvas::ATTR_COMPRESSED);
hwc_rect_t src_area;
src_area.left = mppSource->mSrcImg.x;
src_area.top = mppSource->mSrcImg.y;
src_area.right = mppSource->mSrcImg.x + mppSource->mSrcImg.w;
src_area.bottom = mppSource->mSrcImg.y + mppSource->mSrcImg.h;
hwc_rect_t out_area;
out_area.left = mppSource->mMidImg.x;
out_area.top = mppSource->mMidImg.y;
out_area.right = mppSource->mMidImg.x + mppSource->mMidImg.w;
out_area.bottom = mppSource->mMidImg.y + mppSource->mMidImg.h;
frame->setTransfer(j, src_area, out_area, mppSource->mSrcImg.transform);
}
uint32_t format = mpp->mAssignedSources[0]->mMidImg.format;
bool hasSolidColorLayer = false;
if (mpp->mNeedSolidColorLayer) {
format = DEFAULT_MPP_DST_FORMAT;
hasSolidColorLayer = true;
}
frame->setTargetDimension(mpp->mAssignedDisplay->mXres,
mpp->mAssignedDisplay->mYres, format, hasSolidColorLayer);
assignedInstanceIndex++;
}
}
if ((mpp = getExynosMPP(MPP_LOGICAL_G2D_RGB)) != NULL)
mpp->mAcrylicHandle->requestPerformanceQoS(&request);
else
HWC_LOGE(NULL,"getExynosMPP(MPP_LOGICAL_G2D_RGB) failed");
}
return ret;
}
/*
* Get used capacity of the resource that abstracts same HW resource
* but it is different instance with mpp
*/
float ExynosResourceManager::getResourceUsedCapa(ExynosMPP &mpp)
{
float usedCapa = 0;
if (mpp.mCapacity < 0)
return usedCapa;
HDEBUGLOGD(eDebugResourceManager, "%s:: [%s][%d] mpp[%d, %d]",
__func__, mpp.mName.string(), mpp.mLogicalIndex,
mpp.mPhysicalType, mpp.mPhysicalIndex);
if (mpp.mMPPType == MPP_TYPE_OTF) {
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
if ((mpp.mPhysicalType == mOtfMPPs[i]->mPhysicalType) &&
(mpp.mPhysicalIndex == mOtfMPPs[i]->mPhysicalIndex)) {
usedCapa += mOtfMPPs[i]->mUsedCapacity;
}
}
} else {
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if ((mpp.mPhysicalType == mM2mMPPs[i]->mPhysicalType) &&
(mpp.mPhysicalIndex == mM2mMPPs[i]->mPhysicalIndex)) {
usedCapa += mM2mMPPs[i]->mUsedCapacity;
}
}
}
HDEBUGLOGD(eDebugResourceManager, "\t[%s][%d] mpp usedCapa: %f",
mpp.mName.string(), mpp.mLogicalIndex, usedCapa);
return usedCapa;
}
void ExynosResourceManager::enableMPP(uint32_t physicalType, uint32_t physicalIndex, uint32_t logicalIndex, uint32_t enable)
{
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
if ((mOtfMPPs[i]->mPhysicalType == physicalType) &&
(mOtfMPPs[i]->mPhysicalIndex == physicalIndex) &&
(mOtfMPPs[i]->mLogicalIndex == logicalIndex)) {
mOtfMPPs[i]->mEnable = !!(enable);
return;
}
}
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if ((mM2mMPPs[i]->mPhysicalType == physicalType) &&
(mM2mMPPs[i]->mPhysicalIndex == physicalIndex) &&
(mM2mMPPs[i]->mLogicalIndex == logicalIndex)) {
mM2mMPPs[i]->mEnable = !!(enable);
return;
}
}
}
void ExynosResourceManager::setScaleDownRatio(uint32_t physicalType,
uint32_t physicalIndex, uint32_t logicalIndex, uint32_t scaleDownRatio)
{
ExynosMPP *findMpp = nullptr;
auto mpp_compare = [=](ExynosMPP *mpp)->bool {
return ((mpp->mPhysicalType == physicalType) &&
(mpp->mPhysicalIndex == physicalIndex) &&
(mpp->mLogicalIndex == logicalIndex));
};
auto otfMPP = std::find_if(mOtfMPPs.begin(), mOtfMPPs.end(),
mpp_compare);
if (otfMPP != mOtfMPPs.end()) {
findMpp = *otfMPP;
} else {
auto m2mMPP = std::find_if(mM2mMPPs.begin(), mM2mMPPs.end(),
mpp_compare);
findMpp = m2mMPP == mM2mMPPs.end() ? nullptr : *m2mMPP;
}
if (findMpp == nullptr) {
ALOGE("%s:: Invalid mpp (type: %d, index: %d, %d)",
__func__, physicalType, physicalIndex, logicalIndex);
return;
}
for (uint32_t i = RESTRICTION_RGB; i < RESTRICTION_MAX; i++) {
findMpp->mDstSizeRestrictions[i].maxDownScale = scaleDownRatio;
}
}
int32_t ExynosResourceManager::prepareResources()
{
int ret = NO_ERROR;
HDEBUGLOGD(eDebugResourceManager, "This is first validate");
if ((ret = resetResources()) != NO_ERROR) {
HWC_LOGE(NULL,"%s:: resetResources() error (%d)",
__func__, ret);
return ret;
}
if ((ret = preAssignResources()) != NO_ERROR) {
HWC_LOGE(NULL,"%s:: preAssignResources() error (%d)",
__func__, ret);
return ret;
}
return ret;
}
int32_t ExynosResourceManager::finishAssignResourceWork()
{
int ret = NO_ERROR;
if ((ret = updateResourceState()) != NO_ERROR) {
HWC_LOGE(NULL,"%s:: stopUnAssignedResource() error (%d)",
__func__, ret);
return ret;
}
mDevice->clearGeometryChanged();
return ret;
}
int32_t ExynosResourceManager::initResourcesState(ExynosDisplay *display)
{
int ret = 0;
if (mDevice->isFirstValidate()) {
HDEBUGLOGD(eDebugResourceManager, "This is first validate");
if (exynosHWCControl.displayMode < DISPLAY_MODE_NUM)
mDevice->mDisplayMode = exynosHWCControl.displayMode;
if ((ret = prepareResources()) != NO_ERROR) {
HWC_LOGE(display, "%s:: prepareResources() error (%d)",
__func__, ret);
return ret;
}
preAssignWindows();
}
return NO_ERROR;
}
void ExynosResourceManager::makeSizeRestrictions(uint32_t mppId, const restriction_size_t &size,
restriction_classification_t format) {
mSizeRestrictions[format][mSizeRestrictionCnt[format]].key.hwType = static_cast<mpp_phycal_type_t>(mppId);
mSizeRestrictions[format][mSizeRestrictionCnt[format]].key.nodeType = NODE_SRC;
mSizeRestrictions[format][mSizeRestrictionCnt[format]].key.format = HAL_PIXEL_FORMAT_NONE;
mSizeRestrictions[format][mSizeRestrictionCnt[format]].key.reserved = 0;
mSizeRestrictions[format][mSizeRestrictionCnt[format]++].sizeRestriction = size;
mSizeRestrictions[format][mSizeRestrictionCnt[format]].key.hwType = static_cast<mpp_phycal_type_t>(mppId);
mSizeRestrictions[format][mSizeRestrictionCnt[format]].key.nodeType = NODE_DST;
mSizeRestrictions[format][mSizeRestrictionCnt[format]].key.format = HAL_PIXEL_FORMAT_NONE;
mSizeRestrictions[format][mSizeRestrictionCnt[format]].key.reserved = 0;
mSizeRestrictions[format][mSizeRestrictionCnt[format]++].sizeRestriction = size;
HDEBUGLOGD(eDebugDefault, "MPP : %s, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
getMPPStr(mppId).string(),
size.maxDownScale,
size.maxUpScale,
size.maxFullWidth,
size.maxFullHeight,
size.minFullWidth,
size.minFullHeight,
size.fullWidthAlign,
size.fullHeightAlign,
size.maxCropWidth,
size.maxCropHeight,
size.minCropWidth,
size.minCropHeight,
size.cropXAlign,
size.cropYAlign,
size.cropWidthAlign,
size.cropHeightAlign);
}
void ExynosResourceManager::makeFormatRestrictions(restriction_key_t table) {
mFormatRestrictions[mFormatRestrictionCnt] = table;
HDEBUGLOGD(eDebugDefault, "MPP : %s, %d, %s, %d",
getMPPStr(mFormatRestrictions[mFormatRestrictionCnt].hwType).string(),
mFormatRestrictions[mFormatRestrictionCnt].nodeType,
getFormatStr(mFormatRestrictions[mFormatRestrictionCnt].format, COMP_ANY).string(),
mFormatRestrictions[mFormatRestrictionCnt].reserved);
mFormatRestrictionCnt++;
}
void ExynosResourceManager::makeAcrylRestrictions(mpp_phycal_type_t type){
Acrylic *arc = NULL;
const HW2DCapability *cap;
if (type == MPP_MSC)
arc = Acrylic::createScaler();
else if (type == MPP_G2D)
arc = Acrylic::createCompositor();
else {
ALOGE("Unknown MPP");
return;
}
cap = &arc->getCapabilities();
/* format restriction */
std::unordered_set<int32_t> supportedHalFormats;
for (uint32_t i = 0; i < FORMAT_MAX_CNT; i++) {
if (cap->isFormatSupported(exynos_format_desc[i].halFormat)) {
/* Not add same hal pixel format */
if (supportedHalFormats.find(exynos_format_desc[i].halFormat) !=
supportedHalFormats.end())
continue;
restriction_key_t queried_format;
queried_format.hwType = type;
queried_format.nodeType = NODE_NONE;
queried_format.format = exynos_format_desc[i].halFormat;
queried_format.reserved = 0;
makeFormatRestrictions(queried_format);
supportedHalFormats.insert(exynos_format_desc[i].halFormat);
}
}
/* RGB size restrictions */
restriction_size rSize;
rSize.maxDownScale = cap->supportedMinMinification().hori;
rSize.maxUpScale = cap->supportedMaxMagnification().hori;
rSize.maxFullWidth = cap->supportedMaxSrcDimension().hori;
rSize.maxFullHeight = cap->supportedMaxSrcDimension().vert;
rSize.minFullWidth = cap->supportedMinSrcDimension().hori;
rSize.minFullHeight = cap->supportedMinSrcDimension().vert;
rSize.fullWidthAlign = cap->supportedDimensionAlign().hori;
rSize.fullHeightAlign = cap->supportedDimensionAlign().vert;
rSize.maxCropWidth = cap->supportedMaxSrcDimension().hori;
rSize.maxCropHeight = cap->supportedMaxSrcDimension().vert;
rSize.minCropWidth = cap->supportedMinSrcDimension().hori;
rSize.minCropHeight = cap->supportedMinSrcDimension().vert;
rSize.cropXAlign = cap->supportedDimensionAlign().hori;
rSize.cropYAlign = cap->supportedDimensionAlign().vert;
rSize.cropWidthAlign = cap->supportedDimensionAlign().hori;
rSize.cropHeightAlign = cap->supportedDimensionAlign().vert;
makeSizeRestrictions(type, rSize, RESTRICTION_RGB);
/* YUV size restrictions */
rSize.fullWidthAlign = max(static_cast<uint32_t>(cap->supportedDimensionAlign().hori),
YUV_CHROMA_H_SUBSAMPLE);
rSize.fullHeightAlign = max(static_cast<uint32_t>(cap->supportedDimensionAlign().vert),
YUV_CHROMA_V_SUBSAMPLE);
rSize.cropXAlign = max(static_cast<uint32_t>(cap->supportedDimensionAlign().hori),
YUV_CHROMA_H_SUBSAMPLE);
rSize.cropYAlign = max(static_cast<uint32_t>(cap->supportedDimensionAlign().vert),
YUV_CHROMA_V_SUBSAMPLE);
rSize.cropWidthAlign = max(static_cast<uint32_t>(cap->supportedDimensionAlign().hori),
YUV_CHROMA_H_SUBSAMPLE);
rSize.cropHeightAlign = max(static_cast<uint32_t>(cap->supportedDimensionAlign().vert),
YUV_CHROMA_V_SUBSAMPLE);
makeSizeRestrictions(type, rSize, RESTRICTION_YUV);
delete arc;
}
mpp_phycal_type_t ExynosResourceManager::getPhysicalType(int ch) const {
for (int i=0; i < MAX_DECON_DMA_TYPE; i++){
if(IDMA_CHANNEL_MAP[i].channel == ch)
return IDMA_CHANNEL_MAP[i].type;
}
return MPP_P_TYPE_MAX;
}
ExynosMPP* ExynosResourceManager::getOtfMPPWithChannel(int ch)
{
ExynosMPP *otfMPP = NULL;
for (int i=0; i < MAX_DECON_DMA_TYPE; i++){
if(IDMA_CHANNEL_MAP[i].channel == ch) {
otfMPP = getExynosMPP(IDMA_CHANNEL_MAP[i].type, IDMA_CHANNEL_MAP[i].index);
break;
}
}
return otfMPP;
}
void ExynosResourceManager::updateRestrictions() {
if (mDevice->mDeviceInterface->getUseQuery() == true) {
std::unordered_set<uint32_t> checkDuplicateMPP;
for (const auto unit: AVAILABLE_M2M_MPP_UNITS) {
if (checkDuplicateMPP.find(unit.physicalType) ==
checkDuplicateMPP.end()) {
makeAcrylRestrictions(static_cast<mpp_phycal_type_t>(unit.physicalType));
checkDuplicateMPP.insert(unit.physicalType);
}
}
} else {
mFormatRestrictionCnt = sizeof(restriction_format_table)/sizeof(restriction_key);
for (uint32_t i = 0 ; i < mFormatRestrictionCnt; i++) {
mFormatRestrictions[i].hwType = restriction_format_table[i].hwType;
mFormatRestrictions[i].nodeType = restriction_format_table[i].nodeType;
mFormatRestrictions[i].format = restriction_format_table[i].format;
mFormatRestrictions[i].reserved = restriction_format_table[i].reserved;
}
// i = RGB, YUV
// j = Size restriction count for each format (YUV, RGB)
for (uint32_t i = 0; i < sizeof(restriction_tables)/sizeof(restriction_table_element); i++) {
mSizeRestrictionCnt[i] = restriction_tables[i].table_element_size;
for (uint32_t j = 0; j < mSizeRestrictionCnt[i]; j++) {
memcpy(&mSizeRestrictions[i][j], &restriction_tables[i].table[j],
sizeof(mSizeRestrictions[i][j]));
}
}
}
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
// mAttr should be updated with updated feature_table
mOtfMPPs[i]->updateAttr();
mOtfMPPs[i]->setupRestriction();
}
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
// mAttr should be updated with updated feature_table
mM2mMPPs[i]->updateAttr();
mM2mMPPs[i]->setupRestriction();
}
}
uint32_t ExynosResourceManager::getFeatureTableSize() const
{
return sizeof(feature_table)/sizeof(feature_support_t);
}
bool ExynosResourceManager::hasHDR10PlusMPP() {
for (uint32_t i = 0; i < mOtfMPPs.size(); i++) {
if (mOtfMPPs[i] == NULL) continue;
if (mOtfMPPs[i]->mAttr & MPP_ATTR_HDR10PLUS)
return true;
}
for (uint32_t i = 0; i < mM2mMPPs.size(); i++) {
if (mM2mMPPs[i] == NULL) continue;
if (mM2mMPPs[i]->mAttr & MPP_ATTR_HDR10PLUS)
return true;
}
return false;
}
float ExynosResourceManager::getAssignedCapacity(uint32_t physicalType)
{
float totalCapacity = 0;
for (size_t i = 0; i < mM2mMPPs.size(); i++) {
if (mM2mMPPs[i]->mPhysicalType == physicalType)
totalCapacity += mM2mMPPs[i]->getAssignedCapacity();
}
return totalCapacity;
}
float ExynosResourceManager::getM2MCapa(uint32_t physicalType)
{
float ret = 0;
for (size_t i = 0; i < mM2mMPPs.size(); i++) {
if (mM2mMPPs[i]->mPhysicalType == physicalType)
return mM2mMPPs[i]->mCapacity;
}
return ret;
}
void ExynosResourceManager::dump(String8 &result) const {
result.appendFormat("Resource Manager:\n");
result.appendFormat("[RGB Restrictions]\n");
dump(RESTRICTION_RGB, result);
result.appendFormat("[YUV Restrictions]\n");
dump(RESTRICTION_YUV, result);
}
void ExynosResourceManager::dump(const restriction_classification_t classification,
String8 &result) const {
const auto &restrictions = mSizeRestrictions[classification];
const auto &restrictionCnt = mSizeRestrictionCnt[classification];
for (int i = 0; i < restrictionCnt; ++i) {
result.appendFormat("HW-Node %u-%u:\n", restrictions[i].key.hwType,
restrictions[i].key.nodeType);
if (i > 0 && restrictions[i].sizeRestriction == restrictions[i - 1].sizeRestriction) {
result.append("Same as above\n");
} else {
::dump(restrictions[i].sizeRestriction, result);
}
result.appendFormat("\n");
}
}
void ExynosResourceManager::setM2MCapa(uint32_t physicalType, uint32_t capa)
{
for (size_t i = 0; i < mM2mMPPs.size(); i++) {
if (mM2mMPPs[i]->mPhysicalType == physicalType)
mM2mMPPs[i]->mCapacity = capa;
}
}