From a4700882415ac24f12fc50b345c36a931f8f9447 Mon Sep 17 00:00:00 2001 From: deluxan <santiago.de.luxan@hhi.fraunhofer.de> Date: Sat, 26 Oct 2019 05:06:10 +0200 Subject: [PATCH] ISP Code clean-up and refactoring for easier readability. --- doc/software-manual.tex | 4 +- source/Lib/EncoderLib/IntraSearch.cpp | 88 ++++++++++++++------------- source/Lib/EncoderLib/IntraSearch.h | 38 +++++++----- 3 files changed, 69 insertions(+), 61 deletions(-) diff --git a/doc/software-manual.tex b/doc/software-manual.tex index b98ab091c..70f66e6a8 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -1968,9 +1968,7 @@ Enables or disables the Intra Sub-Partitions coding mode. \Option{ISPFast} & %\ShortOption{\None} & \Default{false} & -Enables or disables reduced testing of non-DCT-II transforms if ISP is likely to become the best mode for a given CU. -\par -This option has no effect if either ISP or MTS are disabled. +Enables or disables fast encoder methods for ISP. \\ \Option{JointCbCr} & diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 0dacb9e31..e831b4e35 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -341,10 +341,9 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, m_ispCandListHor.clear(); m_ispCandListVer.clear(); m_regIntraRDListWithCosts.clear(); - m_ispTestedModes.clear(); - //save the number of subpartitions - m_ispTestedModes.numTotalParts[0] = (int)height >> floorLog2(CU::getISPSplitDim(width, height, TU_1D_HORZ_SPLIT)); - m_ispTestedModes.numTotalParts[1] = (int)width >> floorLog2(CU::getISPSplitDim(width, height, TU_1D_VERT_SPLIT)); + int numTotalPartsHor = (int)width >> floorLog2(CU::getISPSplitDim(width, height, TU_1D_VERT_SPLIT)); + int numTotalPartsVer = (int)height >> floorLog2(CU::getISPSplitDim(width, height, TU_1D_HORZ_SPLIT)); + m_ispTestedModes.init(numTotalPartsHor, numTotalPartsVer); } const bool testBDPCM = sps.getBDPCMEnabledFlag() && CU::bdpcmAllowed( cu, ComponentID( partitioner.chType ) ) && cu.mtsFlag == 0 && cu.lfnstIdx == 0; @@ -3877,15 +3876,18 @@ void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode, static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM>* rdModeLists[2] = { &m_ispCandListHor, &m_ispCandListVer }; ISPType nextISPcandSplitType; - if (!m_ispTestedModes.stopTestingHorSplit && !m_ispTestedModes.stopTestingVerSplit) + auto& ispTestedModes = m_ispTestedModes; + const bool horSplitIsTerminated = ispTestedModes.splitIsFinished[HOR_INTRA_SUBPARTITIONS - 1]; + const bool verSplitIsTerminated = ispTestedModes.splitIsFinished[VER_INTRA_SUBPARTITIONS - 1]; + if (!horSplitIsTerminated && !verSplitIsTerminated) { nextISPcandSplitType = !lastMode ? HOR_INTRA_SUBPARTITIONS : lastMode->ispMod == HOR_INTRA_SUBPARTITIONS ? VER_INTRA_SUBPARTITIONS : HOR_INTRA_SUBPARTITIONS; } - else if (!m_ispTestedModes.stopTestingHorSplit && m_ispTestedModes.stopTestingVerSplit) + else if (!horSplitIsTerminated && verSplitIsTerminated) { nextISPcandSplitType = HOR_INTRA_SUBPARTITIONS; } - else if (m_ispTestedModes.stopTestingHorSplit && !m_ispTestedModes.stopTestingVerSplit) + else if (horSplitIsTerminated && !verSplitIsTerminated) { nextISPcandSplitType = VER_INTRA_SUBPARTITIONS; } @@ -3894,70 +3896,70 @@ void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode, return; // no more modes will be tested } - int maxNumSubPartitions = m_ispTestedModes.numTotalParts[nextISPcandSplitType - 1]; + int maxNumSubPartitions = ispTestedModes.numTotalParts[nextISPcandSplitType - 1]; - if (m_ispTestedModes.numTestedModes[nextISPcandSplitType - 1] >= 2) + if (ispTestedModes.numTestedModes[nextISPcandSplitType - 1] >= 2) { // Split stop criteria after checking the performance of previously tested intra modes const int thresholdSplit1 = maxNumSubPartitions; + bool stopThisSplit = false; - int mode1 = m_ispTestedModes.getTestedIntraMode((ISPType)nextISPcandSplitType, 0); + int mode1 = ispTestedModes.getTestedIntraMode((ISPType)nextISPcandSplitType, 0); mode1 = mode1 == DC_IDX ? -1 : mode1; - int numSubPartsBestMode1 = mode1 != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)nextISPcandSplitType, mode1) : -1; - int mode2 = m_ispTestedModes.getTestedIntraMode((ISPType)nextISPcandSplitType, 1); + int numSubPartsBestMode1 = mode1 != -1 ? ispTestedModes.getNumCompletedSubParts((ISPType)nextISPcandSplitType, mode1) : -1; + int mode2 = ispTestedModes.getTestedIntraMode((ISPType)nextISPcandSplitType, 1); mode2 = mode2 == DC_IDX ? -1 : mode2; - int numSubPartsBestMode2 = mode2 != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)nextISPcandSplitType, mode2) : -1; + int numSubPartsBestMode2 = mode2 != -1 ? ispTestedModes.getNumCompletedSubParts((ISPType)nextISPcandSplitType, mode2) : -1; // 1) The 2 most promising modes do not reach a certain number of sub-partitions if (numSubPartsBestMode1 != -1 && numSubPartsBestMode2 != -1) { if (numSubPartsBestMode1 < thresholdSplit1 && numSubPartsBestMode2 < thresholdSplit1) { - m_ispTestedModes.stopTestingVerSplit = nextISPcandSplitType == VER_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingVerSplit; - m_ispTestedModes.stopTestingHorSplit = nextISPcandSplitType == HOR_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingHorSplit; - return; + stopThisSplit = true; } } - // 2) One split is better than the other after PLANAR and one angle have been tested - ISPType otherSplit = nextISPcandSplitType == HOR_INTRA_SUBPARTITIONS ? VER_INTRA_SUBPARTITIONS : HOR_INTRA_SUBPARTITIONS; - int numSubPartsBestAngleOtherSplit = mode2 != -1 ? m_ispTestedModes.getNumCompletedSubParts(otherSplit, mode2) : -1; - bool stopThisSplit = false; - if (numSubPartsBestAngleOtherSplit != -1 && numSubPartsBestMode2 != -1) + if (!stopThisSplit) { - if (numSubPartsBestAngleOtherSplit > numSubPartsBestMode2) - { - stopThisSplit = true; - } - else if (numSubPartsBestAngleOtherSplit == numSubPartsBestMode2 && numSubPartsBestAngleOtherSplit == maxNumSubPartitions) + // 2) Try to prohibit split type through comparison of 2 modes of both splits (best angle modes) + ISPType otherSplit = nextISPcandSplitType == HOR_INTRA_SUBPARTITIONS ? VER_INTRA_SUBPARTITIONS : HOR_INTRA_SUBPARTITIONS; + int numSubPartsBestMode2OtherSplit = mode2 != -1 ? ispTestedModes.getNumCompletedSubParts(otherSplit, mode2) : -1; + if (numSubPartsBestMode2OtherSplit != -1 && numSubPartsBestMode2 != -1) { - double rdCostBestAngleThisSplit = m_ispTestedModes.getRDCost(nextISPcandSplitType, mode2, maxNumSubPartitions); - double rdCostBestAngleOtherSplit = m_ispTestedModes.getRDCost(otherSplit, mode2, maxNumSubPartitions); - - if (rdCostBestAngleThisSplit == MAX_DOUBLE || rdCostBestAngleOtherSplit < rdCostBestAngleThisSplit * 1.3) + if (numSubPartsBestMode2OtherSplit > numSubPartsBestMode2) { stopThisSplit = true; } + else if (numSubPartsBestMode2OtherSplit == numSubPartsBestMode2 && numSubPartsBestMode2OtherSplit == maxNumSubPartitions) + { + double rdCostBestMode2ThisSplit = ispTestedModes.getRDCost(nextISPcandSplitType, mode2); + double rdCostBestMode2OtherSplit = ispTestedModes.getRDCost(otherSplit, mode2); + double threshold = 1.3; + if (rdCostBestMode2ThisSplit == MAX_DOUBLE || rdCostBestMode2OtherSplit < rdCostBestMode2ThisSplit * threshold) + { + stopThisSplit = true; + } + } } } if (stopThisSplit) { - m_ispTestedModes.stopTestingVerSplit = nextISPcandSplitType == VER_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingVerSplit; - m_ispTestedModes.stopTestingHorSplit = nextISPcandSplitType == HOR_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingHorSplit; + ispTestedModes.splitIsFinished[nextISPcandSplitType - 1] = true; return; } } // Now a new mode is retrieved from the list and it has to be decided whether it should be tested or not - if (m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1] < rdModeLists[nextISPcandSplitType - 1]->size()) + if (ispTestedModes.candIndexInList[nextISPcandSplitType - 1] < rdModeLists[nextISPcandSplitType - 1]->size()) { - ModeInfo candidate = rdModeLists[nextISPcandSplitType - 1]->at(m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1]); - m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1]++; + ModeInfo candidate = rdModeLists[nextISPcandSplitType - 1]->at(ispTestedModes.candIndexInList[nextISPcandSplitType - 1]); + ispTestedModes.candIndexInList[nextISPcandSplitType - 1]++; // extra modes are only tested if ISP has won so far - if (m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1] > m_ispTestedModes.numOrigModesToTest) + if (ispTestedModes.candIndexInList[nextISPcandSplitType - 1] > ispTestedModes.numOrigModesToTest) { - if (m_ispTestedModes.bestSplitSoFar != candidate.ispMod || m_ispTestedModes.bestModeSoFar == PLANAR_IDX) + if (ispTestedModes.bestSplitSoFar != candidate.ispMod || ispTestedModes.bestModeSoFar == PLANAR_IDX) { return; } @@ -3966,7 +3968,7 @@ void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode, bool testCandidate = true; // we look for a reference mode that has already been tested within the window and decide to test the new one according to the reference mode costs - if (candidate.modeId >= DC_IDX && maxNumSubPartitions > 2 && m_ispTestedModes.numTestedModes[nextISPcandSplitType - 1] >= 2) + if (candidate.modeId >= DC_IDX && maxNumSubPartitions > 2 && ispTestedModes.numTestedModes[nextISPcandSplitType - 1] >= 2) { const int angWindowSize = 5; int numSubPartsLeftMode, numSubPartsRightMode, numSubPartsRefMode, leftIntraMode = -1, rightIntraMode = -1; @@ -3976,8 +3978,8 @@ void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode, xFindAlreadyTestedNearbyIntraModes((int)candidate.modeId, &leftIntraMode, &rightIntraMode, (ISPType)candidate.ispMod, windowSize); - numSubPartsLeftMode = leftIntraMode != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, leftIntraMode) : -1; - numSubPartsRightMode = rightIntraMode != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, rightIntraMode) : -1; + numSubPartsLeftMode = leftIntraMode != -1 ? ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, leftIntraMode) : -1; + numSubPartsRightMode = rightIntraMode != -1 ? ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, rightIntraMode) : -1; numSubPartsRefMode = std::max(numSubPartsLeftMode, numSubPartsRightMode); @@ -4026,8 +4028,10 @@ void IntraSearch::xSortISPCandList(double bestCostSoFar, double bestNonISPCost) double thSkipISP = 1.4; if (bestNonISPCost > bestCostSoFar * thSkipISP) { - m_ispTestedModes.stopTestingHorSplit = true; - m_ispTestedModes.stopTestingVerSplit = true; + for (int splitIdx = 0; splitIdx < NUM_INTRA_SUBPARTITIONS_MODES - 1; splitIdx++) + { + m_ispTestedModes.splitIsFinished[splitIdx] = true; + } return; } } diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index 664d0b392..ed193dcd6 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -233,8 +233,7 @@ private: double bestCost[2]; int numTestedModes[2]; int candIndexInList[2]; - bool stopTestingHorSplit; - bool stopTestingVerSplit; + bool splitIsFinished[2]; int numOrigModesToTest; // set a tested mode results @@ -267,13 +266,11 @@ private: return modeHasBeenTested[iModeIdx][st] ? intraMode[iModeIdx][st].numCompSubParts : -1; } - double getRDCost(ISPType splitType, int iModeIdx, int maxNumSubParts) + double getRDCost(ISPType splitType, int iModeIdx) { const unsigned st = splitType - 1; CHECKD(st > 1, "The split type is invalid!"); - return modeHasBeenTested[iModeIdx][st] && intraMode[iModeIdx][st].numCompSubParts == maxNumSubParts - ? intraMode[iModeIdx][st].rdCost - : -1; + return modeHasBeenTested[iModeIdx][st] ? intraMode[iModeIdx][st].rdCost : MAX_DOUBLE; } // get a tested intra mode index @@ -287,16 +284,16 @@ private: // set everything to default values void clear() { - numTestedModes[0] = numTestedModes[1] = 0; - candIndexInList[0] = candIndexInList[1] = 0; - stopTestingHorSplit = false; - stopTestingVerSplit = false; - testedModes[0].clear(); - testedModes[1].clear(); - bestCost[0] = MAX_DOUBLE; - bestCost[1] = MAX_DOUBLE; - bestMode[0] = -1; - bestMode[1] = -1; + for (int splitIdx = 0; splitIdx < NUM_INTRA_SUBPARTITIONS_MODES - 1; splitIdx++) + { + numTestedModes [splitIdx] = 0; + candIndexInList[splitIdx] = 0; + numTotalParts [splitIdx] = 0; + splitIsFinished[splitIdx] = false; + testedModes [splitIdx].clear(); + bestCost [splitIdx] = MAX_DOUBLE; + bestMode [splitIdx] = -1; + } bestModeSoFar = -1; bestSplitSoFar = NOT_INTRA_SUBPARTITIONS; numOrigModesToTest = -1; @@ -307,6 +304,15 @@ private: intraMode[idx][0].clear(); intraMode[idx][1].clear(); } + void init(const int numTotalPartsHor, const int numTotalPartsVer) + { + clear(); + const int horSplit = HOR_INTRA_SUBPARTITIONS - 1, verSplit = VER_INTRA_SUBPARTITIONS - 1; + numTotalParts [horSplit] = numTotalPartsHor; + numTotalParts [verSplit] = numTotalPartsVer; + splitIsFinished[horSplit] = (numTotalParts[horSplit] == 0); + splitIsFinished[verSplit] = (numTotalParts[verSplit] == 0); + } }; static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_ispCandListHor, m_ispCandListVer; -- GitLab