Skip to content
Snippets Groups Projects
IntraSearch.cpp 238 KiB
Newer Older
  • Learn to ignore specific revisions
  •         else
            {
              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);
            }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if ENABLE_DIMD
          bool isDimdValid = cu.slice->getSPS()->getUseDimd();
          if (isDimdValid)
          {
            cu.dimd = false;
            ModeInfo m = ModeInfo( false, false, 0, NOT_INTRA_SUBPARTITIONS, DIMD_IDX );
            uiRdModeList.push_back(m);
    
    Jie's avatar
    Jie committed
    #if !JVET_V0087_DIMD_NO_ISP
    
    Vadim Seregin's avatar
    Vadim Seregin committed
            if (testISP)
            {
              m.ispMod = HOR_INTRA_SUBPARTITIONS;
              m_ispCandListHor.push_back(m);
              m.ispMod = VER_INTRA_SUBPARTITIONS;
              m_ispCandListVer.push_back(m);
            }
    
    Jie's avatar
    Jie committed
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          }
    #else
    
          CHECK(numModesForFullRD != uiRdModeList.size(), "Inconsistent state!");
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
          // 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;
            int      maxSize      = -1;
            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;
            for (int k = numHadCand - 1; k >= 0; k--)
    
              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 (bestMipIdx >= 0)
              {
                if (uiRdModeList.size() <= bestMipIdx)
                {
                  uiRdModeList.push_back(bestMipMode);
                }
              }
              if (saveDataForISP)
              {
                m_ispCandListHor.resize(std::min<size_t>(m_ispCandListHor.size(), maxSize));
              }
    
            if (maxSize == 0)
            {
              cs.dist     = std::numeric_limits<Distortion>::max();
              cs.interHad = 0;
    
              //===== reset context models =====
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if JVET_V0130_INTRA_TMP
              m_CABACEstimator->getCtx() = SubCtx( Ctx::TmpFlag, ctxStartTpmFlag );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
              m_CABACEstimator->getCtx() = SubCtx(Ctx::MipFlag, ctxStartMipFlag);
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
              m_CABACEstimator->getCtx() = SubCtx( Ctx::TimdFlag, ctxStartTimdFlag );
    #endif
    
              m_CABACEstimator->getCtx() = SubCtx(Ctx::ISPMode, ctxStartIspMode);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if SECONDARY_MPM
              m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaMPMIdx, ctxStartMPMIdxFlag);
    #endif
    
              m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaPlanarFlag, ctxStartPlanarFlag);
              m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaMpmFlag, ctxStartIntraMode);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if SECONDARY_MPM
              m_CABACEstimator->getCtx() = SubCtx(Ctx::IntraLumaSecondMpmFlag, ctxStartIntraMode2);
    #endif
    
              m_CABACEstimator->getCtx() = SubCtx(Ctx::MultiRefLineIdx, ctxStartMrlIdx);
    
              return false;
            }
    
        int numNonISPModes = (int)uiRdModeList.size();
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
        bool isTimdValid = cu.slice->getSPS()->getUseTimd();
        if (cu.lwidth() * cu.lheight() > 1024 && cu.slice->getSliceType() == I_SLICE)
        {
          isTimdValid = false;
        }
        if (isTimdValid)
        {
          cu.timd = false;
          uiRdModeList.push_back( ModeInfo( false, false, 0, NOT_INTRA_SUBPARTITIONS, TIMD_IDX ) );
          numNonISPModes++;
          if (lfnstIdx == 0 && !cu.mtsFlag)
          {
            bool isFirstLineOfCtu     = (((pu.block(COMPONENT_Y).y) & ((pu.cs->sps)->getMaxCUWidth() - 1)) == 0);
            int  numOfPassesExtendRef = ((!sps.getUseMRL() || isFirstLineOfCtu) ? 1 : MRL_NUM_REF_LINES);
            for (int mRefNum = 1; mRefNum < numOfPassesExtendRef; mRefNum++)
            {
              int multiRefIdx = MULTI_REF_LINE_IDX[mRefNum];
              uiRdModeList.push_back( ModeInfo( false, false, multiRefIdx, NOT_INTRA_SUBPARTITIONS, TIMD_IDX ) );
              numNonISPModes++;
            }
          }
        }
    #endif
    
          // we reserve positions for ISP in the common full RD list
    
          const int maxNumRDModesISP = sps.getUseLFNST() ? 16 * NUM_LFNST_NUM_PER_SET : 16;
          m_curIspLfnstIdx = 0;
    
          for (int i = 0; i < maxNumRDModesISP; i++)
    
            uiRdModeList.push_back( ModeInfo( false, false, 0, INTRA_SUBPARTITIONS_RESERVED, 0 ) );
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
        if (isTimdValid && sps.getUseISP() && CU::canUseISP(width, height, cu.cs->sps->getMaxTbSize()) && lfnstIdx == 0)
        {
          uiRdModeList.push_back( ModeInfo( false, false, 0, HOR_INTRA_SUBPARTITIONS, TIMD_IDX ) );
          uiRdModeList.push_back( ModeInfo( false, false, 0, VER_INTRA_SUBPARTITIONS, TIMD_IDX ) );
        }
    #endif
    
        ModeInfo       uiBestPUMode;
    
        int            bestBDPCMMode = 0;
        double         bestCostNonBDPCM = MAX_DOUBLE;
    
    
        CodingStructure *csTemp = m_pTempCS[gp_sizeIdxInfo->idxFrom( cu.lwidth() )][gp_sizeIdxInfo->idxFrom( cu.lheight() )];
        CodingStructure *csBest = m_pBestCS[gp_sizeIdxInfo->idxFrom( cu.lwidth() )][gp_sizeIdxInfo->idxFrom( cu.lheight() )];
    
        csTemp->slice = cs.slice;
        csBest->slice = cs.slice;
        csTemp->initStructData();
        csBest->initStructData();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
        csTemp->picture = cs.picture;
        csBest->picture = cs.picture;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
        // just to be sure
        numModesForFullRD = ( int ) uiRdModeList.size();
    
        TUIntraSubPartitioner subTuPartitioner( partitioner );
    
        if ( testISP )
        {
          m_modeCtrl->setIspCost( MAX_DOUBLE );
          m_modeCtrl->setMtsFirstPassNoIspCost( MAX_DOUBLE );
        }
        int bestLfnstIdx = cu.lfnstIdx;
    
        for (int mode = isSecondColorSpace ? 0 : -2 * int(testBDPCM); mode < (int)uiRdModeList.size(); mode++)
    
        {
          // set CU/PU to luma prediction mode
          ModeInfo uiOrgMode;
    
          if (sps.getUseColorTrans() && !m_pcEncCfg->getRGBFormatFlag() && isSecondColorSpace && mode)
          {
            continue;
          }
    
          if (mode < 0 || (isSecondColorSpace && m_savedBDPCMModeFirstColorSpace[m_savedRdModeIdx][mode]))
    
            cu.bdpcmMode = mode < 0 ? -mode : m_savedBDPCMModeFirstColorSpace[m_savedRdModeIdx][mode];
    
            uiOrgMode = ModeInfo( false, false, 0, NOT_INTRA_SUBPARTITIONS, cu.bdpcmMode == 2 ? VER_IDX : HOR_IDX );
    
            uiOrgMode = uiRdModeList[mode];
          }
          if (!cu.bdpcmMode && uiRdModeList[mode].ispMod == INTRA_SUBPARTITIONS_RESERVED)
    
          {
            if (mode == numNonISPModes)   // the list needs to be sorted only once
    
              if (m_pcEncCfg->getUseFastISP())
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
                if (bestTimdMode)
                {
                  m_modeCtrl->setBestPredModeDCT2(MAP131TO67(uiBestPUMode.modeId));
                }
                else
                {
                  m_modeCtrl->setBestPredModeDCT2(uiBestPUMode.modeId);
                }
    #else
    
                m_modeCtrl->setBestPredModeDCT2(uiBestPUMode.modeId);
    
    Keming Cao's avatar
    Keming Cao committed
    #endif
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
              ModeInfo tempBestPUMode = uiBestPUMode;
              if (bestTimdMode)
              {
                tempBestPUMode.modeId = MAP131TO67(tempBestPUMode.modeId);
              }
              if (!xSortISPCandList(bestCurrentCost, csBest->cost, tempBestPUMode))
    #else
    
              if (!xSortISPCandList(bestCurrentCost, csBest->cost, uiBestPUMode))
    
    Keming Cao's avatar
    Keming Cao committed
    #endif
    
              {
                break;
              }
            }
            xGetNextISPMode(uiRdModeList[mode], (mode > 0 ? &uiRdModeList[mode - 1] : nullptr), Size(width, height));
            if (uiRdModeList[mode].ispMod == INTRA_SUBPARTITIONS_RESERVED)
            {
              continue;
    
            cu.lfnstIdx = m_curIspLfnstIdx;
            uiOrgMode   = uiRdModeList[mode];
          }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if ENABLE_DIMD
          cu.dimd = false;
          if( mode >= 0 && uiOrgMode.modeId == DIMD_IDX ) /*to check*/
          {
            uiOrgMode.modeId = cu.dimdMode;
            cu.dimd = true;
          }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if JVET_V0130_INTRA_TMP
          cu.tmpFlag = uiOrgMode.tmpFlag;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
          cu.mipFlag                     = uiOrgMode.mipFlg;
    
          pu.mipTransposedFlag           = uiOrgMode.mipTrFlg;
    
          cu.ispMode                     = uiOrgMode.ispMod;
          pu.multiRefIdx                 = uiOrgMode.mRefId;
          pu.intraDir[CHANNEL_TYPE_LUMA] = uiOrgMode.modeId;
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
          cu.timd = false;
          int modeDiff = uiOrgMode.modeId - MAP131TO67(cu.dimdMode);
          if (isTimdValid && lfnstIdx == 0 && uiOrgMode.ispMod > 0 && modeDiff == 0)
          {
            continue;
          }
          if (isTimdValid && uiOrgMode.mRefId > 0 && lfnstIdx == 0 && cu.mtsFlag == 0 && modeDiff == 0)
          {
            continue;
          }
          if (mode >= 0 && uiOrgMode.modeId == TIMD_IDX)
          {
            if (cu.ispMode)
            {
              cu.lfnstIdx = lfnstIdx;
              if (cu.ispMode == VER_INTRA_SUBPARTITIONS && uiBestPUMode.ispMod == 0 && !bestTimdMode)
              {
                continue;
              }
            }
            uiOrgMode.modeId = cu.timdMode;
            pu.intraDir[CHANNEL_TYPE_LUMA] = uiOrgMode.modeId;
            cu.timd = true;
          }
    #endif
    
    
          CHECK(cu.mipFlag && pu.multiRefIdx, "Error: combination of MIP and MRL not supported");
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
          if (!cu.timd)
          {
    #endif
            CHECK(pu.multiRefIdx && (pu.intraDir[0] == PLANAR_IDX),
                  "Error: combination of MRL and Planar mode not supported");
    #if JVET_W0123_TIMD_FUSION
          }
    #endif
    
          CHECK(cu.ispMode && cu.mipFlag, "Error: combination of ISP and MIP not supported");
          CHECK(cu.ispMode && pu.multiRefIdx, "Error: combination of ISP and MRL not supported");
    
          CHECK(cu.ispMode&& cu.colorTransform, "Error: combination of ISP and ACT not supported");
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if JVET_V0130_INTRA_TMP
          CHECK( cu.mipFlag && cu.tmpFlag, "Error: combination of MIP and TPM not supported" );
          CHECK( cu.tmpFlag && cu.ispMode, "Error: combination of TPM and ISP not supported" );
          CHECK( cu.tmpFlag && pu.multiRefIdx, "Error: combination of TPM and MRL not supported" );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    Jie's avatar
    Jie committed
    #if ENABLE_DIMD && JVET_V0087_DIMD_NO_ISP
          CHECK(cu.ispMode && cu.dimd, "Error: combination of ISP and DIMD not supported");
    #endif
    
          pu.intraDir[CHANNEL_TYPE_CHROMA] = cu.colorTransform ? DM_CHROMA_IDX : pu.intraDir[CHANNEL_TYPE_CHROMA];
    
    
          // set context models
          m_CABACEstimator->getCtx() = ctxStart;
    
          // determine residual for partition
          cs.initSubStructure( *csTemp, partitioner.chType, cs.area, true );
    
    
          bool tmpValidReturn = false;
    
            if ( m_pcEncCfg->getUseFastISP() )
            {
              m_modeCtrl->setISPWasTested(true);
            }
    
            tmpValidReturn = xIntraCodingLumaISP(*csTemp, subTuPartitioner, bestCurrentCost);
            if (csTemp->tus.size() == 0)
            {
              // no TUs were coded
              csTemp->cost = MAX_DOUBLE;
              continue;
            }
    
            // we save the data for future tests
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
            if (!cu.timd)
            {
    #endif
    
            m_ispTestedModes[m_curIspLfnstIdx].setModeResults((ISPType)cu.ispMode, (int)uiOrgMode.modeId, (int)csTemp->tus.size(), csTemp->cus[0]->firstTU->cbf[COMPONENT_Y] ? csTemp->cost : MAX_DOUBLE, csBest->cost);
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
            }
    #endif
    
            csTemp->cost = !tmpValidReturn ? MAX_DOUBLE : csTemp->cost;
    
            if (cu.colorTransform)
            {
              tmpValidReturn = xRecurIntraCodingACTQT(*csTemp, partitioner, mtsCheckRangeFlag, mtsFirstCheckId, mtsLastCheckId, moreProbMTSIdxFirst);
            }
            else
    
            {
              tmpValidReturn = xRecurIntraCodingLumaQT(
                *csTemp, partitioner, uiBestPUMode.ispMod ? bestCurrentCost : MAX_DOUBLE, -1, TU_NO_ISP,
                uiBestPUMode.ispMod, mtsCheckRangeFlag, mtsFirstCheckId, mtsLastCheckId, moreProbMTSIdxFirst);
            }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if JVET_V0130_INTRA_TMP
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
          if (!cu.ispMode && !cu.mtsFlag && !cu.lfnstIdx && !cu.bdpcmMode && !pu.multiRefIdx && !cu.mipFlag && !cu.tmpFlag && testISP && !cu.timd)
    #else
    
    Vadim Seregin's avatar
    Vadim Seregin committed
          if( !cu.ispMode && !cu.mtsFlag && !cu.lfnstIdx && !cu.bdpcmMode && !pu.multiRefIdx && !cu.mipFlag && !cu.tmpFlag && testISP )
    
    Keming Cao's avatar
    Keming Cao committed
    #endif
    #else
    #if JVET_W0123_TIMD_FUSION
          if (!cu.ispMode && !cu.mtsFlag && !cu.lfnstIdx && !cu.bdpcmMode && !pu.multiRefIdx && !cu.mipFlag && testISP && !cu.timd)
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
    
          if (!cu.ispMode && !cu.mtsFlag && !cu.lfnstIdx && !cu.bdpcmMode && !pu.multiRefIdx && !cu.mipFlag && testISP)
    
    Keming Cao's avatar
    Keming Cao committed
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if JVET_V0130_INTRA_TMP
            m_regIntraRDListWithCosts.push_back( ModeInfoWithCost( cu.mipFlag, pu.mipTransposedFlag, pu.multiRefIdx, cu.ispMode, uiOrgMode.modeId, cu.tmpFlag, csTemp->cost ) );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
    
            m_regIntraRDListWithCosts.push_back( ModeInfoWithCost( cu.mipFlag, pu.mipTransposedFlag, pu.multiRefIdx, cu.ispMode, uiOrgMode.modeId, csTemp->cost ) );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
          if( cu.ispMode && !csTemp->cus[0]->firstTU->cbf[COMPONENT_Y] )
          {
            csTemp->cost = MAX_DOUBLE;
    
    Nan Hu's avatar
    Nan Hu committed
            csTemp->costDbOffset = 0;
    
          validReturn |= tmpValidReturn;
    
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
          if( sps.getUseLFNST() && mtsUsageFlag == 1 && !cu.ispMode && mode >= 0 && !cu.timd )
    #else
    
          if( sps.getUseLFNST() && mtsUsageFlag == 1 && !cu.ispMode && mode >= 0 )
    
    Keming Cao's avatar
    Keming Cao committed
    #endif
    
            m_modeCostStore[lfnstIdx][mode] = tmpValidReturn ? csTemp->cost : (MAX_DOUBLE / 2.0); //(MAX_DOUBLE / 2.0) ??
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if JVET_V0130_INTRA_TMP
          DTRACE( g_trace_ctx, D_INTRA_COST, "IntraCost T [x=%d,y=%d,w=%d,h=%d] %f (%d,%d,%d,%d,%d,%d,%d) \n", cu.blocks[0].x,
                  cu.blocks[0].y, ( int ) width, ( int ) height, csTemp->cost, uiOrgMode.modeId, uiOrgMode.ispMod,
                  pu.multiRefIdx, cu.tmpFlag, cu.mipFlag, cu.lfnstIdx, cu.mtsFlag );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
    
          DTRACE(g_trace_ctx, D_INTRA_COST, "IntraCost T [x=%d,y=%d,w=%d,h=%d] %f (%d,%d,%d,%d,%d,%d) \n", cu.blocks[0].x,
    
                 cu.blocks[0].y, (int) width, (int) height, csTemp->cost, uiOrgMode.modeId, uiOrgMode.ispMod,
                 pu.multiRefIdx, cu.mipFlag, cu.lfnstIdx, cu.mtsFlag);
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
            if (isFirstColorSpace)
            {
              if (m_pcEncCfg->getRGBFormatFlag() || !cu.ispMode)
              {
                sortRdModeListFirstColorSpace(uiOrgMode, csTemp->cost, cu.bdpcmMode, m_savedRdModeFirstColorSpace[m_savedRdModeIdx], m_savedRdCostFirstColorSpace[m_savedRdModeIdx], m_savedBDPCMModeFirstColorSpace[m_savedRdModeIdx], m_numSavedRdModeFirstColorSpace[m_savedRdModeIdx]);
              }
            }
    
            // check r-d cost
            if( csTemp->cost < csBest->cost )
            {
              std::swap( csTemp, csBest );
    
              uiBestPUMode  = uiOrgMode;
              bestBDPCMMode = cu.bdpcmMode;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if ENABLE_DIMD
              bestDimdMode = cu.dimd;
    
    Keming Cao's avatar
    Keming Cao committed
    #endif
    #if JVET_W0123_TIMD_FUSION
              bestTimdMode = cu.timd;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
              if( sps.getUseLFNST() && mtsUsageFlag == 1 && !cu.ispMode )
              {
                m_bestModeCostStore[ lfnstIdx ] = csBest->cost; //cs.cost;
    
                m_bestModeCostValid[ lfnstIdx ] = true;
    
              }
              if( csBest->cost < bestCurrentCost )
              {
                bestCurrentCost = csBest->cost;
              }
    
              if ( cu.ispMode )
              {
                m_modeCtrl->setIspCost(csBest->cost);
                bestLfnstIdx = cu.lfnstIdx;
              }
              else if ( testISP )
              {
                m_modeCtrl->setMtsFirstPassNoIspCost(csBest->cost);
              }
    
            }
            if( !cu.ispMode && !cu.bdpcmMode && csBest->cost < bestCostNonBDPCM )
    
              bestCostNonBDPCM = csBest->cost;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
          if( m_pcEncCfg->getFastLocalDualTreeMode() )
    
            if( cu.isConsIntra() && !cu.slice->isIntra() && csBest->cost != MAX_DOUBLE && costInterCU != COST_UNKNOWN && mode >= 0 )
    
              if( m_pcEncCfg->getFastLocalDualTreeMode() == 2 )
    
                //Note: only try one intra mode, which is especially useful to reduce EncT for LDB case (around 4%)
    
          if (sps.getUseColorTrans() && !CS::isDualITree(cs))
          {
            if ((m_pcEncCfg->getRGBFormatFlag() && !cu.colorTransform) && csBest->cost != MAX_DOUBLE && bestCS->cost != MAX_DOUBLE && mode >= 0)
            {
              if (csBest->cost > bestCS->cost)
              {
                break;
              }
            }
          }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
        cu.ispMode = uiBestPUMode.ispMod;
    
        cu.lfnstIdx = bestLfnstIdx;
    
            cs.useSubStructure(*csBest, partitioner.chType, pu, true, true, KEEP_PRED_AND_RESI_SIGNALS, KEEP_PRED_AND_RESI_SIGNALS, true);
    
            cs.useSubStructure(*csBest, partitioner.chType, pu.singleChan(CHANNEL_TYPE_LUMA), true, true, KEEP_PRED_AND_RESI_SIGNALS,
    
        if( validReturn )
        {
          //=== update PU data ====
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if JVET_V0130_INTRA_TMP
          cu.tmpFlag = uiBestPUMode.tmpFlag;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
          cu.mipFlag = uiBestPUMode.mipFlg;
    
          pu.mipTransposedFlag             = uiBestPUMode.mipTrFlg;
    
          pu.multiRefIdx = uiBestPUMode.mRefId;
          pu.intraDir[ CHANNEL_TYPE_LUMA ] = uiBestPUMode.modeId;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if ENABLE_DIMD
          cu.dimd = bestDimdMode;
          if (cu.dimd)
          {
            CHECK(pu.multiRefIdx > 0, "use of DIMD");
          }
    #endif
    
          cu.bdpcmMode = bestBDPCMMode;
    
    Keming Cao's avatar
    Keming Cao committed
    #if JVET_W0123_TIMD_FUSION
          cu.timd = bestTimdMode;
          if (cu.timd)
          {
            pu.intraDir[ CHANNEL_TYPE_LUMA ] = cu.timdMode;
          }
    #endif
    
          if (cu.colorTransform)
          {
            CHECK(pu.intraDir[CHANNEL_TYPE_CHROMA] != DM_CHROMA_IDX, "chroma should use DM mode for adaptive color transform");
          }
    
      }
    
      //===== reset context models =====
      m_CABACEstimator->getCtx() = ctxStart;
    
    void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner, const double maxCostAllowed )
    
    {
      const ChromaFormat format   = cu.chromaFormat;
      const uint32_t    numberValidComponents = getNumberValidComponents(format);
      CodingStructure &cs = *cu.cs;
      const TempCtx ctxStart  ( m_CtxCache, m_CABACEstimator->getCtx() );
    
      cs.setDecomp( cs.area.Cb(), false );
    
    
      double    bestCostSoFar = maxCostAllowed;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
      bool      lumaUsesISP   = !cu.isSepTree() && cu.ispMode;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
      bool      lumaUsesISP = !CS::isDualITree(*cu.cs) && cu.ispMode;
    #endif
    
      PartSplit ispType       = lumaUsesISP ? CU::getISPType( cu, COMPONENT_Y ) : TU_NO_ISP;
      CHECK( cu.ispMode && bestCostSoFar < 0, "bestCostSoFar must be positive!" );
    
    
      auto &pu = *cu.firstPU;
    
      {
        uint32_t       uiBestMode = 0;
        Distortion uiBestDist = 0;
        double     dBestCost = MAX_DOUBLE;
    
        int32_t bestBDPCMMode = 0;
    
          int32_t  uiMinMode = 0;
          int32_t  uiMaxMode = NUM_CHROMA_MODE;
    
          //----- check chroma modes -----
          uint32_t chromaCandModes[ NUM_CHROMA_MODE ];
          PU::getIntraChromaCandModes( pu, chromaCandModes );
    
          // create a temporary CS
          CodingStructure &saveCS = *m_pSaveCS[0];
          saveCS.pcv      = cs.pcv;
          saveCS.picture  = cs.picture;
          saveCS.area.repositionTo( cs.area );
          saveCS.clearTUs();
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
          if( !cu.isSepTree() && cu.ispMode )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
          if (!CS::isDualITree(cs) && cu.ispMode)
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
          if( cu.isSepTree() )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #else
          if (CS::isDualITree(cs))
    #endif
    
          {
            if( partitioner.canSplit( TU_MAX_TR_SPLIT, cs ) )
            {
              partitioner.splitCurrArea( TU_MAX_TR_SPLIT, cs );
    
              do
              {
                cs.addTU( CS::getArea( cs, partitioner.currArea(), partitioner.chType ), partitioner.chType ).depth = partitioner.currTrDepth;
              } while( partitioner.nextPart( cs ) );
    
              partitioner.exitCurrSplit();
            }
            else
            cs.addTU( CS::getArea( cs, partitioner.currArea(), partitioner.chType ), partitioner.chType );
          }
    
          std::vector<TransformUnit*> orgTUs;
    
    
          if( lumaUsesISP )
          {
            CodingUnit& auxCU = saveCS.addCU( cu, partitioner.chType );
            auxCU.ispMode = cu.ispMode;
            saveCS.sps = cu.cs->sps;
            saveCS.addPU( *cu.firstPU, partitioner.chType );
          }
    
    
    
          // create a store for the TUs
          for( const auto &ptu : cs.tus )
          {
            // for split TUs in HEVC, add the TUs without Chroma parts for correct setting of Cbfs
    
            if( lumaUsesISP || pu.contains( *ptu, CHANNEL_TYPE_CHROMA ) )
    
            {
              saveCS.addTU( *ptu, partitioner.chType );
              orgTUs.push_back( ptu );
            }
          }
    
          // SATD pre-selecting.
          int satdModeList[NUM_CHROMA_MODE];
          int64_t satdSortedCost[NUM_CHROMA_MODE];
          for (int i = 0; i < NUM_CHROMA_MODE; i++)
          {
            satdSortedCost[i] = 0; // for the mode not pre-select by SATD, do RDO by default, so set the initial value 0.
            satdModeList[i] = 0;
          }
          bool modeIsEnable[NUM_INTRA_MODE + 1]; // use intra mode idx to check whether enable
          for (int i = 0; i < NUM_INTRA_MODE + 1; i++)
          {
            modeIsEnable[i] = 1;
          }
    
          DistParam distParamSad;
          DistParam distParamSatd;
    
          pu.intraDir[1] = MDLM_L_IDX; // temporary assigned, just to indicate this is a MDLM mode. for luma down-sampling operation.
    
          initIntraPatternChType(cu, pu.Cb());
          initIntraPatternChType(cu, pu.Cr());
          xGetLumaRecPixels(pu, pu.Cb());
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if MMLM
          m_encPreRDRun = true;
    #endif
    
          for (int idx = uiMinMode; idx <= uiMaxMode - 1; idx++)
          {
            int mode = chromaCandModes[idx];
            satdModeList[idx] = mode;
            if (PU::isLMCMode(mode) && !PU::isLMCModeEnabled(pu, mode))
            {
              continue;
            }
    
            if ((mode == LM_CHROMA_IDX) || (mode == PLANAR_IDX) || (mode == DM_CHROMA_IDX)) // only pre-check regular modes and MDLM modes, not including DM ,Planar, and LM
    
            {
              continue;
            }
            pu.intraDir[1] = mode; // temporary assigned, for SATD checking.
    
    
            int64_t sad = 0;
            int64_t sadCb = 0;
            int64_t satdCb = 0;
            int64_t sadCr = 0;
            int64_t satdCr = 0;
    
            CodingStructure& cs = *(pu.cs);
    
            CompArea areaCb = pu.Cb();
            PelBuf orgCb = cs.getOrgBuf(areaCb);
            PelBuf predCb = cs.getPredBuf(areaCb);
    
            m_pcRdCost->setDistParam(distParamSad, orgCb, predCb, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, false);
            m_pcRdCost->setDistParam(distParamSatd, orgCb, predCb, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, true);
            distParamSad.applyWeight = false;
            distParamSatd.applyWeight = false;
    
            if (PU::isLMCMode(mode))
            {
              predIntraChromaLM(COMPONENT_Cb, predCb, pu, areaCb, mode);
            }
            else
            {
    
              initPredIntraParams(pu, pu.Cb(), *pu.cs->sps);
              predIntraAng(COMPONENT_Cb, predCb, pu);
    
            sadCb = distParamSad.distFunc(distParamSad) * 2;
            satdCb = distParamSatd.distFunc(distParamSatd);
            sad += std::min(sadCb, satdCb);
    
            CompArea areaCr = pu.Cr();
            PelBuf orgCr = cs.getOrgBuf(areaCr);
            PelBuf predCr = cs.getPredBuf(areaCr);
    
            m_pcRdCost->setDistParam(distParamSad, orgCr, predCr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, false);
            m_pcRdCost->setDistParam(distParamSatd, orgCr, predCr, pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, true);
            distParamSad.applyWeight = false;
            distParamSatd.applyWeight = false;
    
            if (PU::isLMCMode(mode))
            {
              predIntraChromaLM(COMPONENT_Cr, predCr, pu, areaCr, mode);
            }
            else
            {
    
              initPredIntraParams(pu, pu.Cr(), *pu.cs->sps);
              predIntraAng(COMPONENT_Cr, predCr, pu);
    
            sadCr = distParamSad.distFunc(distParamSad) * 2;
            satdCr = distParamSatd.distFunc(distParamSatd);
            sad += std::min(sadCr, satdCr);
    
            satdSortedCost[idx] = sad;
          }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if MMLM
          m_encPreRDRun = false;
    #endif
    
          // sort the mode based on the cost from small to large.
          int tempIdx = 0;
          int64_t tempCost = 0;
          for (int i = uiMinMode; i <= uiMaxMode - 1; i++)
          {
            for (int j = i + 1; j <= uiMaxMode - 1; j++)
            {
              if (satdSortedCost[j] < satdSortedCost[i])
              {
                tempIdx = satdModeList[i];
                satdModeList[i] = satdModeList[j];
                satdModeList[j] = tempIdx;
    
                tempCost = satdSortedCost[i];
                satdSortedCost[i] = satdSortedCost[j];
                satdSortedCost[j] = tempCost;
    
              }
            }
          }
          int reducedModeNumber = 2; // reduce the number of chroma modes
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if MMLM
          reducedModeNumber += 3;    // Match number of RDs with the anchor
    #endif
    
          for (int i = 0; i < reducedModeNumber; i++)
          {
            modeIsEnable[satdModeList[uiMaxMode - 1 - i]] = 0; // disable the last reducedModeNumber modes
          }
    
          bool testBDPCM = true;
          testBDPCM = testBDPCM && CU::bdpcmAllowed(cu, COMPONENT_Cb) && cu.ispMode == 0 && cu.mtsFlag == 0 && cu.lfnstIdx == 0;
          for (int32_t uiMode = uiMinMode - (2 * int(testBDPCM)); uiMode < uiMaxMode; uiMode++)
    
            int chromaIntraMode;
    
    
            if (uiMode < 0)
            {
                cu.bdpcmModeChroma = -uiMode;
    
                chromaIntraMode = cu.bdpcmModeChroma == 2 ? chromaCandModes[1] : chromaCandModes[2];
    
              chromaIntraMode = chromaCandModes[uiMode];
    
    
              cu.bdpcmModeChroma = 0;
              if( PU::isLMCMode( chromaIntraMode ) && ! PU::isLMCModeEnabled( pu, chromaIntraMode ) )
              {
                continue;
              }
              if (!modeIsEnable[chromaIntraMode] && PU::isLMCModeEnabled(pu, chromaIntraMode)) // when CCLM is disable, then MDLM is disable. not use satd checking
              {
                continue;
              }
    
            cs.setDecomp( pu.Cb(), false );
            cs.dist = baseDist;
            //----- restore context models -----
            m_CABACEstimator->getCtx() = ctxStart;
    
            //----- chroma coding -----
            pu.intraDir[1] = chromaIntraMode;
    
    
            xRecurIntraChromaCodingQT( cs, partitioner, bestCostSoFar, ispType );
            if( lumaUsesISP && cs.dist == MAX_UINT )
            {
              continue;
            }
    
            if (cs.sps->getTransformSkipEnabledFlag())
    
            uint64_t fracBits   = xGetIntraFracBitsQT( cs, partitioner, false, true, -1, ispType );
    
            Distortion uiDist = cs.dist;
            double    dCost   = m_pcRdCost->calcRdCost( fracBits, uiDist - baseDist );
    
            //----- compare -----
            if( dCost < dBestCost )
            {
    
              if( lumaUsesISP && dCost < bestCostSoFar )
              {
                bestCostSoFar = dCost;
              }
    
              for( uint32_t i = getFirstComponentOfChannel( CHANNEL_TYPE_CHROMA ); i < numberValidComponents; i++ )
              {
                const CompArea &area = pu.blocks[i];
    
                saveCS.getRecoBuf     ( area ).copyFrom( cs.getRecoBuf   ( area ) );
    #if KEEP_PRED_AND_RESI_SIGNALS
                saveCS.getPredBuf     ( area ).copyFrom( cs.getPredBuf   ( area ) );
                saveCS.getResiBuf     ( area ).copyFrom( cs.getResiBuf   ( area ) );
    
    Taoran Lu's avatar
    Taoran Lu committed
    #endif
                saveCS.getPredBuf     ( area ).copyFrom( cs.getPredBuf   (area ) );
                cs.picture->getPredBuf( area ).copyFrom( cs.getPredBuf   (area ) );
    
                cs.picture->getRecoBuf( area ).copyFrom( cs.getRecoBuf( area ) );
    
                for( uint32_t j = 0; j < saveCS.tus.size(); j++ )
                {
                  saveCS.tus[j]->copyComponentFrom( *orgTUs[j], area.compID );
                }
              }
    
              dBestCost  = dCost;
              uiBestDist = uiDist;
              uiBestMode = chromaIntraMode;
    
              bestBDPCMMode = cu.bdpcmModeChroma;
    
            }
          }
    
          for( uint32_t i = getFirstComponentOfChannel( CHANNEL_TYPE_CHROMA ); i < numberValidComponents; i++ )
          {
            const CompArea &area = pu.blocks[i];
    
            cs.getRecoBuf         ( area ).copyFrom( saveCS.getRecoBuf( area ) );
    #if KEEP_PRED_AND_RESI_SIGNALS
            cs.getPredBuf         ( area ).copyFrom( saveCS.getPredBuf( area ) );
            cs.getResiBuf         ( area ).copyFrom( saveCS.getResiBuf( area ) );
    #endif
    
    Taoran Lu's avatar
    Taoran Lu committed
            cs.getPredBuf         ( area ).copyFrom( saveCS.getPredBuf( area ) );
            cs.picture->getPredBuf( area ).copyFrom( cs.getPredBuf    ( area ) );
    
    
            cs.picture->getRecoBuf( area ).copyFrom( cs.    getRecoBuf( area ) );
    
            for( uint32_t j = 0; j < saveCS.tus.size(); j++ )
            {
              orgTUs[ j ]->copyComponentFrom( *saveCS.tus[ j ], area.compID );
            }
          }
        }
    
        pu.intraDir[1] = uiBestMode;
        cs.dist        = uiBestDist;
    
        cu.bdpcmModeChroma = bestBDPCMMode;
    
      }
    
      //----- restore context models -----
      m_CABACEstimator->getCtx() = ctxStart;
    
      if( lumaUsesISP && bestCostSoFar >= maxCostAllowed )
      {
        cu.ispMode = 0;
      }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
    void IntraSearch::saveCuAreaCostInSCIPU( Area area, double cost )
    {
      if( m_numCuInSCIPU < NUM_INTER_CU_INFO_SAVE )
      {
        m_cuAreaInSCIPU[m_numCuInSCIPU] = area;
        m_cuCostInSCIPU[m_numCuInSCIPU] = cost;
        m_numCuInSCIPU++;
      }
    }
    
    void IntraSearch::initCuAreaCostInSCIPU()
    {
      for( int i = 0; i < NUM_INTER_CU_INFO_SAVE; i++ )
      {
        m_cuAreaInSCIPU[i] = Area();
        m_cuCostInSCIPU[i] = 0;
      }
      m_numCuInSCIPU = 0;
    }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
    void IntraSearch::PLTSearch(CodingStructure &cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp)
    
      CodingUnit    &cu = *cs.getCU(partitioner.chType);
    
      TransformUnit &tu = *cs.getTU(partitioner.chType);
    
      uint32_t height = cu.block(compBegin).height;
      uint32_t width = cu.block(compBegin).width;
    
      if (m_pcEncCfg->getLmcs() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
    
      {
        cs.getPredBuf().copyFrom(cs.getOrgBuf());
        cs.getPredBuf().Y().rspSignal(m_pcReshape->getFwdLUT());
      }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
      if( cu.isLocalSepTree() )
    
        cs.prevPLT.curPLTSize[compBegin] = cs.prevPLT.curPLTSize[COMPONENT_Y];
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
      cu.lastPLTSize[compBegin] = cs.prevPLT.curPLTSize[compBegin];
      //derive palette
      derivePLTLossy(cs, partitioner, compBegin, numComp);
      reorderPLT(cs, partitioner, compBegin, numComp);
    
      bool idxExist[MAXPLTSIZE + 1] = { false };
    
      preCalcPLTIndexRD(cs, partitioner, compBegin, numComp); // Pre-calculate distortions for each pixel
    
      double rdCost = MAX_DOUBLE;
    
      deriveIndexMap(cs, partitioner, compBegin, numComp, PLT_SCAN_HORTRAV, rdCost, idxExist); // Optimize palette index map (horizontal scan)
    
      if ((cu.curPLTSize[compBegin] + cu.useEscape[compBegin]) > 1)
      {
    
        deriveIndexMap(cs, partitioner, compBegin, numComp, PLT_SCAN_VERTRAV, rdCost, idxExist); // Optimize palette index map (vertical scan)
      }
      // Remove unused palette entries
      uint8_t newPLTSize = 0;
      int idxMapping[MAXPLTSIZE + 1];
      memset(idxMapping, -1, sizeof(int) * (MAXPLTSIZE + 1));
      for (int i = 0; i < cu.curPLTSize[compBegin]; i++)
      {
        if (idxExist[i])
        {
          idxMapping[i] = newPLTSize;
          newPLTSize++;
        }
    
      idxMapping[cu.curPLTSize[compBegin]] = cu.useEscape[compBegin]? newPLTSize: -1;
      if (newPLTSize != cu.curPLTSize[compBegin]) // there exist unused palette entries
      { // update palette table and reuseflag
        Pel curPLTtmp[MAX_NUM_COMPONENT][MAXPLTSIZE];
        int reuseFlagIdx = 0, curPLTtmpIdx = 0, reuseEntrySize = 0;
        memset(cu.reuseflag[compBegin], false, sizeof(bool) * MAXPLTPREDSIZE);
    
        int compBeginTmp = compBegin;
        int numCompTmp   = numComp;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
        if( cu.isLocalSepTree() )
    
          memset(cu.reuseflag[COMPONENT_Y], false, sizeof(bool) * MAXPLTPREDSIZE);
    
          compBeginTmp = COMPONENT_Y;
          numCompTmp   = (cu.chromaFormat != CHROMA_400) ? 3 : 1;
        }
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
        for (int curIdx = 0; curIdx < cu.curPLTSize[compBegin]; curIdx++)
        {
          if (idxExist[curIdx])
          {
    
            for (int comp = compBeginTmp; comp < (compBeginTmp + numCompTmp); comp++)
    
              curPLTtmp[comp][curPLTtmpIdx] = cu.curPLT[comp][curIdx];
    
            // Update reuse flags
            if (curIdx < cu.reusePLTSize[compBegin])
            {
              bool match = false;
              for (; reuseFlagIdx < cs.prevPLT.curPLTSize[compBegin]; reuseFlagIdx++)
              {
                bool matchTmp = true;
                for (int comp = compBegin; comp < (compBegin + numComp); comp++)
                {
                  matchTmp = matchTmp && (curPLTtmp[comp][curPLTtmpIdx] == cs.prevPLT.curPLT[comp][reuseFlagIdx]);
                }
                if (matchTmp)
                {
                  match = true;
                  break;
                }
              }
              if (match)
              {
                cu.reuseflag[compBegin][reuseFlagIdx] = true;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if !INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
    
                if( cu.isLocalSepTree() )
    
                  cu.reuseflag[COMPONENT_Y][reuseFlagIdx] = true;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
                reuseEntrySize++;
              }
            }
            curPLTtmpIdx++;
          }
        }
        cu.reusePLTSize[compBegin] = reuseEntrySize;
        // update palette table