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