Skip to content
Snippets Groups Projects
IntraSearch.cpp 166 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* The copyright in this software is being made available under the BSD
     * License, included below. This software may be subject to other third party
     * and contributor rights, including patent rights, and no such rights are
     * granted under this license.
     *
    
     * Copyright (c) 2010-2019, ITU/ISO/IEC
    
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are met:
     *
     *  * Redistributions of source code must retain the above copyright notice,
     *    this list of conditions and the following disclaimer.
     *  * Redistributions in binary form must reproduce the above copyright notice,
     *    this list of conditions and the following disclaimer in the documentation
     *    and/or other materials provided with the distribution.
     *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
     *    be used to endorse or promote products derived from this software without
     *    specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
     * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     * THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /** \file     EncSearch.cpp
     *  \brief    encoder intra search class
     */
    
    #include "IntraSearch.h"
    
    #include "EncModeCtrl.h"
    
    #include "CommonLib/CommonDef.h"
    #include "CommonLib/Rom.h"
    #include "CommonLib/Picture.h"
    #include "CommonLib/UnitTools.h"
    
    #include "CommonLib/dtrace_next.h"
    #include "CommonLib/dtrace_buffer.h"
    
    #include <math.h>
    #include <limits>
     //! \ingroup EncoderLib
     //! \{
    
    #if JVET_O0119_BASE_PALETTE_444
    #define PLTCtx(c) SubCtx( Ctx::Palette, c )
    #endif
    
    IntraSearch::IntraSearch()
      : m_pSplitCS      (nullptr)
      , m_pFullCS       (nullptr)
      , m_pBestCS       (nullptr)
      , m_pcEncCfg      (nullptr)
      , m_pcTrQuant     (nullptr)
      , m_pcRdCost      (nullptr)
    
    Taoran Lu's avatar
    Taoran Lu committed
      , m_pcReshape     (nullptr)
    
      , m_CABACEstimator(nullptr)
      , m_CtxCache      (nullptr)
      , m_isInitialized (false)
    {
      for( uint32_t ch = 0; ch < MAX_NUM_TBLOCKS; ch++ )
      {
        m_pSharedPredTransformSkip[ch] = nullptr;
      }
    }
    
    
    void IntraSearch::destroy()
    {
      CHECK( !m_isInitialized, "Not initialized" );
    
      if( m_pcEncCfg )
      {
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        const uint32_t uiNumLayersToAllocateSplit = 1;
        const uint32_t uiNumLayersToAllocateFull  = 1;
    
        const int uiNumSaveLayersToAllocate = 2;
    
        for( uint32_t layer = 0; layer < uiNumSaveLayersToAllocate; layer++ )
        {
          m_pSaveCS[layer]->destroy();
          delete m_pSaveCS[layer];
        }
    
        uint32_t numWidths  = gp_sizeIdxInfo->numWidths();
        uint32_t numHeights = gp_sizeIdxInfo->numHeights();
    
        for( uint32_t width = 0; width < numWidths; width++ )
        {
          for( uint32_t height = 0; height < numHeights; height++ )
          {
    
    Karsten Suehring's avatar
    Karsten Suehring committed
            if( gp_sizeIdxInfo->isCuSize( gp_sizeIdxInfo->sizeFrom( width ) ) && gp_sizeIdxInfo->isCuSize( gp_sizeIdxInfo->sizeFrom( height ) ) )
    
            {
              for( uint32_t layer = 0; layer < uiNumLayersToAllocateSplit; layer++ )
              {
                m_pSplitCS[width][height][layer]->destroy();
    
                delete m_pSplitCS[width][height][layer];
              }
    
              for( uint32_t layer = 0; layer < uiNumLayersToAllocateFull; layer++ )
              {
                m_pFullCS[width][height][layer]->destroy();
    
                delete m_pFullCS[width][height][layer];
              }
    
              delete[] m_pSplitCS[width][height];
              delete[] m_pFullCS [width][height];
    
              m_pBestCS[width][height]->destroy();
              m_pTempCS[width][height]->destroy();
    
              delete m_pTempCS[width][height];
              delete m_pBestCS[width][height];
            }
          }
    
          delete[] m_pSplitCS[width];
          delete[] m_pFullCS [width];
    
          delete[] m_pTempCS[width];
          delete[] m_pBestCS[width];
        }
    
        delete[] m_pSplitCS;
        delete[] m_pFullCS;
    
        delete[] m_pBestCS;
        delete[] m_pTempCS;
    
        delete[] m_pSaveCS;
      }
    
      m_pSplitCS = m_pFullCS = nullptr;
    
      m_pBestCS = m_pTempCS = nullptr;
    
      m_pSaveCS = nullptr;
    
      for( uint32_t ch = 0; ch < MAX_NUM_TBLOCKS; ch++ )
      {
        delete[] m_pSharedPredTransformSkip[ch];
        m_pSharedPredTransformSkip[ch] = nullptr;
      }
    
    
    Taoran Lu's avatar
    Taoran Lu committed
      m_tmpStorageLCU.destroy();
    
      m_isInitialized = false;
    }
    
    IntraSearch::~IntraSearch()
    {
      if( m_isInitialized )
      {
        destroy();
      }
    }
    
    void IntraSearch::init( EncCfg*        pcEncCfg,
                            TrQuant*       pcTrQuant,
                            RdCost*        pcRdCost,
                            CABACWriter*   CABACEstimator,
                            CtxCache*      ctxCache,
                            const uint32_t     maxCUWidth,
                            const uint32_t     maxCUHeight,
                            const uint32_t     maxTotalCUDepth
    
    Taoran Lu's avatar
    Taoran Lu committed
                           , EncReshape*   pcReshape
    
    )
    {
      CHECK(m_isInitialized, "Already initialized");
      m_pcEncCfg                     = pcEncCfg;
      m_pcTrQuant                    = pcTrQuant;
      m_pcRdCost                     = pcRdCost;
      m_CABACEstimator               = CABACEstimator;
      m_CtxCache                     = ctxCache;
    
    Taoran Lu's avatar
    Taoran Lu committed
      m_pcReshape                    = pcReshape;
    
    
      const ChromaFormat cform = pcEncCfg->getChromaFormatIdc();
    
      IntraPrediction::init( cform, pcEncCfg->getBitDepth( CHANNEL_TYPE_LUMA ) );
    
    Taoran Lu's avatar
    Taoran Lu committed
      m_tmpStorageLCU.create(UnitArea(cform, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
    
    
      for( uint32_t ch = 0; ch < MAX_NUM_TBLOCKS; ch++ )
      {
        m_pSharedPredTransformSkip[ch] = new Pel[MAX_CU_SIZE * MAX_CU_SIZE];
      }
    
      uint32_t numWidths  = gp_sizeIdxInfo->numWidths();
      uint32_t numHeights = gp_sizeIdxInfo->numHeights();
    
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      const uint32_t uiNumLayersToAllocateSplit = 1;
      const uint32_t uiNumLayersToAllocateFull  = 1;
    
    
      m_pBestCS = new CodingStructure**[numWidths];
      m_pTempCS = new CodingStructure**[numWidths];
    
      m_pFullCS  = new CodingStructure***[numWidths];
      m_pSplitCS = new CodingStructure***[numWidths];
    
      for( uint32_t width = 0; width < numWidths; width++ )
      {
        m_pBestCS[width] = new CodingStructure*[numHeights];
        m_pTempCS[width] = new CodingStructure*[numHeights];
    
        m_pFullCS [width] = new CodingStructure**[numHeights];
        m_pSplitCS[width] = new CodingStructure**[numHeights];
    
        for( uint32_t height = 0; height < numHeights; height++ )
        {
    
    Karsten Suehring's avatar
    Karsten Suehring committed
          if(  gp_sizeIdxInfo->isCuSize( gp_sizeIdxInfo->sizeFrom( width ) ) && gp_sizeIdxInfo->isCuSize( gp_sizeIdxInfo->sizeFrom( height ) ) )
    
          {
            m_pBestCS[width][height] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
            m_pTempCS[width][height] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
    
            m_pBestCS[width][height]->create( m_pcEncCfg->getChromaFormatIdc(), Area( 0, 0, gp_sizeIdxInfo->sizeFrom( width ), gp_sizeIdxInfo->sizeFrom( height ) ), false );
            m_pTempCS[width][height]->create( m_pcEncCfg->getChromaFormatIdc(), Area( 0, 0, gp_sizeIdxInfo->sizeFrom( width ), gp_sizeIdxInfo->sizeFrom( height ) ), false );
            m_pFullCS [width][height] = new CodingStructure*[uiNumLayersToAllocateFull];
            m_pSplitCS[width][height] = new CodingStructure*[uiNumLayersToAllocateSplit];
    
            for( uint32_t layer = 0; layer < uiNumLayersToAllocateFull; layer++ )
            {
              m_pFullCS [width][height][layer] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
    
              m_pFullCS [width][height][layer]->create( m_pcEncCfg->getChromaFormatIdc(), Area( 0, 0, gp_sizeIdxInfo->sizeFrom( width ), gp_sizeIdxInfo->sizeFrom( height ) ), false );
            }
    
            for( uint32_t layer = 0; layer < uiNumLayersToAllocateSplit; layer++ )
            {
              m_pSplitCS[width][height][layer] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
    
              m_pSplitCS[width][height][layer]->create( m_pcEncCfg->getChromaFormatIdc(), Area( 0, 0, gp_sizeIdxInfo->sizeFrom( width ), gp_sizeIdxInfo->sizeFrom( height ) ), false );
            }
          }
          else
          {
            m_pBestCS[width][height] = nullptr;
            m_pTempCS[width][height] = nullptr;
    
            m_pFullCS [width][height] = nullptr;
            m_pSplitCS[width][height] = nullptr;
          }
        }
      }
    
      const int uiNumSaveLayersToAllocate = 2;
    
      m_pSaveCS = new CodingStructure*[uiNumSaveLayersToAllocate];
    
      for( uint32_t depth = 0; depth < uiNumSaveLayersToAllocate; depth++ )
      {
        m_pSaveCS[depth] = new CodingStructure( m_unitCache.cuCache, m_unitCache.puCache, m_unitCache.tuCache );
        m_pSaveCS[depth]->create( UnitArea( cform, Area( 0, 0, maxCUWidth, maxCUHeight ) ), false );
      }
    
      m_isInitialized = true;
    }
    
    
    //////////////////////////////////////////////////////////////////////////
    // INTRA PREDICTION
    //////////////////////////////////////////////////////////////////////////
    
    #if JVET_O0050_LOCAL_DUAL_TREE
    
    static constexpr double COST_UNKNOWN = -65536.0;
    
    
    double IntraSearch::findInterCUCost( CodingUnit &cu )
    {
      if( cu.isConsIntra() && !cu.slice->isIntra() )
      {
        //search corresponding inter CU cost
        for( int i = 0; i < m_numCuInSCIPU; i++ )
        {
          if( cu.lumaPos() == m_cuAreaInSCIPU[i].pos() && cu.lumaSize() == m_cuAreaInSCIPU[i].size() )
          {
            return m_cuCostInSCIPU[i];
          }
        }
      }
      return COST_UNKNOWN;
    }
    #endif
    
    bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner, const double bestCostSoFar, bool mtsCheckRangeFlag, int mtsFirstCheckId, int mtsLastCheckId, bool moreProbMTSIdxFirst )
    
    {
      CodingStructure       &cs            = *cu.cs;
      const SPS             &sps           = *cs.sps;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
      const uint32_t             uiWidthBit    = g_aucLog2[partitioner.currArea().lwidth() ];
    
      const uint32_t             uiHeightBit   =                   g_aucLog2[partitioner.currArea().lheight()];
    
      // Lambda calculation at equivalent Qp of 4 is recommended because at that Qp, the quantization divisor is 1.
    
      const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda(cu.transQuantBypass) * FRAC_BITS_SCALE;
    
    
      //===== loop over partitions =====
    
      const TempCtx ctxStart          ( m_CtxCache, m_CABACEstimator->getCtx() );
    
      const TempCtx ctxStartMipFlag    ( m_CtxCache, SubCtx( Ctx::MipFlag,          m_CABACEstimator->getCtx() ) );
    
    #if !JVET_O0925_MIP_SIMPLIFICATIONS
    
      const TempCtx ctxStartMipMode    ( m_CtxCache, SubCtx( Ctx::MipMode,          m_CABACEstimator->getCtx() ) );
    
      const TempCtx ctxStartIspMode    ( m_CtxCache, SubCtx( Ctx::ISPMode,          m_CABACEstimator->getCtx() ) );
      const TempCtx ctxStartPlanarFlag ( m_CtxCache, SubCtx( Ctx::IntraLumaPlanarFlag, m_CABACEstimator->getCtx() ) );
    
    Frank Bossen's avatar
    Frank Bossen committed
      const TempCtx ctxStartIntraMode(m_CtxCache, SubCtx(Ctx::IntraLumaMpmFlag, m_CABACEstimator->getCtx()));
    
    Paul Keydel's avatar
    Paul Keydel committed
      const TempCtx ctxStartMrlIdx      ( m_CtxCache, SubCtx( Ctx::MultiRefLineIdx,        m_CABACEstimator->getCtx() ) );
    
    
      CHECK( !cu.firstPU, "CU has no PUs" );
      const bool keepResi   = cs.pps->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() || KEEP_PRED_AND_RESI_SIGNALS;
    
    
      // variables for saving fast intra modes scan results across multiple LFNST passes
      bool LFNSTLoadFlag = sps.getUseLFNST() && cu.lfnstIdx != 0;
      bool LFNSTSaveFlag = sps.getUseLFNST() && cu.lfnstIdx == 0;
    
      LFNSTSaveFlag &= sps.getUseIntraMTS() ? cu.mtsFlag == 0 : true;
    
      const uint32_t lfnstIdx = cu.lfnstIdx;
    
    #if JVET_O0050_LOCAL_DUAL_TREE
      double costInterCU = findInterCUCost( cu );
    #endif
    
      const int width  = partitioner.currArea().lwidth();
      const int height = partitioner.currArea().lheight();
    
      // Marking MTS usage for faster MTS
      // 0: MTS is either not applicable for current CU (cuWidth > MTS_INTRA_MAX_CU_SIZE or cuHeight > MTS_INTRA_MAX_CU_SIZE), not active in the config file or the fast decision algorithm is not used in this case
      // 1: MTS fast algorithm can be applied for the current CU, and the DCT2 is being checked
      // 2: MTS is being checked for current CU. Stored results of DCT2 can be utilized for speedup
      uint8_t mtsUsageFlag = 0;
      const int maxSizeEMT = MTS_INTRA_MAX_CU_SIZE;
      if( width <= maxSizeEMT && height <= maxSizeEMT && sps.getUseIntraMTS() )
      {
        mtsUsageFlag = ( sps.getUseLFNST() && cu.mtsFlag == 1 ) ? 2 : 1;
      }
    
      if( width * height < 64 && !m_pcEncCfg->getUseFastLFNST() )
      {
        mtsUsageFlag = 0;
      }
    
    #if MAX_TB_SIZE_SIGNALLING
    
      bool testISP = sps.getUseISP() && cu.mtsFlag == 0 && cu.lfnstIdx == 0 && CU::canUseISP( width, height, cu.cs->sps->getMaxTbSize() );
    
      bool testISP = sps.getUseISP() && cu.mtsFlag == 0 && cu.lfnstIdx == 0 && CU::canUseISP( width, height, MAX_TB_SIZEY );
    
    #if !JVET_O0502_ISP_CLEANUP
    
      bool ispHorIsFirstTest = testISP ? CU::firstTestISPHorSplit( width, height, COMPONENT_Y, nullptr, nullptr ) : true;
      int ispOptions[] = { NOT_INTRA_SUBPARTITIONS, HOR_INTRA_SUBPARTITIONS, VER_INTRA_SUBPARTITIONS };
      if ( !ispHorIsFirstTest )
      {
        ispOptions[1] = VER_INTRA_SUBPARTITIONS;
        ispOptions[2] = HOR_INTRA_SUBPARTITIONS;
    
    #if JVET_O0502_ISP_CLEANUP
    
        //reset the variables used for the tests
    
        m_ispCandListHor.clear();
        m_ispCandListVer.clear();
        m_regIntraRDListWithCosts.clear();
        m_ispTestedModes.clear();
        //save the number of subpartitions
        m_ispTestedModes.numTotalParts[0] = (int)height >> g_aucLog2[CU::getISPSplitDim(width, height, TU_1D_HORZ_SPLIT)];
        m_ispTestedModes.numTotalParts[1] = (int)width >> g_aucLog2[CU::getISPSplitDim(width, height, TU_1D_VERT_SPLIT)];
    #else
    
        //variables for the full RD list without MRL modes
        m_rdModeListWithoutMrl      .clear();
        m_rdModeListWithoutMrlHor   .clear();
        m_rdModeListWithoutMrlVer   .clear();
        //variables with data from regular intra used to skip ISP splits
        m_intraModeDiagRatio        .clear();
        m_intraModeHorVerRatio      .clear();
        m_intraModeTestedNormalIntra.clear();
    
    #if JVET_O1136_TS_BDPCM_SIGNALLING
      const bool testBDPCM = sps.getBDPCMEnabledFlag() && CU::bdpcmAllowed( cu, ComponentID( partitioner.chType ) ) && cu.mtsFlag == 0 && cu.lfnstIdx == 0;
    #else
    
      const bool testBDPCM = m_pcEncCfg->getRDPCM() && CU::bdpcmAllowed( cu, ComponentID( partitioner.chType ) ) && cu.mtsFlag == 0 && cu.lfnstIdx == 0;
    
      static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiHadModeList;
    
      static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandCostList;
      static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandHadList;
    
    
      bool validReturn = false;
    
      {
        CandHadList.clear();
        CandCostList.clear();
        uiHadModeList.clear();
    
        CHECK(pu.cu != &cu, "PU is not contained in the CU");
    
        //===== determine set of modes to be tested (using prediction signal only) =====
        int numModesAvailable = NUM_LUMA_MODE; // total number of Intra modes
    
        const bool fastMip    = sps.getUseMIP() && m_pcEncCfg->getUseFastMIP();
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
    #if JVET_O0545_MAX_TB_SIGNALLING
        const bool mipAllowed = sps.getUseMIP() && isLuma(partitioner.chType) && pu.lwidth() <= cu.cs->sps->getMaxTbSize() && pu.lheight() <= cu.cs->sps->getMaxTbSize() && ((cu.lfnstIdx == 0) || allowLfnstWithMip(cu.firstPU->lumaSize()));
    #else
        const bool mipAllowed = sps.getUseMIP() && isLuma(partitioner.chType) && pu.lwidth() <= MIP_MAX_WIDTH && pu.lheight() <= MIP_MAX_HEIGHT && ((cu.lfnstIdx == 0) || allowLfnstWithMip(cu.firstPU->lumaSize()));
    #endif
        const bool testMip    = mipAllowed && mipModesAvailable(pu.Y());
    #else
    
    #if JVET_O0545_MAX_TB_SIGNALLING
        const bool mipAllowed = sps.getUseMIP() && ( cu.lfnstIdx == 0 ) && isLuma( partitioner.chType ) && pu.lwidth() <= cu.cs->sps->getMaxTbSize() && pu.lheight() <= cu.cs->sps->getMaxTbSize();
    #else
    
        const bool mipAllowed = sps.getUseMIP() && ( cu.lfnstIdx == 0 ) && isLuma( partitioner.chType ) && pu.lwidth() <= MIP_MAX_WIDTH && pu.lheight() <= MIP_MAX_HEIGHT;
    
        const bool testMip    = mipAllowed && mipModesAvailable( pu.Y() ) && !(fastMip && (cu.lwidth() > 2 * cu.lheight() || cu.lheight() > 2 * cu.lwidth()));
    
    
        static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeList;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
        numModesForFullRD = g_aucIntraModeNumFast_UseMPM_2D[uiWidthBit - MIN_CU_LOG2][uiHeightBit - MIN_CU_LOG2];
    
    
    #if INTRA_FULL_SEARCH
        numModesForFullRD = numModesAvailable;
    #endif
    
    
        {
          // this should always be true
          CHECK( !pu.Y().valid(), "PU is not valid" );
    
    Liang Zhao's avatar
    Liang Zhao committed
    #if ENABLE_JVET_L0283_MRL
    
          bool isFirstLineOfCtu = (((pu.block(COMPONENT_Y).y)&((pu.cs->sps)->getMaxCUWidth() - 1)) == 0);
          int numOfPassesExtendRef = (isFirstLineOfCtu ? 1 : MRL_NUM_REF_LINES);
    
    Liang Zhao's avatar
    Liang Zhao committed
    #endif
    
          pu.multiRefIdx = 0;
    
    
          if( numModesForFullRD != numModesAvailable )
          {
            CHECK( numModesForFullRD >= numModesAvailable, "Too many modes for full RD search" );
    
            const CompArea &area = pu.Y();
    
            PelBuf piOrg         = cs.getOrgBuf(area);
            PelBuf piPred        = cs.getPredBuf(area);
    
    
            DistParam distParamSad;
            DistParam distParamHad;
    
            if (cu.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())
    
    Taoran Lu's avatar
    Taoran Lu committed
            {
              CompArea      tmpArea(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size());
              PelBuf tmpOrg = m_tmpStorageLCU.getBuf(tmpArea);
              tmpOrg.copyFrom(piOrg);
              tmpOrg.rspSignal(m_pcReshape->getFwdLUT());
    
              m_pcRdCost->setDistParam(distParamSad, tmpOrg, piPred, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false); // Use SAD cost
              m_pcRdCost->setDistParam(distParamHad, tmpOrg, piPred, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y,  true); // Use HAD (SATD) cost
    
            {
              m_pcRdCost->setDistParam(distParamSad, piOrg, piPred, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y, false); // Use SAD cost
              m_pcRdCost->setDistParam(distParamHad, piOrg, piPred, sps.getBitDepth(CHANNEL_TYPE_LUMA), COMPONENT_Y,  true); // Use HAD (SATD) cost
            }
    
            distParamSad.applyWeight = false;
            distParamHad.applyWeight = false;
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
              numModesForFullRD += fastMip? std::max(numModesForFullRD, g_aucLog2[std::min(pu.lwidth(), pu.lheight())] - 1) : numModesForFullRD;
    #else
    
              numModesForFullRD += fastMip? std::max(2, g_aucLog2[std::min(pu.lwidth(), pu.lheight())] - 1) : numModesForFullRD;
    
            }
            const int numHadCand = (testMip ? 2 : 1) * 3;
    
            //*** Derive (regular) candidates using Hadamard
            cu.mipFlag = false;
    
            //===== init pattern for luma prediction =====
            initIntraPatternChType(cu, pu.Y(), true);
    
            bool bSatdChecked[NUM_INTRA_MODE];
            memset( bSatdChecked, 0, sizeof( bSatdChecked ) );
    
    
            {
              for( int modeIdx = 0; modeIdx < numModesAvailable; modeIdx++ )
              {
                uint32_t       uiMode = modeIdx;
    
    
                // Skip checking extended Angular modes in the first round of SATD
                if( uiMode > DC_IDX && ( uiMode & 1 ) )
                {
                  continue;
                }
    
                bSatdChecked[uiMode] = true;
    
                pu.intraDir[0] = modeIdx;
    
    
                if( useDPCMForFirstPassIntraEstimation( pu, uiMode ) )
                {
                  encPredIntraDPCM( COMPONENT_Y, piOrg, piPred, uiMode );
                }
                else
                {
    
                // Use the min between SAD and HAD as the cost criterion
                // SAD is scaled by 2 to align with the scaling of HAD
    
                minSadHad += std::min(distParamSad.distFunc(distParamSad)*2, distParamHad.distFunc(distParamHad));
    
    
                // NB xFracModeBitsIntra will not affect the mode for chroma that may have already been pre-estimated.
    
                m_CABACEstimator->getCtx() = SubCtx( Ctx::MipFlag, ctxStartMipFlag );
                m_CABACEstimator->getCtx() = SubCtx( Ctx::ISPMode, ctxStartIspMode );
                m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaPlanarFlag, ctxStartPlanarFlag);
    
    Frank Bossen's avatar
    Frank Bossen committed
                m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaMpmFlag, ctxStartIntraMode);
    
    Paul Keydel's avatar
    Paul Keydel committed
                m_CABACEstimator->getCtx() = SubCtx( Ctx::MultiRefLineIdx, ctxStartMrlIdx );
    
    
                uint64_t fracModeBits = xFracModeBitsIntra(pu, uiMode, CHANNEL_TYPE_LUMA);
    
    
                double cost = ( double ) minSadHad + (double)fracModeBits * sqrtLambdaForFirstPass;
    
    
                DTRACE(g_trace_ctx, D_INTRA_COST, "IntraHAD: %u, %llu, %f (%d)\n", minSadHad, fracModeBits, cost, uiMode);
    
                updateCandList( ModeInfo(false, 0, NOT_INTRA_SUBPARTITIONS, uiMode), cost,          uiRdModeList,  CandCostList, numModesForFullRD );
                updateCandList( ModeInfo(false, 0, NOT_INTRA_SUBPARTITIONS, uiMode), (double)minSadHad, uiHadModeList, CandHadList,  numHadCand );
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
              if( !sps.getUseMIP() && LFNSTSaveFlag )
    #else
    
              {
                // save found best modes
                m_uiSavedNumRdModesLFNST   = numModesForFullRD;
                m_uiSavedRdModeListLFNST   = uiRdModeList;
                m_dSavedModeCostLFNST      = CandCostList;
                // PBINTRA fast
                m_uiSavedHadModeListLFNST  = uiHadModeList;
                m_dSavedHadListLFNST       = CandHadList;
                LFNSTSaveFlag              = false;
              }
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
            if( !sps.getUseMIP() && LFNSTLoadFlag )
    #else
    
            {
              // restore saved modes
              numModesForFullRD = m_uiSavedNumRdModesLFNST;
              uiRdModeList      = m_uiSavedRdModeListLFNST;
              CandCostList      = m_dSavedModeCostLFNST;
              // PBINTRA fast
              uiHadModeList     = m_uiSavedHadModeListLFNST;
              CandHadList       = m_dSavedHadListLFNST;
    
    #if !JVET_O0925_MIP_SIMPLIFICATIONS
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
            if (!(sps.getUseMIP() && LFNSTLoadFlag))
            {
    #else
    
            CHECK( uiRdModeList.size() != numModesForFullRD, "Error: RD mode list size" );
    
            static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> parentCandList = uiRdModeList;
    
    
            // Second round of SATD for extended Angular modes
            for (int modeIdx = 0; modeIdx < numModesForFullRD; modeIdx++)
            {
    
              unsigned parentMode = parentCandList[modeIdx].modeId;
    
              if (parentMode > (DC_IDX + 1) && parentMode < (NUM_LUMA_MODE - 1))
              {
                for (int subModeIdx = -1; subModeIdx <= 1; subModeIdx += 2)
                {
                  unsigned mode = parentMode + subModeIdx;
    
    
                  if (!bSatdChecked[mode])
                  {
                    pu.intraDir[0] = mode;
    
    
                    if (useDPCMForFirstPassIntraEstimation(pu, mode))
                    {
                      encPredIntraDPCM(COMPONENT_Y, piOrg, piPred, mode);
                    }
                    else
                    {
    
                    // Use the min between SAD and SATD as the cost criterion
                    // SAD is scaled by 2 to align with the scaling of HAD
    
                    Distortion minSadHad = std::min(distParamSad.distFunc(distParamSad)*2, distParamHad.distFunc(distParamHad));
    
    
                    // NB xFracModeBitsIntra will not affect the mode for chroma that may have already been pre-estimated.
    
                    m_CABACEstimator->getCtx() = SubCtx( Ctx::MipFlag, ctxStartMipFlag );
                    m_CABACEstimator->getCtx() = SubCtx( Ctx::ISPMode, ctxStartIspMode );
                    m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaPlanarFlag, ctxStartPlanarFlag);
    
    Frank Bossen's avatar
    Frank Bossen committed
                    m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaMpmFlag, ctxStartIntraMode);
    
    Paul Keydel's avatar
    Paul Keydel committed
                    m_CABACEstimator->getCtx() = SubCtx( Ctx::MultiRefLineIdx, ctxStartMrlIdx );
    
    
                    uint64_t fracModeBits = xFracModeBitsIntra(pu, mode, CHANNEL_TYPE_LUMA);
    
    
                    double cost = (double) minSadHad + (double) fracModeBits * sqrtLambdaForFirstPass;
    
                    updateCandList( ModeInfo( false, 0, NOT_INTRA_SUBPARTITIONS, mode ), cost,        uiRdModeList,  CandCostList, numModesForFullRD );
                    updateCandList( ModeInfo( false, 0, NOT_INTRA_SUBPARTITIONS, mode ), (double)minSadHad, uiHadModeList, CandHadList,  numHadCand );
    
    #if JVET_O0502_ISP_CLEANUP
    
              // we save the regular intra modes list
    
              m_ispCandListHor = uiRdModeList;
    #else
    
              //we save the list with no mrl modes to keep only the Hadamard selected modes (no mpms)
    
              m_rdModeListWithoutMrl = uiRdModeList;
    
    Liang Zhao's avatar
    Liang Zhao committed
    #if ENABLE_JVET_L0283_MRL
    
            pu.multiRefIdx = 1;
    
            const int  numMPMs = NUM_MOST_PROBABLE_MODES;
            unsigned  multiRefMPM [numMPMs];
    
            PU::getIntraMPMs(pu, multiRefMPM);
            for (int mRefNum = 1; mRefNum < numOfPassesExtendRef; mRefNum++)
            {
              int multiRefIdx = MULTI_REF_LINE_IDX[mRefNum];
    
              pu.multiRefIdx = multiRefIdx;
              {
    
              for (int x = 1; x < numMPMs; x++)
    
              {
                uint32_t mode = multiRefMPM[x];
                {
                  pu.intraDir[0] = mode;
    
    
                  if (useDPCMForFirstPassIntraEstimation(pu, mode))
                  {
                    encPredIntraDPCM(COMPONENT_Y, piOrg, piPred, mode);
                  }
                  else
                  {
    
                  // Use the min between SAD and SATD as the cost criterion
                  // SAD is scaled by 2 to align with the scaling of HAD
    
                  Distortion minSadHad = std::min(distParamSad.distFunc(distParamSad)*2, distParamHad.distFunc(distParamHad));
    
    
                  // NB xFracModeBitsIntra will not affect the mode for chroma that may have already been pre-estimated.
    
                  m_CABACEstimator->getCtx() = SubCtx( Ctx::MipFlag, ctxStartMipFlag );
                  m_CABACEstimator->getCtx() = SubCtx( Ctx::ISPMode, ctxStartIspMode );
                  m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaPlanarFlag, ctxStartPlanarFlag);
    
    Frank Bossen's avatar
    Frank Bossen committed
                  m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaMpmFlag, ctxStartIntraMode);
    
    Paul Keydel's avatar
    Paul Keydel committed
                  m_CABACEstimator->getCtx() = SubCtx( Ctx::MultiRefLineIdx, ctxStartMrlIdx );
    
    
                  uint64_t fracModeBits = xFracModeBitsIntra(pu, mode, CHANNEL_TYPE_LUMA);
    
    
                  double cost = (double)minSadHad + (double)fracModeBits * sqrtLambdaForFirstPass;
    
                  updateCandList( ModeInfo( false, multiRefIdx, NOT_INTRA_SUBPARTITIONS, mode ), cost,        uiRdModeList,  CandCostList, numModesForFullRD );
                  updateCandList( ModeInfo( false, multiRefIdx, NOT_INTRA_SUBPARTITIONS, mode ), (double)minSadHad, uiHadModeList, CandHadList,  numHadCand );
    
    Liang Zhao's avatar
    Liang Zhao committed
    #endif
    
            CHECKD( uiRdModeList.size() != numModesForFullRD, "Error: RD mode list size" );
    
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
            if (LFNSTSaveFlag && testMip && !allowLfnstWithMip(cu.firstPU->lumaSize())) // save a different set for the next run
            {
    
              m_uiSavedRdModeListLFNST = uiRdModeList;
              m_dSavedModeCostLFNST = CandCostList;
              // PBINTRA fast
              m_uiSavedHadModeListLFNST = uiHadModeList;
              m_dSavedHadListLFNST = CandHadList;
              m_uiSavedNumRdModesLFNST = g_aucIntraModeNumFast_UseMPM_2D[uiWidthBit - MIN_CU_LOG2][uiHeightBit - MIN_CU_LOG2];
              m_uiSavedRdModeListLFNST.resize(m_uiSavedNumRdModesLFNST);
              m_dSavedModeCostLFNST.resize(m_uiSavedNumRdModesLFNST);
              // PBINTRA fast
              m_uiSavedHadModeListLFNST.resize(3);
              m_dSavedHadListLFNST.resize(3);
              LFNSTSaveFlag = false;
            }
    #endif
    
              //*** Derive MIP candidates using Hadamard
              if (testMip)
              {
                cu.mipFlag = true;
                pu.multiRefIdx = 0;
    
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
                double mipHadCost[MAX_NUM_MIP_MODE] = { MAX_DOUBLE };
    
                initIntraPatternChType(cu, pu.Y());
    #endif
    
                initIntraMip( pu );
    
                for (uint32_t uiMode = 0; uiMode < getNumModesMip(pu.Y()); uiMode++)
                {
                  pu.intraDir[CHANNEL_TYPE_LUMA] = uiMode;
                  predIntraMip(COMPONENT_Y, piPred, pu);
    
                  // Use the min between SAD and HAD as the cost criterion
                  // SAD is scaled by 2 to align with the scaling of HAD
                  Distortion minSadHad = std::min(distParamSad.distFunc(distParamSad)*2, distParamHad.distFunc(distParamHad));
    
                  m_CABACEstimator->getCtx() = SubCtx( Ctx::MipFlag, ctxStartMipFlag );
    
    #if !JVET_O0925_MIP_SIMPLIFICATIONS
    
                  m_CABACEstimator->getCtx() = SubCtx( Ctx::MipMode, ctxStartMipMode );
    
    
                  uint64_t fracModeBits = xFracModeBitsIntra(pu, uiMode, CHANNEL_TYPE_LUMA);
    
                  double cost = double(minSadHad) + double(fracModeBits) * sqrtLambdaForFirstPass;
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
                  mipHadCost[uiMode] = cost;
                  DTRACE(g_trace_ctx, D_INTRA_COST, "IntraMIP: %u, %llu, %f (%d)\n", minSadHad, fracModeBits, cost, uiMode);
    
                  updateCandList(ModeInfo(true, 0, NOT_INTRA_SUBPARTITIONS, uiMode), cost, uiRdModeList, CandCostList, numModesForFullRD + 1);
                  updateCandList(ModeInfo(true, 0, NOT_INTRA_SUBPARTITIONS, uiMode), 0.8*double(minSadHad), uiHadModeList, CandHadList, numHadCand);
    #else
    
                  updateCandList(ModeInfo(true, 0, NOT_INTRA_SUBPARTITIONS, uiMode),        cost,  uiRdModeList,  CandCostList, numModesForFullRD);
                  updateCandList(ModeInfo(true, 0, NOT_INTRA_SUBPARTITIONS, uiMode), double(minSadHad), uiHadModeList, CandHadList, numHadCand);
    
                }
    
                const double thresholdHadCost = 1.0 + 1.4 / sqrt((double)(pu.lwidth()*pu.lheight()));
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
                reduceHadCandList(uiRdModeList, CandCostList, numModesForFullRD, thresholdHadCost, mipHadCost, pu, fastMip);
    #else
    
                reduceHadCandList(uiRdModeList, CandCostList, numModesForFullRD, thresholdHadCost, 0.0);
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
              if ( sps.getUseMIP() && LFNSTSaveFlag)
              {
                // save found best modes
                m_uiSavedNumRdModesLFNST = numModesForFullRD;
                m_uiSavedRdModeListLFNST = uiRdModeList;
                m_dSavedModeCostLFNST = CandCostList;
                // PBINTRA fast
                m_uiSavedHadModeListLFNST = uiHadModeList;
                m_dSavedHadListLFNST = CandHadList;
                LFNSTSaveFlag = false;
              }
            }
            else //if( sps.getUseMIP() && LFNSTLoadFlag)
            {
              // restore saved modes
              numModesForFullRD = m_uiSavedNumRdModesLFNST;
              uiRdModeList = m_uiSavedRdModeListLFNST;
              CandCostList = m_dSavedModeCostLFNST;
              // PBINTRA fast
              uiHadModeList = m_uiSavedHadModeListLFNST;
              CandHadList = m_dSavedHadListLFNST;
            }
    #endif
    
              const int numMPMs = NUM_MOST_PROBABLE_MODES;
              unsigned  uiPreds[numMPMs];
    
              pu.multiRefIdx = 0;
    
    
              const int numCand = PU::getIntraMPMs( pu, uiPreds );
    
              for( int j = 0; j < numCand; j++ )
              {
                bool mostProbableModeIncluded = false;
    
                ModeInfo mostProbableMode( false, 0, NOT_INTRA_SUBPARTITIONS, uiPreds[j] );
    
                  mostProbableModeIncluded |= ( mostProbableMode == uiRdModeList[i] );
    
                }
                if( !mostProbableModeIncluded )
                {
                  numModesForFullRD++;
                  uiRdModeList.push_back( mostProbableMode );
    
                  CandCostList.push_back(0);
    
    #if JVET_O0502_ISP_CLEANUP
    
                // we add the MPMs to the list that contains only regular intra modes
    
                for (int j = 0; j < numCand; j++)
                {
                  bool     mostProbableModeIncluded = false;
                  ModeInfo mostProbableMode(false, 0, NOT_INTRA_SUBPARTITIONS, uiPreds[j]);
    
                  for (int i = 0; i < m_ispCandListHor.size(); i++)
                  {
                    mostProbableModeIncluded |= (mostProbableMode == m_ispCandListHor[i]);
                  }
                  if (!mostProbableModeIncluded)
                  {
                    m_ispCandListHor.push_back(mostProbableMode);
                  }
                }
    #else
    
                //we add the ISP MPMs to the list without mrl modes
                m_rdModeListWithoutMrlHor = m_rdModeListWithoutMrl;
                m_rdModeListWithoutMrlVer = m_rdModeListWithoutMrl;
    
                for (int k = 0; k < m_rdModeListWithoutMrl.size(); k++)
                {
                  m_rdModeListWithoutMrlHor[k].ispMod = HOR_INTRA_SUBPARTITIONS;
                  m_rdModeListWithoutMrlVer[k].ispMod = VER_INTRA_SUBPARTITIONS;
                }
                static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM>* listPointer;
    
                for( int k = 1; k < NUM_INTRA_SUBPARTITIONS_MODES; k++ )
    
                {
                  cu.ispMode = ispOptions[k];
                  listPointer = &( cu.ispMode == HOR_INTRA_SUBPARTITIONS ? m_rdModeListWithoutMrlHor : m_rdModeListWithoutMrlVer );
                  const int numCandISP = PU::getIntraMPMs( pu, uiPreds );
                  for( int j = 0; j < numCandISP; j++ )
                  {
                    bool mostProbableModeIncluded = false;
    
                    ModeInfo mostProbableMode( false, 0, cu.ispMode, uiPreds[j] );
    
    
                    for( int i = 0; i < listPointer->size(); i++ )
                    {
                      mostProbableModeIncluded |= ( mostProbableMode == listPointer->at( i ) );
                    }
                    if( !mostProbableModeIncluded )
                    {
                      listPointer->push_back( mostProbableMode );
                    }
                  }
                }
                cu.ispMode = NOT_INTRA_SUBPARTITIONS;
    
    #if !JVET_O0925_MIP_SIMPLIFICATIONS
    
            //*** Add MPMs for MIP to candidate list
            if (!fastMip && testMip && pu.lwidth() < 8 && pu.lheight() < 8)
            {
              unsigned mpm[NUM_MPM_MIP];
              int numCandMip = PU::getMipMPMs(pu, mpm);
    
              for( int j = 0; j < numCandMip; j++ )
              {
                bool mostProbableModeIncluded = false;
                ModeInfo mostProbableMode(true, 0, NOT_INTRA_SUBPARTITIONS, mpm[j]);
                for( int i = 0; i < numModesForFullRD; i++ )
                {
                  mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]);
                }
                if( !mostProbableModeIncluded )
                {
                  numModesForFullRD++;
                  uiRdModeList.push_back( mostProbableMode );
                  CandCostList.push_back(0);
                }
              }
            }
    
            THROW( "Full search not supported for MIP" );
    
          }
          if( sps.getUseLFNST() && mtsUsageFlag == 1 )
          {
            // Store the modes to be checked with RD
            m_savedNumRdModes[ lfnstIdx ]     = numModesForFullRD;
            std::copy_n( uiRdModeList.begin(),  numModesForFullRD, m_savedRdModeList[ lfnstIdx ] );
          }
        }
        else //mtsUsage = 2 (here we potentially reduce the number of modes that will be full-RD checked)
        {
    
          if( ( m_pcEncCfg->getUseFastLFNST() || !cu.slice->isIntra() ) && m_bestModeCostValid[ lfnstIdx ] )
    
          {
            numModesForFullRD = 0;
    
            double thresholdSkipMode = 1.0 + ( ( cu.lfnstIdx > 0 ) ? 0.1 : 1.0 ) * ( 1.4 / sqrt( ( double ) ( width*height ) ) );
    
            // Skip checking the modes with much larger R-D cost than the best mode
            for( int i = 0; i < m_savedNumRdModes[ lfnstIdx ]; i++ )
            {
              if( m_modeCostStore[ lfnstIdx ][ i ] <= thresholdSkipMode * m_bestModeCostStore[ lfnstIdx ] )
              {
                uiRdModeList.push_back( m_savedRdModeList[ lfnstIdx ][ i ] );
                numModesForFullRD++;
              }
            }
          }
          else //this is necessary because we skip the candidates list calculation, since it was already obtained for the DCT-II. Now we load it
          {
            // Restore the modes to be checked with RD
            numModesForFullRD = m_savedNumRdModes[ lfnstIdx ];
            uiRdModeList.resize( numModesForFullRD );
            std::copy_n( m_savedRdModeList[ lfnstIdx ], m_savedNumRdModes[ lfnstIdx ], uiRdModeList.begin() );
            CandCostList.resize( numModesForFullRD );
    
    #if !JVET_O0502_ISP_CLEANUP
    
        if( testISP ) // we remove the non-MPMs from the ISP lists
    
          static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeListCopyHor = m_rdModeListWithoutMrlHor;
          m_rdModeListWithoutMrlHor.clear();
          static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeListCopyVer = m_rdModeListWithoutMrlVer;
          m_rdModeListWithoutMrlVer.clear();
          static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> *listPointerCopy, *listPointer;
    
          for( int ispOptionIdx = 1; ispOptionIdx < NUM_INTRA_SUBPARTITIONS_MODES; ispOptionIdx++ )
    
          {
            cu.ispMode = ispOptions[ispOptionIdx];
            //we get the mpm cand list
            const int numMPMs = NUM_MOST_PROBABLE_MODES;
            unsigned  uiPreds[numMPMs];
    
            pu.multiRefIdx = 0;
    
            PU::getIntraMPMs( pu, uiPreds );
    
            //we copy only the ISP MPMs
            listPointerCopy = &( cu.ispMode == HOR_INTRA_SUBPARTITIONS ? uiRdModeListCopyHor : uiRdModeListCopyVer );
            listPointer     = &( cu.ispMode == HOR_INTRA_SUBPARTITIONS ? m_rdModeListWithoutMrlHor : m_rdModeListWithoutMrlVer );
            for( int k = 0; k < listPointerCopy->size(); k++ )
            {
              for( int q = 0; q < numMPMs; q++ )
              {
    
                if (listPointerCopy->at(k) == ModeInfo( false, 0, cu.ispMode, uiPreds[q] ))
    
                {
                  listPointer->push_back( listPointerCopy->at( k ) );
                  break;
                }
              }
            }
          }
          cu.ispMode = NOT_INTRA_SUBPARTITIONS;
        }
    
    
        CHECK( numModesForFullRD != uiRdModeList.size(), "Inconsistent state!" );
    
        // after this point, don't use numModesForFullRD
    
        // PBINTRA fast
    
        if( m_pcEncCfg->getUsePbIntraFast() && !cs.slice->isIntra() && uiRdModeList.size() < numModesAvailable && !cs.slice->getDisableSATDForRD() && ( mtsUsageFlag != 2 || lfnstIdx > 0 ) )
    
          double pbintraRatio = (lfnstIdx > 0) ? 1.25 : PBINTRA_RATIO;
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
          ModeInfo bestMipMode;
          int bestMipIdx = -1;
          for( int idx = 0; idx < uiRdModeList.size(); idx++ )
          {
            if( uiRdModeList[idx].mipFlg )
            {
              bestMipMode = uiRdModeList[idx];
              bestMipIdx = idx;
              break;
            }
          }
          const int numHadCand = 3;
    #else
    
          const int numHadCand = (testMip ? 2 : 1) * 3;
    
            if (CandHadList.size() < (k + 1) || CandHadList[k] > cs.interHad * pbintraRatio) { maxSize = k; }
    
          }
          if (maxSize > 0)
          {
            uiRdModeList.resize(std::min<size_t>(uiRdModeList.size(), maxSize));
    
    #if JVET_O0925_MIP_SIMPLIFICATIONS
            if( bestMipIdx >= 0 )
            {
              if( uiRdModeList.size() <= bestMipIdx )
              {
                uiRdModeList.push_back(bestMipMode);
              }
            }
    #endif