blob: a9b9d1b3d5c1c0e24d655ac3902295e547641078 [file] [log] [blame]
/*
* 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 <cutils/properties.h>
#include <system/graphics.h>
#include "ExynosResourceManager.h"
#include "ExynosMPPModule.h"
#include "ExynosResourceRestriction.h"
#include "ExynosLayer.h"
#include "ExynosHWCDebug.h"
#include "ExynosHWCHelper.h"
#include "hardware/exynos/acryl.h"
#include "ExynosPrimaryDisplayModule.h"
#include "ExynosVirtualDisplay.h"
#include "ExynosExternalDisplay.h"
#include "ExynosDeviceInterface.h"
/* Basic supported features */
feature_support_t feature_table[] =
{
{MPP_DPP_G,
MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM | MPP_ATTR_CUSTOM_ROT
},
{MPP_DPP_GF,
MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM | MPP_ATTR_CUSTOM_ROT
},
{MPP_DPP_VG,
MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM | MPP_ATTR_CUSTOM_ROT
},
{MPP_DPP_VGS,
MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_SCALE | MPP_ATTR_DIM | MPP_ATTR_CUSTOM_ROT
},
{MPP_DPP_VGF,
MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM | MPP_ATTR_CUSTOM_ROT
},
{MPP_DPP_VGFS,
MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_SCALE | MPP_ATTR_DIM | MPP_ATTR_CUSTOM_ROT
},
{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_ROT_180 | MPP_ATTR_ROT_270 | MPP_ATTR_CUSTOM_ROT |
MPP_ATTR_DIM | MPP_ATTR_HDR10
},
{MPP_MSC,
MPP_ATTR_FLIP_H | MPP_ATTR_FLIP_V | MPP_ATTR_ROT_90 | MPP_ATTR_ROT_180 | MPP_ATTR_ROT_270
},
{MPP_G2D,
MPP_ATTR_AFBC | MPP_ATTR_FLIP_H | MPP_ATTR_FLIP_V | MPP_ATTR_ROT_90 | MPP_ATTR_ROT_180 | MPP_ATTR_ROT_270 |
MPP_ATTR_HDR10 | MPP_ATTR_USE_CAPA
}
};
using namespace android;
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(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(HWC_DISPLAY_PRIMARY);
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(HWC_DISPLAY_PRIMARY);
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 display_type = 0; display_type < HWC_NUM_DISPLAY_TYPES; display_type++) {
exynosDisplay = mDevice->getDisplay(display_type);
if ((exynosDisplay != NULL) && (exynosDisplay->mPlugState == true)) {
for (uint32_t i = 0; i < exynosDisplay->mLayers.size(); i++) {
ExynosLayer *layer = exynosDisplay->mLayers[i];
if ((layer->mLayerBuffer != NULL) &&
#ifdef GRALLOC_VERSION1
(layer->mLayerBuffer->producer_usage & GRALLOC1_PRODUCER_USAGE_CAMERA)) {
#else
(layer->mLayerBuffer->flags & GRALLOC_USAGE_HW_CAMERA_MASK)) {
#endif
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->mUseDecon) {
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 {
uint32_t firstIndex = (uint32_t)display->mExynosCompositionInfo.mFirstIndex;
uint32_t lastIndex = (uint32_t)display->mExynosCompositionInfo.mLastIndex;
for (uint32_t i = firstIndex; i <= lastIndex; i++) {
if (display->mExynosCompositionInfo.mFirstIndex == -1)
break;
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__);
goto err;
}
}
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__);
goto err;
}
}
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);
goto err;
}
}
display->mExynosCompositionInfo.initializeInfos(display);
ret = EXYNOS_ERROR_CHANGED;
} else {
goto err;
}
}
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)
goto err;
}
}
/* 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;
goto err;
} 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;
err:
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->mUseDecon == true) &&
(mM2mMPPs[i]->mLogicalType != MPP_LOGICAL_G2D_RGB))
continue;
if ((display->mUseDecon == 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->mUseDecon == 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->flags) == NO_DRM) &&
(display->mDREnable == true) &&
(display->mDynamicReCompMode == DEVICE_2_CLIENT))
return eDynamicRecomposition;
if ((layer->mLayerBuffer != NULL) &&
(display->mDisplayId == HWC_DISPLAY_PRIMARY) &&
(mForceReallocState != DST_REALLOC_DONE)) {
ALOGI("Device type assign skipping by dst reallocation...... ");
return eReallocOnGoingForDDI;
}
if (layer->mCompositionType == HWC2_COMPOSITION_CLIENT)
return eSkipLayer;
if (display->mColorTransformHint != HAL_COLOR_TRANSFORM_IDENTITY)
return eUnSupportedColorTransform;
if ((display->mLowFpsLayerInfo.mHasLowFpsLayer == true) &&
(display->mLowFpsLayerInfo.mFirstIndex <= (int32_t)index) &&
((int32_t)index <= display->mLowFpsLayerInfo.mLastIndex))
return eLowFpsLayer;
if(layer->mIsDimLayer && layer->mLayerBuffer == NULL) {
return eDimLayer;
}
if (!(display->mDisplayId == HWC_DISPLAY_VIRTUAL &&
((ExynosVirtualDisplay *)display)->mIsWFDState == (int)LLWFD))
/* Process to Source copy layer blending exception */
if ((display->mBlendingNoneIndex != -1) && (display->mLayers.size() > 0)) {
if ((layer->mOverlayPriority < ePriorityHigh) &&
((int)index <= display->mBlendingNoneIndex))
return eSourceOverBelow;
}
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;
}
int32_t ExynosResourceManager::getCandidateM2mMPPOutImages(ExynosDisplay *display,
ExynosLayer *layer, uint32_t *imageNum, exynos_image *image_lists)
{
uint32_t listSize = *imageNum;
if (listSize != M2M_MPP_OUT_IMAGS_COUNT)
return -EINVAL;
uint32_t index = 0;
exynos_image src_img;
exynos_image dst_img;
layer->setSrcExynosImage(&src_img);
layer->setDstExynosImage(&dst_img);
dst_img.transform = 0;
/* 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.hdrStaticInfo = src_img.hdrStaticInfo;
dst_img.needDegamma = false; //Dst side need not degamma
uint32_t dstW = dst_img.w;
uint32_t dstH = dst_img.h;
bool isPerpendicular = !!(src_img.transform & HAL_TRANSFORM_ROT_90);
if (isPerpendicular) {
dstW = dst_img.h;
dstH = dst_img.w;
}
/* Scale up case */
if ((dstW > src_img.w) && (dstH > src_img.h))
{
/* VGFS doesn't rotate image, m2mMPP rotates image */
src_img.transform = 0;
ExynosMPP *mppVGFS = getExynosMPP(MPP_LOGICAL_DPP_VGFS);
exynos_image dst_scale_img = dst_img;
/* Some chipset have VGS instead of VGFS */
if (mppVGFS == NULL) {
mppVGFS = getExynosMPP(MPP_LOGICAL_DPP_VGS);
if (mppVGFS == NULL)
mppVGFS = getExynosMPP(MPP_LOGICAL_DPP_VG);
}
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;
}
}
uint32_t upScaleRatio = mppVGFS->getMaxUpscale(src_img, dst_scale_img);
uint32_t downScaleRatio = mppVGFS->getMaxDownscale(*display, src_img, dst_scale_img);
uint32_t srcCropWidthAlign = mppVGFS->getSrcCropWidthAlign(src_img);
uint32_t srcCropHeightAlign = mppVGFS->getSrcCropHeightAlign(src_img);
dst_scale_img.x = 0;
dst_scale_img.y = 0;
if (isPerpendicular) {
dst_scale_img.w = pixel_align(src_img.h, srcCropWidthAlign);
dst_scale_img.h = pixel_align(src_img.w, srcCropHeightAlign);
} else {
dst_scale_img.w = pixel_align(src_img.w, srcCropWidthAlign);
dst_scale_img.h = pixel_align(src_img.h, srcCropHeightAlign);
}
HDEBUGLOGD(eDebugResourceManager, "index[%d], w: %d, h: %d, ratio(type: %d, %d, %d)", index, dst_scale_img.w, dst_scale_img.h,
mppVGFS->mLogicalType, upScaleRatio, downScaleRatio);
if (dst_scale_img.w * upScaleRatio < dst_img.w) {
dst_scale_img.w = pixel_align((uint32_t)ceilf((float)dst_img.w/(float)upScaleRatio), srcCropWidthAlign);
}
if (dst_scale_img.h * upScaleRatio < dst_img.h) {
dst_scale_img.h = pixel_align((uint32_t)ceilf((float)dst_img.h/(float)upScaleRatio), srcCropHeightAlign);
}
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);
image_lists[index++] = dst_scale_img;
}
if (isFormatYUV(src_img.format) && !hasHdrInfo(src_img)) {
dst_img.format = DEFAULT_MPP_DST_YUV_FORMAT;
}
ExynosExternalDisplay *external_display = (ExynosExternalDisplay*)mDevice->getDisplay(HWC_DISPLAY_EXTERNAL);
/* 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->mDisplayId == HWC_DISPLAY_PRIMARY))) {
ExynosMPP *mppVGRFS = getExynosMPP(MPP_LOGICAL_DPP_VGRFS);
uint32_t srcCropWidthAlign = 1;
uint32_t srcCropHeightAlign = 1;
if (mppVGRFS != NULL) {
srcCropWidthAlign = mppVGRFS->getSrcCropWidthAlign(dst_img);
srcCropHeightAlign = mppVGRFS->getSrcCropHeightAlign(dst_img);
}
dst_img.w = pixel_align(dst_img.w, srcCropWidthAlign);
dst_img.h = pixel_align(dst_img.h, srcCropHeightAlign);
}
}
image_lists[index++] = 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->mDisplayId == 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->mDisplayId == HWC_DISPLAY_PRIMARY))) {
image_lists[index++] = 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[index++] = dst_img;
}
if (*imageNum < index)
return -EINVAL;
else {
*imageNum = index;
return (uint32_t)listSize;
}
}
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->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) || (validateFlag == eSourceOverBelow)) {
bool isAssignable = false;
uint64_t isSupported = 0;
/* 1. Find available otfMPP */
if ((validateFlag != eInsufficientWindow) &&
(validateFlag != eSourceOverBelow)) {
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->mUseDecon == true) &&
(mM2mMPPs[j]->mLogicalType == MPP_LOGICAL_G2D_COMBO))
continue;
if ((display->mUseDecon == 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) ||
(validateFlag == eSourceOverBelow)) &&
(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;
}
isAssignable = mM2mMPPs[j]->isAssignable(display, src_img, dst_img);
HDEBUGLOGD(eDebugResourceManager, "\t\t check %s: supportedBit(%d), isAssignable(%d)",
mM2mMPPs[j]->mName.string(),
(layer->mSupportedMPPFlag & mM2mMPPs[j]->mLogicalType), isAssignable);
if (isAssignable) {
if ((mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_RGB) &&
(mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_COMBO)) {
exynos_image otf_src_img = dst_img;
exynos_image otf_dst_img = dst_img;
otf_dst_img.format = DEFAULT_MPP_DST_FORMAT;
exynos_image image_lists[M2M_MPP_OUT_IMAGS_COUNT];
uint32_t imageNum = M2M_MPP_OUT_IMAGS_COUNT;
if ((ret = getCandidateM2mMPPOutImages(display, layer, &imageNum, image_lists)) < 0)
{
HWC_LOGE(display, "Fail getCandidateM2mMPPOutImages (%d)", ret);
return ret;
}
HDEBUGLOGD(eDebugResourceManager, "candidate M2mMPPOutImage num: %d", imageNum);
for (uint32_t outImg = 0; outImg < imageNum; outImg++)
{
dumpExynosImage(eDebugResourceManager, image_lists[outImg]);
otf_src_img = image_lists[outImg];
/* transform is already handled by m2mMPP */
otf_src_img.transform = 0;
otf_dst_img.transform = 0;
if ((isSupported = mM2mMPPs[j]->isSupported(*display, src_img, otf_src_img)) != NO_ERROR)
{
HDEBUGLOGD(eDebugResourceManager, "\t\t\t check %s: supportedBit(0x%" PRIx64 ")",
mM2mMPPs[j]->mName.string(), -isSupported);
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) {
*m2mMPP = mM2mMPPs[j];
return HWC2_COMPOSITION_EXYNOS;
}
}
}
}
}
/* 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->mUseDecon)
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.count(mOtfMPPs[j]->mLogicalType) != 0) {
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.count(mM2mMPPs[j]->mLogicalType) != 0) {
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 (uint32_t display_type = 0; display_type < HWC_NUM_DISPLAY_TYPES; display_type++) {
HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay_type(%d), checkBit(%d)", display_type, (mOtfMPPs[i]->mPreAssignDisplayList[displayMode] & (1<<display_type)));
if (mOtfMPPs[i]->mPreAssignDisplayList[displayMode] & (1<<display_type)) {
display = mDevice->getDisplay(display_type);
HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay_type(%d), display(%p)", display_type, display);
if ((display != NULL) && (display->mPlugState == true)) {
HDEBUGLOGD(eDebugResourceManager, "\t\treserve to display %d", display_type);
mOtfMPPs[i]->reserveMPP(display->mType);
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 (uint32_t display_type = HWC_DISPLAY_PRIMARY; display_type < HWC_NUM_DISPLAY_TYPES; display_type++) {
HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay_type(%d), checkBit(%d)", display_type, (mM2mMPPs[i]->mPreAssignDisplayList[displayMode] & (1<<display_type)));
if (mM2mMPPs[i]->mPreAssignDisplayList[displayMode] & (1<<display_type)) {
display = mDevice->getDisplay(display_type);
HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay_type(%d), display(%p)", display_type, display);
if ((display != NULL) && (display->mPlugState == true)) {
HDEBUGLOGD(eDebugResourceManager, "\t\treserve to display %d", display->mType);
mM2mMPPs[i]->reserveMPP(display->mType);
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->mDisplays[HWC_DISPLAY_PRIMARY];
primaryDisplay->usePreDefinedWindow(false);
for (uint32_t display_type = 1; display_type < HWC_NUM_DISPLAY_TYPES; display_type++) {
display = mDevice->getDisplay(display_type);
if ((display == NULL) || (display->mDisplayId != 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;
}
/* Check to need degamma */
if ((display->mDisplayId == HWC_DISPLAY_EXTERNAL) &&
(((ExynosExternalDisplay *)display)->mExternalHdrSupported) && (hasHdrLayer)) {
for (uint32_t i = 0; i < display->mLayers.size(); i++) {
ExynosLayer *layer = display->mLayers[i];
if(!layer->mIsHdrLayer)
layer->mNeedDegamma = 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;
}
void ExynosResourceManager::setFrameRateForPerformance(ExynosMPP __unused &mpp,
AcrylicPerformanceRequestFrame __unused *frame)
{
}
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);
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->mLogicalType == MPP_LOGICAL_G2D_RGB) ||
(mpp->mLogicalType == MPP_LOGICAL_G2D_COMBO)) {
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;
}
}
}
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, 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, int deviceFormat) {
mFormatRestrictions[mFormatRestrictionCnt] = table;
HDEBUGLOGD(eDebugDefault, "MPP : %s, %d, %s(device : %d), %d"
,getMPPStr(mFormatRestrictions[mFormatRestrictionCnt].hwType).string()
,mFormatRestrictions[mFormatRestrictionCnt].nodeType
,getFormatStr(mFormatRestrictions[mFormatRestrictionCnt].format).string(), deviceFormat
,mFormatRestrictions[mFormatRestrictionCnt].reserved);
mFormatRestrictionCnt++;
}
void ExynosResourceManager::makeAcrylRestrictions(mpp_phycal_type_t type){
Acrylic *arc = NULL;
const HW2DCapability *cap;
// restriction_key queried_format_table[128];
int cnt=0;
if (type == MPP_MSC)
arc = Acrylic::createScaler();
else if (type == MPP_G2D)
arc = Acrylic::createCompositor();
else {
ALOGE("Unknown MPP");
return;
}
cap = &arc->getCapabilities();
restriction_key_t queried_format_table[1024];
/* format restriction */
for (uint32_t i = 0; i < FORMAT_MAX_CNT; i++) {
if (cap->isFormatSupported(exynos_format_desc[i].halFormat)) {
queried_format_table[cnt].hwType = type;
queried_format_table[cnt].nodeType = NODE_NONE;
queried_format_table[cnt].format = exynos_format_desc[i].halFormat;
queried_format_table[cnt].reserved = 0;
makeFormatRestrictions(queried_format_table[cnt],
queried_format_table[cnt].format);
cnt++;
}
}
/* 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) {
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) {
makeAcrylRestrictions(MPP_MSC);
makeAcrylRestrictions(MPP_G2D);
} 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(restriction_size_element_t));
}
}
}
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()
{
return sizeof(feature_table)/sizeof(feature_support_t);
}