/* * 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 #include #include #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(); 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(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::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; exynosMPP->initTDMInfo(exynos_mpp.hw_block_index, exynos_mpp.axi_port_index); 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.c_str()); } for (uint32_t i = 0; i < mM2mMPPs.size(); i++) { HDEBUGLOGD(eDebugResourceManager, "m2mMPP[%d]", i); String8 dumpMPP; mM2mMPPs[i]->dump(dumpMPP); HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.c_str()); } } mDstBufMgrThread->mRunning = true; mDstBufMgrThread->run("DstBufMgrThread"); char value[PROPERTY_VALUE_MAX]; mMinimumSdrDimRatio = property_get("debug.hwc.min_sdr_dimming", value, nullptr) > 0 ? std::atof(value) : 0.0f; updateSupportWCG(); } 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; /* TODO(b/265244856): to clarify which display size to alloc */ 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; } } } } 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 ((ret = display->updateColorConversionInfo()) != NO_ERROR) { HWC_LOGE(display, "%s:: updateColorConversionInfo() fail, ret(%d)", __func__, ret); return ret; } display->checkPreblendingRequirement(); HDEBUGLOGD(eDebugTDM, "%s layer's calculation start", __func__); for (uint32_t i = 0; i < display->mLayers.size(); i++) { calculateHWResourceAmount(display, display->mLayers[i]); } 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(display); } 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.c_str()); result.clear(); display->mExynosCompositionInfo.dump(result); HDEBUGLOGD(eDebugResourceManager, "%s", result.c_str()); 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.c_str()); } } 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.c_str(), 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.c_str()); 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.c_str(), 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.c_str()); m2mMPP->reserveMPP(); } } else { HDEBUGLOGD(eDebugResourceManager, "%s setting priority is ok", m2mMPP->mName.c_str()); } } 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(eDebugResourceAssigning, "%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.c_str()); } } } 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(eDebugResourceAssigning, "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 isAssignableState = false; if ((layer->mSupportedMPPFlag & m2mMPP->mLogicalType) != 0) isAssignableState = isAssignable(m2mMPP, display, src_img, dst_img, layer); bool canChange = (layer->mValidateCompositionType != HWC2_COMPOSITION_CLIENT) && ((display->mDisplayControl.cursorSupport == false) || (layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) && (layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignableState; HDEBUGLOGD(eDebugResourceAssigning, "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, " "remainNum(%d)", i, layer->mValidateCompositionType, layer->mSupportedMPPFlag, isAssignableState, 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.c_str(), ret); return ret; } layer->setExynosMidImage(dst_img); float totalUsedCapacity = getResourceUsedCapa(*m2mMPP); display->addExynosCompositionLayer(i, totalUsedCapacity); 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 isAssignableState = false; if ((layer->mSupportedMPPFlag & m2mMPP->mLogicalType) != 0) isAssignableState = isAssignable(m2mMPP, display, src_img, dst_img, layer); bool canChange = (layer->mValidateCompositionType != HWC2_COMPOSITION_CLIENT) && ((display->mDisplayControl.cursorSupport == false) || (layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) && (layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignableState; HDEBUGLOGD(eDebugResourceAssigning, "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, " "remainNum(%d)", i, layer->mValidateCompositionType, layer->mSupportedMPPFlag, isAssignableState, 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.c_str(), ret); return ret; } layer->setExynosMidImage(dst_img); float totalUsedCapacity = getResourceUsedCapa(*m2mMPP); display->addExynosCompositionLayer(i, totalUsedCapacity); layer->mValidateCompositionType = HWC2_COMPOSITION_EXYNOS; remainNum--; } if ((canChange == false) || (remainNum == 0)) break; } } HDEBUGLOGD(eDebugResourceAssigning, "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.c_str(), ret); } // assign otfMPP again if ((ret = otfMPP->assignMPP(display, layer)) != NO_ERROR) { ALOGE("%s:: %s MPP assignMPP() error (%d)", __func__, otfMPP->mName.c_str(), ret); } } } } return ret; } int32_t ExynosResourceManager::changeLayerFromClientToDevice(ExynosDisplay* display, ExynosLayer* layer, uint32_t layer_index, const 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.c_str(), ret); return ret; } HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", layer_index, otfMPP->mName.c_str()); } if (m2mMPP != NULL) { if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR) { ALOGE("%s:: %s MPP assignMPP() error (%d)", __func__, m2mMPP->mName.c_str(), ret); return ret; } layer->setExynosMidImage(m2m_out_img); HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", layer_index, m2mMPP->mName.c_str()); } layer->mValidateCompositionType = HWC2_COMPOSITION_DEVICE; display->mWindowNumUsed++; HDEBUGLOGD(eDebugResourceAssigning, "\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 isAssignableState = false; otfMppReordering(display, mOtfMPPs, src_img, dst_img); for (uint32_t i = 0; i < mOtfMPPs.size(); i++) { compositionInfo->setExynosImage(src_img, dst_img); compositionInfo->setExynosMidImage(dst_img); HDEBUGLOGD(eDebugTDM, "%s M2M target calculation start", __func__); calculateHWResourceAmount(display, compositionInfo); isSupported = mOtfMPPs[i]->isSupported(*display, src_img, dst_img); if (isSupported == NO_ERROR) isAssignableState = isAssignable(mOtfMPPs[i], display, src_img, dst_img, compositionInfo); HDEBUGLOGD(eDebugResourceAssigning, "\t\t check %s: supportedBit(0x%" PRIx64 "), isAssignable(%d)", mOtfMPPs[i]->mName.c_str(), -isSupported, isAssignableState); if ((isSupported == NO_ERROR) && (isAssignableState)) { if ((ret = mOtfMPPs[i]->assignMPP(display, compositionInfo)) != NO_ERROR) { HWC_LOGE(display, "%s:: %s MPP assignMPP() error (%d)", __func__, mOtfMPPs[i]->mName.c_str(), ret); return ret; } compositionInfo->mOtfMPP = mOtfMPPs[i]; display->mWindowNumUsed++; HDEBUGLOGD(eDebugResourceManager, "%s:: %s is assigned", __func__, mOtfMPPs[i]->mName.c_str()); 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->mType == 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; #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; if (layer->mPreprocessedInfo.sdrDimRatio < mMinimumSdrDimRatio) return eExceedSdrDimRatio; return NO_ERROR; } int32_t ExynosResourceManager::validateRCDLayer(const ExynosDisplay &display, const ExynosLayer &layer, const uint32_t layerIndex, const exynos_image &srcImg, const exynos_image &dstImg) { if (CC_UNLIKELY(srcImg.bufferHandle == NULL || srcImg.format != HAL_PIXEL_FORMAT_GOOGLE_R_8)) { return eInvalidHandle; } if (bool supported; CC_UNLIKELY(display.getRCDLayerSupport(supported) != NO_ERROR || !supported)) return eUnSupportedUseCase; // no rotation if (srcImg.transform & (HAL_TRANSFORM_ROT_90 | HAL_TRANSFORM_ROT_180)) { return eMPPUnsupported; } // no scale if (srcImg.w != dstImg.w || srcImg.h != dstImg.h) { return eMPPUnsupported; } // only support RCD Layers on the top if (layerIndex != display.mLayers.size() - 1) { return eMPPUnsupported; } // b/215335109: IMG_SIZE must be equal or larger than display output if (dstImg.x != 0 || dstImg.y != 0 || dstImg.w != display.mXres || dstImg.h != 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 &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) { for (ExynosMPP *m : mOtfMPPs) { auto ratio = m->getMaxUpscale(dst_scale_img, dst_img); if (ratio > 1) { otfMpp = m; otfMppRatio = ratio; break; } } const auto reqRatio = max(float(dst_img.w) / float(srcWidth * otfMppRatio), float(dst_img.h) / float(srcHeight * otfMppRatio)); for (ExynosMPP *m : mM2mMPPs) { float ratio = float(m->getMaxUpscale(src_img, dst_scale_img)); if (ratio > reqRatio) { m2mMpp = m; m2mMppRatio = ratio; break; } } } else { for (ExynosMPP *m : mM2mMPPs) { auto ratio = m->getMaxDownscale(*display, src_img, dst_scale_img); if (ratio > 1) { m2mMpp = m; m2mMppRatio = ratio; break; } } const float otfSrcWidth = float(srcWidth / m2mMppRatio); const float scaleRatio_H = otfSrcWidth / float(dst_img.w); const float otfSrcHeight = float(srcHeight / 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; for (ExynosMPP *m : mOtfMPPs) { 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; break; } } } 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(eDebugResourceAssigning, "\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 &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(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(eDebugResourceAssigning)) { layer->printLayer(); } if ((validateFlag == NO_ERROR) || (validateFlag == eInsufficientWindow) || (validateFlag == eDimLayer)) { bool isAssignableFlag = false; uint64_t isSupported = 0; /* 1. Find available otfMPP */ if (validateFlag != eInsufficientWindow) { otfMppReordering(display, mOtfMPPs, src_img, dst_img); for (uint32_t j = 0; j < mOtfMPPs.size(); j++) { if ((layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType) != 0) isAssignableFlag = isAssignable(mOtfMPPs[j], display, src_img, dst_img, layer); HDEBUGLOGD(eDebugResourceAssigning, "\t\t check %s: flag (%d) supportedBit(%d), isAssignable(%d)", mOtfMPPs[j]->mName.c_str(), layer->mSupportedMPPFlag, (layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType), isAssignableFlag); // dim layer skip device composition if color native if (display->mColorMode == HAL_COLOR_MODE_NATIVE && validateFlag == eDimLayer) { ALOGD("%s::DimLayer & color native", __func__); continue; } if ((layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType) && (isAssignableFlag)) { isSupported = mOtfMPPs[j]->isSupported(*display, src_img, dst_img); HDEBUGLOGD(eDebugResourceAssigning, "\t\t\t isSupported(%" 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(eDebugResourceAssigning, "\t\tInsufficient window but exynosComposition is not assigned"); continue; } bool isAssignableState = mM2mMPPs[j]->isAssignableState(display, src_img, dst_img); HDEBUGLOGD(eDebugResourceAssigning, "\t\t check %s: supportedBit(%d), isAssignableState(%d)", mM2mMPPs[j]->mName.c_str(), (layer->mSupportedMPPFlag & mM2mMPPs[j]->mLogicalType), isAssignableState); float totalUsedCapa = ExynosResourceManager::getResourceUsedCapa(*mM2mMPPs[j]); 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 image_lists; if ((ret = getCandidateM2mMPPOutImages(display, layer, image_lists)) < 0) { HWC_LOGE(display, "Fail getCandidateM2mMPPOutImages (%d)", ret); return ret; } HDEBUGLOGD(eDebugResourceAssigning, "candidate M2mMPPOutImage num: %zu", image_lists.size()); for (auto &otf_src_img : image_lists) { dumpExynosImage(eDebugResourceAssigning, 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) || ((isAssignableFlag = mM2mMPPs[j]->hasEnoughCapa(display, m2m_src_img, otf_src_img, totalUsedCapa)) == false)) { HDEBUGLOGD(eDebugResourceAssigning, "\t\t\t check %s: supportedBit(0x%" PRIx64 "), hasEnoughCapa(%d)", mM2mMPPs[j]->mName.c_str(), -isSupported, isAssignableFlag); continue; } otfMppReordering(display, mOtfMPPs, otf_src_img, otf_dst_img); /* 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); isAssignableFlag = false; if (isSupported == NO_ERROR) { /* to prevent HW resource execeeded */ ExynosCompositionInfo dpuSrcInfo; dpuSrcInfo.mSrcImg = otf_src_img; dpuSrcInfo.mDstImg = otf_dst_img; HDEBUGLOGD(eDebugTDM, "%s Composition target calculation start (candidates)", __func__); calculateHWResourceAmount(display, &dpuSrcInfo); isAssignableFlag = isAssignable(mOtfMPPs[k], display, otf_src_img, otf_dst_img, &dpuSrcInfo); } HDEBUGLOGD(eDebugResourceAssigning, "\t\t\t check %s: supportedBit(0x%" PRIx64 "), isAssignable(%d)", mOtfMPPs[k]->mName.c_str(), -isSupported, isAssignableFlag); if ((isSupported == NO_ERROR) && isAssignableFlag) { *m2mMPP = mM2mMPPs[j]; *otfMPP = mOtfMPPs[k]; m2m_out_img = otf_src_img; return HWC2_COMPOSITION_DEVICE; } } } } else { if ((layer->mSupportedMPPFlag & mM2mMPPs[j]->mLogicalType) && ((isAssignableFlag = mM2mMPPs[j]->hasEnoughCapa(display, src_img, dst_img, totalUsedCapa) == 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.c_str(), layer->mSupportedMPPFlag, isAssignableFlag); } } } } } /* 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(eDebugResourceAssigning, "%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); // TODO: call validate function for RCD layer if (layer->mCompositionType == HWC2_COMPOSITION_DISPLAY_DECORATION && validateRCDLayer(*display, *layer, i, src_img, dst_img) == NO_ERROR) { layer->mValidateCompositionType = HWC2_COMPOSITION_DISPLAY_DECORATION; continue; } 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.c_str(), ret); return ret; } HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", i, otfMPP->mName.c_str()); } if (m2mMPP != NULL) { if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR) { ALOGE("%s:: %s MPP assignMPP() error (%d)", __func__, m2mMPP->mName.c_str(), ret); return ret; } layer->setExynosMidImage(m2m_out_img); HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", i, m2mMPP->mName.c_str()); } layer->mValidateCompositionType = compositionType; display->mWindowNumUsed++; HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: mWindowNumUsed(%d)", i, display->mWindowNumUsed); } else if (compositionType == HWC2_COMPOSITION_EXYNOS) { float totalUsedCapacity = 0; if (m2mMPP != NULL) { if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR) { ALOGE("%s:: %s MPP assignMPP() error (%d)", __func__, m2mMPP->mName.c_str(), ret); return ret; } totalUsedCapacity = getResourceUsedCapa(*m2mMPP); HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", i, m2mMPP->mName.c_str()); } layer->mValidateCompositionType = compositionType; HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: exynosComposition", i); /* G2D composition */ if (((ret = display->addExynosCompositionLayer(i, totalUsedCapacity)) == 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(eDebugResourceAssigning, "\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().c_str(), 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().c_str(), windowIndex); } else if (layer->mValidateCompositionType == HWC2_COMPOSITION_DISPLAY_DECORATION) { layer->mWindowIndex = -1; continue; } 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(eDebugResourceAssigning, "%s++++++++++", __func__); for (uint32_t i = 0; i < display->mLayers.size(); i++) { ExynosLayer *layer = display->mLayers[i]; HDEBUGLOGD(eDebugResourceAssigning, "[%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(eDebugResourceAssigning, "\tsrc_img"); dumpExynosImage(eDebugResourceAssigning, src_img); HDEBUGLOGD(eDebugResourceAssigning, "\tdst_img"); dumpExynosImage(eDebugResourceAssigning, 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(eDebugResourceAssigning, "\t%s: supported", mOtfMPPs[j]->mName.c_str()); } else { if (((-ret) == eMPPUnsupportedFormat) && ((ret = mOtfMPPs[j]->isSupported(*display, src_img, dst_img_yuv)) == NO_ERROR)) { layer->mSupportedMPPFlag |= mOtfMPPs[j]->mLogicalType; HDEBUGLOGD(eDebugResourceAssigning, "\t%s: supported with yuv dst", mOtfMPPs[j]->mName.c_str()); } } if (ret < 0) { HDEBUGLOGD(eDebugResourceAssigning, "\t%s: unsupported flag(0x%" PRIx64 ")", mOtfMPPs[j]->mName.c_str(), -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(eDebugResourceAssigning, "\t%s: supported", mM2mMPPs[j]->mName.c_str()); } else { if (((-ret) == eMPPUnsupportedFormat) && ((ret = mM2mMPPs[j]->isSupported(*display, src_img, dst_img_yuv)) == NO_ERROR)) { layer->mSupportedMPPFlag |= mM2mMPPs[j]->mLogicalType; HDEBUGLOGD(eDebugResourceAssigning, "\t%s: supported with yuv dst", mM2mMPPs[j]->mName.c_str()); } } if (ret < 0) { HDEBUGLOGD(eDebugResourceAssigning, "\t%s: unsupported flag(0x%" PRIx64 ")", mM2mMPPs[j]->mName.c_str(), -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(eDebugResourceAssigning, "[%d] layer mSupportedMPPFlag(0x%8x)", i, layer->mSupportedMPPFlag); } HDEBUGLOGD(eDebugResourceAssigning, "%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.c_str()); } } 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.c_str()); } } HDEBUGLOGD(eDebugResourceManager, "%s-----------", __func__); return NO_ERROR; } std::pair ExynosResourceManager::decideMainAndMinorDisplay( const int32_t willOnDispId) const { ExynosDisplay *mainDisp = nullptr, *minorDisp = nullptr; auto rule = [](const ExynosDisplay* left, const ExynosDisplay* right) { if (left->mType == right->mType) return left->mIndex < right->mIndex; return left->mType > right->mType; }; std::set availableDisps(rule); for (auto& [disp_id, disp] : mDisplayMap) { if (disp == nullptr || !disp->mPlugState || !disp->mPowerModeState.has_value() || (disp->mDisplayId != willOnDispId && disp->mPowerModeState.value() == (hwc2_power_mode_t)HWC_POWER_MODE_OFF)) continue; availableDisps.insert(disp); HDEBUGLOGD(eDebugResourceManager, "%s: available display id: %d ", __func__, disp->mDisplayId); } if (availableDisps.size() == 1) { mainDisp = *availableDisps.begin(); HDEBUGLOGD(eDebugResourceManager, "%s: main display:%d ", __func__, mainDisp->mDisplayId); } else if (availableDisps.size() == 2) { mainDisp = *availableDisps.begin(); minorDisp = *availableDisps.rbegin(); HDEBUGLOGD(eDebugResourceManager, "%s: main display:%d minor display:%d ", __func__, mainDisp->mDisplayId, minorDisp->mDisplayId); } else { ALOGE("%s(): wrong available display size:%zu", __func__, availableDisps.size()); } return {mainDisp, minorDisp}; } void ExynosResourceManager::updatePreAssignDisplayList(const ExynosDisplay* mainDisp, const ExynosDisplay* minorDisp) { auto updatePreAssignDisplay = [=](ExynosMPP* mpp, const ExynosDisplay* mainDisp, const ExynosDisplay* minorDisp) { if (mpp->mPreAssignDisplayInfo == HWC_RESERVE_DISPLAY_MAIN_BIT) { if (mainDisp != NULL) mpp->mPreAssignDisplayList[DISPLAY_MODE_PRIMARY_MAIN] = mainDisp->getDisplayPreAssignBit(); else ALOGE("Main display does not exist!"); } else if (mpp->mPreAssignDisplayInfo == HWC_RESERVE_DISPLAY_MINOR_BIT) { if (minorDisp != NULL) mpp->mPreAssignDisplayList[DISPLAY_MODE_PRIMARY_MAIN] = minorDisp->getDisplayPreAssignBit(); else if (mainDisp != NULL) mpp->mPreAssignDisplayList[DISPLAY_MODE_PRIMARY_MAIN] = mainDisp->getDisplayPreAssignBit(); else ALOGE("Main & minor display don't exist!"); } }; for (auto& mpp : mOtfMPPs) { updatePreAssignDisplay(mpp, mainDisp, minorDisp); } for (auto& mpp : mM2mMPPs) { updatePreAssignDisplay(mpp, mainDisp, minorDisp); } } 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(eDebugResourceAssigning, "\t%s check, dispMode(%d), 0x%8x", mOtfMPPs[i]->mName.c_str(), 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(eDebugResourceAssigning, "\t\tdisplay index(%zu), checkBit(%d)", j, checkBit); if (checkBit) { HDEBUGLOGD(eDebugResourceAssigning, "\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.has_value() && (display->mPowerModeState.value() != HWC2_POWER_MODE_OFF))))) { HDEBUGLOGD(eDebugResourceAssigning, "\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(eDebugResourceAssigning, "\t%s check, 0x%8x", mM2mMPPs[i]->mName.c_str(), 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(eDebugResourceAssigning, "\t\tdisplay index(%zu), checkBit(%d)", j, checkBit); if (checkBit) { HDEBUGLOGD(eDebugResourceAssigning, "\t\tdisplay index(%zu), displayId(%d), display(%p)", j, display->mDisplayId, display); if ((display != NULL) && (display->mPlugState == true)) { HDEBUGLOGD(eDebugResourceAssigning, "\t\treserve to display %d", display->mDisplayId); mM2mMPPs[i]->reserveMPP(display->mDisplayId); break; } else { HDEBUGLOGD(eDebugResourceAssigning, "\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.c_str()); } } for (uint32_t i = 0; i < mM2mMPPs.size(); i++) { if (hwcCheckDebugMessages(eDebugResourceManager)) { String8 dumpMPP; mM2mMPPs[i]->dump(dumpMPP); HDEBUGLOGD(eDebugResourceManager, "%s", dumpMPP.c_str()); } } HDEBUGLOGD(eDebugResourceManager, "%s-----------", __func__); return NO_ERROR; } void ExynosResourceManager::preAssignWindows(ExynosDisplay *display) { ExynosPrimaryDisplayModule *primaryDisplay = NULL; if (display->mType == HWC_DISPLAY_PRIMARY) { primaryDisplay = (ExynosPrimaryDisplayModule *)display; } else { primaryDisplay = (ExynosPrimaryDisplayModule *)mDevice->getDisplay( getDisplayId(HWC_DISPLAY_PRIMARY, 0)); } primaryDisplay->usePreDefinedWindow(false); } 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.c_str(), 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.compressionInfo.type == COMP_TYPE_AFBC) 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(eDebugResourceAssigning, "%s:: [%s][%d] mpp[%d, %d]", __func__, mpp.mName.c_str(), 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(eDebugResourceAssigning, "\t[%s][%d] mpp usedCapa: %f", mpp.mName.c_str(), 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(const int32_t willOnDispId) { 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; } auto [mainDisp, minorDisp] = decideMainAndMinorDisplay(willOnDispId); if ((mDevice->mGeometryChanged & GEOMETRY_DISPLAY_POWER_ON) || (mDevice->mGeometryChanged & GEOMETRY_DISPLAY_POWER_OFF) || (mDevice->mGeometryChanged & GEOMETRY_DEVICE_DISPLAY_ADDED) || (mDevice->mGeometryChanged & GEOMETRY_DEVICE_DISPLAY_REMOVED) || willOnDispId != -1) updatePreAssignDisplayList(mainDisp, minorDisp); if ((ret = preAssignResources()) != NO_ERROR) { HWC_LOGE(NULL,"%s:: preAssignResources() error (%d)", __func__, ret); return ret; } setDisplaysTDMInfo(mainDisp, minorDisp); 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(display); } 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(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(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).c_str(), 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).c_str(), mFormatRestrictions[mFormatRestrictionCnt].nodeType, getFormatStr(mFormatRestrictions[mFormatRestrictionCnt].format, COMP_TYPE_MASK) .c_str(), 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 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(cap->supportedDimensionAlign().hori), YUV_CHROMA_H_SUBSAMPLE); rSize.fullHeightAlign = max(static_cast(cap->supportedDimensionAlign().vert), YUV_CHROMA_V_SUBSAMPLE); rSize.cropXAlign = max(static_cast(cap->supportedDimensionAlign().hori), YUV_CHROMA_H_SUBSAMPLE); rSize.cropYAlign = max(static_cast(cap->supportedDimensionAlign().vert), YUV_CHROMA_V_SUBSAMPLE); rSize.cropWidthAlign = max(static_cast(cap->supportedDimensionAlign().hori), YUV_CHROMA_H_SUBSAMPLE); rSize.cropHeightAlign = max(static_cast(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 checkDuplicateMPP; for (const auto unit: AVAILABLE_M2M_MPP_UNITS) { if (checkDuplicateMPP.find(unit.physicalType) == checkDuplicateMPP.end()) { makeAcrylRestrictions(static_cast(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); result.appendFormat("[MPP Dump]\n"); for (auto mpp : mOtfMPPs) { mpp->dump(result); } for (auto mpp : mM2mMPPs) { mpp->dump(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; } } bool ExynosResourceManager::isAssignable(ExynosMPP *candidateMPP, ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst, ExynosMPPSource *mppSrc) { bool ret = true; float totalUsedCapacity = getResourceUsedCapa(*candidateMPP); ret = candidateMPP->isAssignable(display, src, dst, totalUsedCapacity); if ((ret) && (mppSrc != nullptr)) { if ((candidateMPP->mMPPType == MPP_TYPE_OTF) && (!isHWResourceAvailable(display, candidateMPP, mppSrc))) { if (mppSrc->mSourceType == MPP_SOURCE_LAYER) { ExynosLayer *layer = (ExynosLayer *)mppSrc; layer->mCheckMPPFlag[candidateMPP->mLogicalType] = eMPPExeedHWResource; } ret = false; } } return ret; } void ExynosResourceManager::updateSupportWCG() { for (uint32_t i = 0; i < mOtfMPPs.size(); i++) { if (mOtfMPPs[i] == NULL) continue; if (mOtfMPPs[i]->mAttr & (MPP_ATTR_WCG | MPP_ATTR_HDR10)) mDeviceSupportWCG = true; } for (uint32_t i = 0; i < mM2mMPPs.size(); i++) { if (mM2mMPPs[i] == NULL) continue; if (mM2mMPPs[i]->mAttr & (MPP_ATTR_WCG | MPP_ATTR_HDR10)) mDeviceSupportWCG = true; } } bool ExynosResourceManager::needHdrProcessing(ExynosDisplay *display, exynos_image &srcImg, exynos_image &dstImg) { if (!deviceSupportWCG()) return false; return true; } uint32_t ExynosResourceManager::needHWResource(ExynosDisplay *display, exynos_image &srcImg, exynos_image &dstImg, tdm_attr_t attr) { uint32_t ret = 0; switch (attr) { case TDM_ATTR_SBWC: ret = (srcImg.compressionInfo.type == COMP_TYPE_SBWC) ? 1 : 0; break; case TDM_ATTR_AFBC: ret = (srcImg.compressionInfo.type == COMP_TYPE_AFBC) ? 1 : 0; break; case TDM_ATTR_ITP: ret = (isFormatYUV(srcImg.format)) ? 1 : 0; break; case TDM_ATTR_WCG: ret = (srcImg.needPreblending) ? 1 : 0; break; case TDM_ATTR_ROT_90: ret = ((srcImg.transform & HAL_TRANSFORM_ROT_90) == 0) ? 0 : 1; break; case TDM_ATTR_SCALE: { bool isPerpendicular = !!(srcImg.transform & HAL_TRANSFORM_ROT_90); if (isPerpendicular) { ret = ((srcImg.w != dstImg.h) || (srcImg.h != dstImg.w)) ? 1 : 0; } else { ret = ((srcImg.w != dstImg.w) || (srcImg.h != dstImg.h)) ? 1 : 0; } } break; default: ret = 0; break; } return ret; }