Skip to content
Snippets Groups Projects
IntraSearch.cpp 589 KiB
Newer Older
  • Learn to ignore specific revisions
  •             
                ModeInfo currMode;
                for (int tool = 0; tool < numTool; tool++)
                {
                  isTimd      = tool == 0;
                  isTimdMrl   = tool == 1;
                  
                  for (int pass = 0; pass < numToolPass[tool]; pass++)
                  {
                    if (isTimd)
                    {
                      cu.timd = true;
    
    #if JVET_AJ0146_TIMDSAD
                      cu.timdSad = false;
    #endif				  
    
                      cu.timdMrg = pass == 1;
                      intraDir = !cu.timdMrg ? cu.timdMode : cu.timdMrgList[0][0];
                      modeId = !cu.timdMrg ? TIMD_IDX : TIMDM_IDX;
                      modeRefIdx = 0;
                      multiRefIdx = 0;
                    }
    
                    if (isTimdMrl)
                    {
                      multiRefIdx = MULTI_REF_LINE_IDX[pass + 1];
                      modeRefIdx = multiRefIdx;
                      intraDir = cu.timdMode;
                      modeId = TIMD_IDX;
                      cu.timd = true;
    
    #if JVET_AJ0146_TIMDSAD
                      cu.timdSad = false;
    #endif				  
    
                      cu.timdMrg = false;
                      testTimdMrl = true;
                    }
    
                    // PU/CU init
                    pu.intraDir[0] = intraDir;
                    pu.cu->tmrlFlag = false;
                    pu.multiRefIdx = multiRefIdx;
                    pu.cu->timd = isTimd || isTimdMrl;
    
    #if JVET_AJ0146_TIMDSAD
                    pu.cu->timdSad = false;
    #endif
    
                    // Init intra pattern
                    initIntraPatternChType(cu, pu.Y());
    
                    // Init IPM parameters
                    initPredIntraParams(pu, pu.Y(), sps);
    
                    // Prediction
                    predIntraAng(COMPONENT_Y, piPred, pu);
                    
                    // Cost calculation
                    Distortion sadCost = distParamSad.distFunc(distParamSad);
                    Distortion minSadHad = std::min(sadCost * 2, distParamHad.distFunc(distParamHad));
    
                    loadStartStates();
                    uint64_t fracModeBits = xFracModeBitsIntra(pu, intraDir, CHANNEL_TYPE_LUMA);
    
                    double cost = (double) minSadHad + (double) fracModeBits * sqrtLambdaForFirstPass;
                    currMode = ModeInfo(false, false, modeRefIdx, NOT_INTRA_SUBPARTITIONS, modeId);
                    // Update lists
                    numTimdSatd++;
                    timdModes.push_back(currMode);
                    timdCosts.push_back(cost);
                    timdSadCosts.push_back(static_cast<double>(minSadHad));
                    TimdMode mode = getTimdMode(cu.timdMrg, multiRefIdx);
                    PelBuf timdSaveBuf(m_timdPredBuf[mode], pu.Y());
                    timdSaveBuf.copyFrom(piPred);
                    m_satdCostTIMD[mode][0] = static_cast<uint64_t>(cost);
                    m_satdCostTIMD[mode][1] = minSadHad;
    
    #if JVET_AK0061_PDP_MPM
                    if (pdpPredEligible && pdpSaveFlag) 
                    {
                      if (cu.timdMrg) 
                      {
                        m_timdMergeRdModeList.first = ModeInfo(false, false, modeRefIdx, NOT_INTRA_SUBPARTITIONS, modeId);
                        m_timdMergeRdModeList.second = cost;
                      }
                    }
    #endif
    
                  }
                }
                cu.tmrlFlag = false;           
                cu.timd = false;
                cu.timdMrg = false;
    #endif
    
    
                CHECKD(uiRdModeList.size() != numModesForFullRD, "Error: RD mode list size");
    
    #if JVET_V0130_INTRA_TMP && JVET_AB0130_ITMP_SAMPLING
                // derive TPM candidate using hadamard
                if (testTpm)
                {
                  cu.tmpFlag = true;
                  cu.mipFlag = false;
                  pu.multiRefIdx = 0;
    
    
    #if JVET_AD0086_ENHANCED_INTRA_TMP
                  static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeListTmp;
    
                  static_vector<double, FAST_UDI_MAX_RDMODE_NUM> candCostListTmp;
    
                  int foundCandiNum = 0;
                  bool bsuccessfull = 0;
    
    #endif
    #if JVET_AH0200_INTRA_TMP_BV_REORDER
                  int adjustedTMPNonLicBvNum = TMP_REFINE_NONLIC_BV_NUM;
                  int adjustedTmpLicBvNum = TMP_REFINE_LIC_BV_NUM;
                  if(m_pcEncCfg->getIntraPeriod() != 1)
                  {
                    adjustedTMPNonLicBvNum = 10;
                    adjustedTmpLicBvNum = 4;
                  }
                  static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeListFracTmp;
                  static_vector<double, FAST_UDI_MAX_RDMODE_NUM> candCostListFracTmp;
                  Distortion backupMinSadHad[MTMP_NUM];
                  Distortion backupSadCost[MTMP_NUM];
                  Distortion backupLicMinSadHad[MTMP_NUM][4];
                  Distortion backupLicSadCost[MTMP_NUM][4];
                  static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeListLicFracTmp;
                  static_vector<double, FAST_UDI_MAX_RDMODE_NUM> candCostListLicFracTmp;
                  static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeListTmpLic;
                  static_vector<double, FAST_UDI_MAX_RDMODE_NUM> candCostListTmpLic;
    
                  CodingUnit cuCopy = cu;
    
    #if JVET_W0069_TMP_BOUNDARY
                  RefTemplateType templateType = getRefTemplateType(cuCopy, cuCopy.blocks[COMPONENT_Y]);
                  if (templateType != NO_TEMPLATE)
    #else
                  if (isRefTemplateAvailable(cuCopy, cuCopy.blocks[COMPONENT_Y]))
    #endif
                  {
    
    #if JVET_AD0086_ENHANCED_INTRA_TMP
                    cu.tmpIsSubPel = 0;
    
    #if JVET_AG0136_INTRA_TMP_LIC
                    cu.tmpSubPelIdx = -1;
    #else
    
    #endif
    #if JVET_AH0200_INTRA_TMP_BV_REORDER
                    cu.tmpFracIdx   = 0;
                    int numModesForFracIntraTmp = numModesForFullRD + adjustedTMPNonLicBvNum;
    
    #if JVET_AI0136_ADAPTIVE_DUAL_TREE
                    if(relatedCU && relatedCU->skipFracTmp)
    #else
    
                    {
                      numModesForFracIntraTmp = numModesForFullRD;
                    }
                    if(m_tmpNumCand > 0)
                    {
                      for(int idxInList=0; idxInList < uiRdModeList.size(); idxInList++)
                      {
                        if(cu.lwidth() * cu.lheight() > TMP_SKIP_REFINE_THRESHOLD)
                        {
                          break;
                        }
                        updateCandList(uiRdModeList[idxInList], candCostList[idxInList], uiRdModeListFracTmp, candCostListFracTmp, numModesForFracIntraTmp);
                      }
                    }
    
                    int numModesForLicFracIntraTmp = numModesForFullRD + adjustedTmpLicBvNum;
    
    #if JVET_AI0136_ADAPTIVE_DUAL_TREE
                    if(relatedCU && relatedCU->skipFracTmp)
    #else
    
                    {
                      numModesForLicFracIntraTmp = numModesForFullRD;
                    }
                    if(m_tmpNumCandUseMR > 0)
                    {
                      for(int idxInList=0; idxInList < uiRdModeList.size(); idxInList++)
                      {
                        if(cu.lwidth() * cu.lheight() > TMP_SKIP_REFINE_THRESHOLD)
                        {
                          break;
                        }
                        updateCandList(uiRdModeList[idxInList], candCostList[idxInList], uiRdModeListLicFracTmp, candCostListLicFracTmp, numModesForLicFracIntraTmp);
                      }
                    }
    
                    for(int tmpFusionFlag = 0; tmpFusionFlag <= 1; tmpFusionFlag++)
                    {
                      cu.tmpFusionFlag = tmpFusionFlag ? true: false;
    
                      for (int tmpFlmFlag = 0; tmpFlmFlag <= 1; tmpFlmFlag++)
                      {
                        cu.tmpFlmFlag = tmpFlmFlag ? true: false;
                        if(tmpFlmFlag && tmpFusionFlag)
                        {
                          continue;
                        }
    
    
    #if JVET_AG0136_INTRA_TMP_LIC
                        for (int tmpLicFlag = 0; tmpLicFlag <= 1; tmpLicFlag++)
                        {
                          cu.ibcLicFlag = tmpLicFlag ? true : false;
                          cu.tmpLicFlag = tmpLicFlag ? true : false;
                          if (tmpLicFlag && tmpFlmFlag)
                          {
                            continue;
                          }
                          const int ibcLicLoopNum = (cu.slice->getSPS()->getItmpLicExtension() && cu.tmpLicFlag && !cu.tmpFusionFlag) ? 4 : 1;
                          for (int licIdc = 0; licIdc < ibcLicLoopNum; licIdc++)
                          {
                            cu.ibcLicIdx = licIdc;
                          int idxNum = cu.tmpFusionFlag ? TMP_GROUP_IDX << 1 : (cu.tmpLicFlag ? m_tmpNumCandUseMR : m_tmpNumCand);
    #else
    
                        int idxNum = cu.tmpFusionFlag ? TMP_GROUP_IDX << 1 : m_tmpNumCand;
    
                        for (int tmpIdx = 0; tmpIdx < idxNum; tmpIdx++)
                        {
    
    #if JVET_AG0136_INTRA_TMP_LIC
                          if (cu.tmpFusionFlag && !(cu.tmpLicFlag ? m_tmpFusionInfoUseMR : m_tmpFusionInfo)[tmpIdx].bValid)
    #else
    
                          if(cu.tmpFusionFlag && !m_tmpFusionInfo[tmpIdx].bValid)
    
                          generateTMPrediction(piPred.buf, piPred.stride, placeHolder, pu
    #if JVET_AG0136_INTRA_TMP_LIC
                                               , cu.tmpLicFlag
    #endif
                                               , false);
    #if JVET_AG0136_INTRA_TMP_LIC
                            if (cu.tmpLicFlag)
                            {
                              if (!cu.tmpFusionFlag)
                              {
                                const auto& arrayLicParams = getMemLicParams(cu.ibcLicIdx, cu.tmpIdx);
                                if (cu.ibcLicIdx == IBC_LIC_IDX_M)
                                {
                                  piPred.linearTransforms(arrayLicParams[1], arrayLicParams[0], arrayLicParams[2], arrayLicParams[4], arrayLicParams[3], arrayLicParams[5], arrayLicParams[6], true, cu.cs->slice->clpRng(COMPONENT_Y));
                                }
                                else
                                {
                                  piPred.linearTransform(arrayLicParams[1], arrayLicParams[0], arrayLicParams[2], true, cu.cs->slice->clpRng(COMPONENT_Y));
                                }
                              }
                            }
    #endif
    
                          xGenerateTmpFlmPred(piPred, pu.lwidth(), pu.lheight(), templateType, pu.cu, false);
    
                          xTMPFusionApplyModel(piPred, pu.lwidth(), pu.lheight(), templateType, pu.cu
    #if JVET_AG0136_INTRA_TMP_LIC
                                               , cu.tmpLicFlag
    #endif
                                               , false);
    
    
    #if JVET_W0069_TMP_BOUNDARY
    #if TMP_FAST_ENC
                    bsuccessfull = generateTMPrediction(piPred.buf, piPred.stride, pu.Y(), foundCandiNum, pu.cu);
    #else
                    getTargetTemplate(&cuCopy, pu.lwidth(), pu.lheight(), templateType);
                    candidateSearchIntra(&cuCopy, pu.lwidth(), pu.lheight(), templateType);
                    bsuccessfull = generateTMPrediction(piPred.buf, piPred.stride, pu.lwidth(), pu.lheight(), foundCandiNum);
    #endif
    #else
    #if TMP_FAST_ENC
                    bsuccessfull = generateTMPrediction(piPred.buf, piPred.stride, pu.Y(), foundCandiNum, pu.cu);
    #else
                    getTargetTemplate(&cuCopy, pu.lwidth(), pu.lheight());
                    candidateSearchIntra(&cuCopy, pu.lwidth(), pu.lheight());
                    bsuccessfull = generateTMPrediction(piPred.buf, piPred.stride, pu.lwidth(), pu.lheight(), foundCandiNum);
    #endif
    #endif
                  }
    #if JVET_W0069_TMP_BOUNDARY
                  else
                  {
                    foundCandiNum = 1;
    
    #if JVET_AC0115_INTRA_TMP_DIMD_MTS_LFNST 
                    bsuccessfull = generateTmDcPrediction(piPred.buf, piPred.stride, pu.lwidth(), pu.lheight(), 1 << (cuCopy.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA) - 1), pu.cu);
    #else
    
                    bsuccessfull = generateTmDcPrediction(piPred.buf, piPred.stride, pu.lwidth(), pu.lheight(), 1 << (cuCopy.cs->sps->getBitDepth(CHANNEL_TYPE_LUMA) - 1));
    
                  }
    #endif
                  if (bsuccessfull && foundCandiNum >= 1)
                  {
    
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
    
                          Distortion sadCost = distParamSad.distFunc(distParamSad);
                          Distortion minSadHad = std::min(sadCost * 2, distParamHad.distFunc(distParamHad));
    
                          Distortion minSadHad =
                            std::min(distParamSad.distFunc(distParamSad) * 2, distParamHad.distFunc(distParamHad));
    
    #if JVET_AG0136_INTRA_TMP_LIC
                          m_CABACEstimator->getCtx() = SubCtx(Ctx::TmpLic, ctxStartTmpLicFlag);
                          m_CABACEstimator->getCtx() = SubCtx(Ctx::ItmpLicIndex, ctxStartTmpLicIdx);
    #endif
    
                          uint64_t fracModeBits = xFracModeBitsIntra(pu, 0, CHANNEL_TYPE_LUMA);
    
                          double cost = double(minSadHad) + double(fracModeBits) * sqrtLambdaForFirstPass;
    
    #if JVET_AH0200_INTRA_TMP_BV_REORDER
                          isTmpModeTestd = true;
                          if(!tmpFusionFlag && !tmpFlmFlag)
                          {
                            if(tmpBestSatdCost > cost)
                            {
                              tmpBestSatdCost = cost;
                            }
                          }
    #endif
    
    
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
    
    #if JVET_AH0200_INTRA_TMP_BV_REORDER
                          if(tmpFlmFlag || tmpFusionFlag                   
                            || (cu.lwidth() * cu.lheight() > TMP_SKIP_REFINE_THRESHOLD))
                          {
    #endif
                            m_bestIntraSADCost = std::min(m_bestIntraSADCost, cost - double(minSadHad) + (double)sadCost);
    #if JVET_AH0200_INTRA_TMP_BV_REORDER
                          }
    #endif
    
                          DTRACE(g_trace_ctx, D_INTRA_COST, "IntraTPM: %u, %llu, %f (%d)\n", minSadHad, fracModeBits, cost, 0);
    #if JVET_AD0086_ENHANCED_INTRA_TMP
    
    #if JVET_AG0136_INTRA_TMP_LIC
    
    #if JVET_AH0200_INTRA_TMP_BV_REORDER
                          if(tmpFlmFlag || tmpFusionFlag || (cu.lwidth() * cu.lheight() > TMP_SKIP_REFINE_THRESHOLD))
                          {
                            updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx, cu.tmpFracIdx), cost, uiRdModeList, candCostList, numModesForFullRD);
    
                            updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx, cu.tmpFracIdx), 0.8 * double(minSadHad), uiHadModeList, candHadList, numHadCand);
    
                          }
                          else if (cu.tmpLicFlag)
                          {
                            backupLicMinSadHad[cu.tmpIdx][cu.ibcLicIdx] = minSadHad;
                            backupLicSadCost[cu.tmpIdx][cu.ibcLicIdx] = sadCost;
                            updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx, cu.tmpFracIdx), cost, uiRdModeListLicFracTmp, candCostListLicFracTmp, numModesForLicFracIntraTmp);
                          }
                          else
                          {
                            backupMinSadHad[cu.tmpIdx] = minSadHad;
                            backupSadCost[cu.tmpIdx] = sadCost;
                            updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx, cu.tmpFracIdx), cost, uiRdModeListFracTmp, candCostListFracTmp, numModesForFracIntraTmp);
                          }
    #else
    
                          updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx), cost, uiRdModeList, candCostList, numModesForFullRD);
    
                          updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx), 0.8 * double(minSadHad), uiHadModeList, candHadList, numHadCand);
    
                          updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpIsSubPel, cu.tmpSubPelIdx), cost, uiRdModeList, candCostList, numModesForFullRD);
    
                          updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpIsSubPel, cu.tmpSubPelIdx), 0.8 * double(minSadHad), uiHadModeList, candHadList, numHadCand);
    
                          updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1), cost, uiRdModeList, candCostList, numModesForFullRD);
    
                          updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1), 0.8 * double(minSadHad), uiHadModeList, CandHadList, numHadCand);
    #endif
    #if JVET_AD0086_ENHANCED_INTRA_TMP
                        //record the best full-pel candidates
    
    #if JVET_AH0200_INTRA_TMP_BV_REORDER
                        if (!tmpFlmFlag && !tmpFusionFlag && tmpLicFlag)
                        {
                          for(int idxInList=0; idxInList < uiRdModeListLicFracTmp.size(); idxInList++)
                          {
                            if(cu.lwidth() * cu.lheight() > TMP_SKIP_REFINE_THRESHOLD)
                            {
                              break;
                            }
                            if(uiRdModeListLicFracTmp[idxInList].tmpFlag)
                            {
                              updateCandList(uiRdModeListLicFracTmp[idxInList], candCostListLicFracTmp[idxInList], uiRdModeListTmpLic, candCostListTmpLic, numModesForLicFracIntraTmp);
                            }
                            if(idxInList >= numModesForFullRD && uiRdModeListTmpLic.size() >= adjustedTmpLicBvNum)
                            {
                              break;
                            }
    
    #if JVET_AI0136_ADAPTIVE_DUAL_TREE
                            if(idxInList >= (numModesForFullRD-1) && relatedCU && relatedCU->skipFracTmp)
    #else
    
                            if(idxInList >= (numModesForFullRD-1) && relatedCU.skipFracTmp)
    
    #if JVET_AG0136_INTRA_TMP_LIC
                        if (!tmpFlmFlag && !tmpFusionFlag && !tmpLicFlag)
    #else
    
                        if(!tmpFlmFlag&&!tmpFusionFlag)
    
    #if JVET_AH0200_INTRA_TMP_BV_REORDER			  
                          for(int idxInList=0; idxInList < uiRdModeListFracTmp.size(); idxInList++)
                          {
                            if(cu.lwidth() * cu.lheight() > TMP_SKIP_REFINE_THRESHOLD)
                            {
                              break;
                            }
                            if(uiRdModeListFracTmp[idxInList].tmpFlag)
                            {
                              updateCandList(uiRdModeListFracTmp[idxInList], candCostListFracTmp[idxInList], uiRdModeListTmp, candCostListTmp, numModesForFracIntraTmp);
                            }
                            if(idxInList >= numModesForFullRD && uiRdModeListTmp.size() >= adjustedTMPNonLicBvNum)
                            {
                              break;
                            }
    
    #if JVET_AI0136_ADAPTIVE_DUAL_TREE
                            if(idxInList >= (numModesForFullRD-1) && relatedCU && relatedCU->skipFracTmp)
    #else
    
                            if(idxInList >= (numModesForFullRD-1) && relatedCU.skipFracTmp)
    
                          for(int idxInList=0; idxInList < uiRdModeList.size(); idxInList++)
                          {
                            if(uiRdModeList[idxInList].tmpFlag){
    
                              updateCandList(uiRdModeList[idxInList], candCostList[idxInList], uiRdModeListTmp, candCostListTmp, numModesForFullRD);
    
    #if JVET_AG0136_INTRA_TMP_LIC
                        }
                        }
    #endif
    
                      }
                    }
                    //fractional BV
                    cu.tmpFusionFlag = false;
                    cu.tmpFlmFlag = false;
    
    #if JVET_AG0136_INTRA_TMP_LIC
                    cu.tmpLicFlag = false;
                    cu.ibcLicIdx = 0;
    #endif
    
                    for(int idxInList=0; idxInList < uiRdModeListTmp.size(); idxInList++)
                    {
                      cu.tmpIdx = uiRdModeListTmp[idxInList].tmpIdx;
                      xPadForInterpolation(&cu);
                      for(int tmpIsSubPel = 1; tmpIsSubPel < 4; tmpIsSubPel++)
                      {
                        for (int idx = 0; idx < TMP_MAX_SUBPEL_DIR; idx++)
                        {
                          cu.tmpIsSubPel = tmpIsSubPel;
                          cu.tmpSubPelIdx = idx;
                          int placeHolder;
    
                          generateTMPrediction(piPred.buf, piPred.stride, placeHolder, pu
    #if JVET_AG0136_INTRA_TMP_LIC
                                               , cu.tmpLicFlag
    #endif
                                               , false);
    
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS&&JVET_AE0169_BIPREDICTIVE_IBC
                          Distortion sadCost = distParamSad.distFunc(distParamSad);
                          Distortion minSadHad = std::min(sadCost * 2, distParamHad.distFunc(distParamHad));
    #else
    
                          Distortion minSadHad =
                              std::min(distParamSad.distFunc(distParamSad) * 2, distParamHad.distFunc(distParamHad));
    
                          uint64_t fracModeBits = xFracModeBitsIntra(pu, 0, CHANNEL_TYPE_LUMA);
    
                          double cost = double(minSadHad) + double(fracModeBits) * sqrtLambdaForFirstPass;
    
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS&&JVET_AE0169_BIPREDICTIVE_IBC
                          m_bestIntraSADCost = std::min(m_bestIntraSADCost, cost - double(minSadHad) + (double)sadCost);
    #endif
    
                          DTRACE(g_trace_ctx, D_INTRA_COST, "IntraTPM: %u, %llu, %f (%d)\n", minSadHad, fracModeBits, cost, 0);
    
    #if JVET_AG0136_INTRA_TMP_LIC
                          updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx), cost, uiRdModeList, candCostList, numModesForFullRD);
    
                          updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx), 0.8 * double(minSadHad), uiHadModeList, candHadList, numHadCand);
    
                          updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpIsSubPel, cu.tmpSubPelIdx), cost, uiRdModeList, candCostList, numModesForFullRD);
    
                          updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpIsSubPel, cu.tmpSubPelIdx), 0.8 * double(minSadHad), uiHadModeList, candHadList, numHadCand);
    
    #endif
    
    #if JVET_AH0200_INTRA_TMP_BV_REORDER
                    for(int idxInList=0; idxInList < uiRdModeListTmp.size(); idxInList++)
                    {
                      cu.tmpIdx = uiRdModeListTmp[idxInList].tmpIdx;
                      cu.tmpLicFlag = uiRdModeListTmp[idxInList].tmpLicFlag;
                      CHECK(cu.tmpLicFlag, "cu.tmpLicFlag == 1");
                      cu.ibcLicFlag = cu.tmpLicFlag;
                      cu.ibcLicIdx = uiRdModeListTmp[idxInList].tmpLicIdc;
    
    #if JVET_AI0129_INTRA_TMP_OVERLAPPING_REFINEMENT
                      searchFracCandidate(&cu, getTargetPatch(), templateType);
    #else
    
                      searchFracCandidate(&cu, getTargetPatch(floorLog2(std::max(cu.lwidth(), cu.lheight())) - 2), templateType);
    
                      for (int spIdx = 0; spIdx < std::min(2, (int) m_mtmpFracCandList[cu.tmpIdx].size()); spIdx++)
                      {
                        cu.tmpIsSubPel = m_mtmpFracCandList[cu.tmpIdx][spIdx].m_subpel;
                        cu.tmpSubPelIdx = m_mtmpFracCandList[cu.tmpIdx][spIdx].m_fracDir;
                        CHECK(cu.tmpIsSubPel < 0 || cu.tmpIsSubPel > 2, "cu.tmpIsSubPel < 1 || cu.tmpIsSubPel > 2");
                        cu.tmpFracIdx = spIdx;
    
                        Distortion sadCost;
                        Distortion minSadHad;
                        uint64_t fracModeBits = 0;
                        double cost;
                        if(cu.tmpIsSubPel)
                        {
                          int placeHolder;
                          generateTMPrediction(piPred.buf, piPred.stride, placeHolder, pu, cu.tmpLicFlag, false);
      #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS&&JVET_AE0169_BIPREDICTIVE_IBC
                          sadCost = distParamSad.distFunc(distParamSad);
                          minSadHad = std::min(sadCost * 2, distParamHad.distFunc(distParamHad));
      #else
                          minSadHad =
                              std::min(distParamSad.distFunc(distParamSad) * 2, distParamHad.distFunc(distParamHad));
      #endif
                        }
                        else
                        {
                          sadCost = backupSadCost[cu.tmpIdx];
                          minSadHad = backupMinSadHad[cu.tmpIdx];
                        }
                        if(!cu.tmpIsSubPel && !cu.tmpFracIdx)
                        {
                          cost = candCostListTmp[idxInList];
                        }
                        else
                        {
                          loadStartStates();
    
                          fracModeBits = xFracModeBitsIntra(pu, 0, CHANNEL_TYPE_LUMA);
                          cost = double(minSadHad) + double(fracModeBits) * sqrtLambdaForFirstPass;
                        }
    
                        if(tmpBestSatdCost > cost)
                        {
                          tmpBestSatdCost = cost;
                        }
    
      #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS&&JVET_AE0169_BIPREDICTIVE_IBC
                        m_bestIntraSADCost = std::min(m_bestIntraSADCost, cost - double(minSadHad) + (double)sadCost);
      #endif
                        DTRACE(g_trace_ctx, D_INTRA_COST, "IntraTPM: %u, %llu, %f (%d)\n", minSadHad, fracModeBits, cost, 0);
      #if JVET_AG0136_INTRA_TMP_LIC
                        updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx, cu.tmpFracIdx), cost, uiRdModeList, candCostList, numModesForFullRD);
    
                        updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx, cu.tmpFracIdx), 0.8 * double(minSadHad), uiHadModeList, candHadList, numHadCand);
    
      #else
                        updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpIsSubPel, cu.tmpSubPelIdx, cu.tmpFracIdx), cost, uiRdModeList, candCostList, numModesForFullRD);
    
                        updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpIsSubPel, cu.tmpSubPelIdx, cu.tmpFracIdx), 0.8 * double(minSadHad), uiHadModeList, candHadList, numHadCand);
    
      #endif
                      }
                    }
    
                    for(int idxInList=0; idxInList < uiRdModeListTmpLic.size(); idxInList++)
                    {
                      cu.tmpIdx = uiRdModeListTmpLic[idxInList].tmpIdx;
                      cu.tmpLicFlag = uiRdModeListTmpLic[idxInList].tmpLicFlag;
                      CHECK(!cu.tmpLicFlag, "cu.tmpLicFlag != 0");
                      cu.ibcLicFlag = cu.tmpLicFlag;
                      cu.ibcLicIdx = uiRdModeListTmpLic[idxInList].tmpLicIdc;
    
    #if JVET_AI0129_INTRA_TMP_OVERLAPPING_REFINEMENT
                      searchFracCandidate(&cu, getTargetPatch(), templateType);
    #else
    
                      searchFracCandidate(&cu, getTargetPatch(floorLog2(std::max(cu.lwidth(), cu.lheight())) - 2), templateType);
    
                      for (int spIdx = 0; spIdx < std::min(2, (int) m_mtmpFracCandList[cu.tmpIdx].size()); spIdx++)
                      {
                        cu.tmpIsSubPel = m_mtmpFracCandList[cu.tmpIdx][spIdx].m_subpel;
                        cu.tmpSubPelIdx = m_mtmpFracCandList[cu.tmpIdx][spIdx].m_fracDir;
                        CHECK(cu.tmpIsSubPel < 0 || cu.tmpIsSubPel > 2, "cu.tmpIsSubPel < 1 || cu.tmpIsSubPel > 2");
                        cu.tmpFracIdx = spIdx;
    
                        Distortion sadCost;
                        Distortion minSadHad;
                        uint64_t fracModeBits = 0;
                        double cost;
                        if(cu.tmpIsSubPel)
                        {
                          int placeHolder;
                          generateTMPrediction(piPred.buf, piPred.stride, placeHolder, pu, cu.tmpLicFlag, false);
    
                          if (cu.tmpLicFlag)
                          {
                            PelBuf bufDumb;
                            pcInterPred->LicItmp(pu, bufDumb, false);
                            const auto& arrayLicParams = pcInterPred->getArrayLicParams();
                            if (cu.ibcLicIdx == IBC_LIC_IDX_M)
                            {
                              piPred.linearTransforms(arrayLicParams[1], arrayLicParams[0], arrayLicParams[2], arrayLicParams[4], arrayLicParams[3], arrayLicParams[5], arrayLicParams[6], true, cu.cs->slice->clpRng(COMPONENT_Y));
                            }
                            else
                            {
                              piPred.linearTransform(arrayLicParams[1], arrayLicParams[0], arrayLicParams[2], true, cu.cs->slice->clpRng(COMPONENT_Y));
                            }
                          }
    
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS&&JVET_AE0169_BIPREDICTIVE_IBC
                          sadCost = distParamSad.distFunc(distParamSad);
                          minSadHad = std::min(sadCost * 2, distParamHad.distFunc(distParamHad));
    #else
                          minSadHad =
                              std::min(distParamSad.distFunc(distParamSad) * 2, distParamHad.distFunc(distParamHad));
    #endif
                        }
                        else
                        {
                          sadCost = backupLicSadCost[cu.tmpIdx][cu.ibcLicIdx];
                          minSadHad = backupLicMinSadHad[cu.tmpIdx][cu.ibcLicIdx];                  
                        }
                        if(!cu.tmpIsSubPel && !cu.tmpFracIdx)
                        {
                          cost = candCostListTmpLic[idxInList];
                        }
                        else
                        {
                          loadStartStates();
    
                          fracModeBits = xFracModeBitsIntra(pu, 0, CHANNEL_TYPE_LUMA);
                          cost = double(minSadHad) + double(fracModeBits) * sqrtLambdaForFirstPass;
                        }
                        if(tmpBestSatdCost > cost)
                        {
                          tmpBestSatdCost = cost;
                        }
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS&&JVET_AE0169_BIPREDICTIVE_IBC
                        m_bestIntraSADCost = std::min(m_bestIntraSADCost, cost - double(minSadHad) + (double)sadCost);
    #endif
                        DTRACE(g_trace_ctx, D_INTRA_COST, "IntraTPM: %u, %llu, %f (%d)\n", minSadHad, fracModeBits, cost, 0);
                        updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx, cu.tmpFracIdx), cost, uiRdModeList, candCostList, numModesForFullRD);
    
                        updateCandList(ModeInfo(0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1, cu.tmpIdx, cu.tmpFusionFlag, cu.tmpFlmFlag, cu.tmpLicFlag, cu.ibcLicIdx, cu.tmpIsSubPel, cu.tmpSubPelIdx, cu.tmpFracIdx), 0.8 * double(minSadHad), uiHadModeList, candHadList, numHadCand);
    
    #if JVET_AD0086_ENHANCED_INTRA_TMP
                  cu.tmpFlag       = 0;
                  cu.tmpFusionFlag = false;
                  cu.tmpFlmFlag    = false;
    
    #if JVET_AG0136_INTRA_TMP_LIC
                  cu.tmpLicFlag    = false;
                  cu.ibcLicFlag    = false;
                  cu.ibcLicIdx     = 0;
    #endif
    
    #if JVET_AG0136_INTRA_TMP_LIC
                  cu.tmpSubPelIdx  = -1;
    #else
    
    #if JVET_AH0200_INTRA_TMP_BV_REORDER
                  cu.tmpFracIdx    = -1;
    #endif
    
                if (LFNSTSaveFlag && testMip
                    && !allowLfnstWithMip(cu.firstPU->lumaSize()))   // save a different set for the next run
                {
                  // save found best modes
                  m_uiSavedRdModeListLFNST = uiRdModeList;
    
                  m_dSavedModeCostLFNST    = candCostList;
    
                  // PBINTRA fast
                  m_uiSavedHadModeListLFNST = uiHadModeList;
    
                  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;
                }
    
    #if JVET_V0130_INTRA_TMP && !JVET_AB0130_ITMP_SAMPLING
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                // derive TPM candidate using hadamard
                if( testTpm )
                {
                  cu.tmpFlag = true;
                  cu.mipFlag = false;
                  pu.multiRefIdx = 0;
    
    #if JVET_AB0157_TMRL
                  cu.tmrlFlag = false;
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                  int foundCandiNum = 0;
                  bool bsuccessfull = 0;
                  CodingUnit cu_cpy = cu;
    
    
    #if JVET_W0069_TMP_BOUNDARY
    
                  RefTemplateType templateType = getRefTemplateType( cu_cpy, cu_cpy.blocks[COMPONENT_Y] );
                  if( templateType != NO_TEMPLATE )
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                  if( isRefTemplateAvailable( cu_cpy, cu_cpy.blocks[COMPONENT_Y] ) )
    
    #endif
    
    #if JVET_W0069_TMP_BOUNDARY
    
                    getTargetTemplate( &cu_cpy, pu.lwidth(), pu.lheight(), templateType );
                    candidateSearchIntra( &cu_cpy, pu.lwidth(), pu.lheight(), templateType );
                    bsuccessfull = generateTMPrediction( piPred.buf, piPred.stride, pu.lwidth(), pu.lheight(), foundCandiNum );
    
                    getTargetTemplate( &cu_cpy, pu.lwidth(), pu.lheight() );
                    candidateSearchIntra( &cu_cpy, pu.lwidth(), pu.lheight() );
                    bsuccessfull = generateTMPrediction( piPred.buf, piPred.stride, pu.lwidth(), pu.lheight(), foundCandiNum );
    
    #endif
    
    #if JVET_W0069_TMP_BOUNDARY
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                  else
                  {
                    foundCandiNum = 1;
    
                    bsuccessfull = generateTmDcPrediction( piPred.buf, piPred.stride, pu.lwidth(), pu.lheight(), 1 << (cu_cpy.cs->sps->getBitDepth( CHANNEL_TYPE_LUMA ) - 1) );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                  }
    
    #endif
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                  if( bsuccessfull && foundCandiNum >= 1 )
                  {
    
                    Distortion minSadHad =
                      std::min( distParamSad.distFunc( distParamSad ) * 2, distParamHad.distFunc( distParamHad ) );
    
    
    Vadim Seregin's avatar
    Vadim Seregin committed
                    uint64_t fracModeBits = xFracModeBitsIntra( pu, 0, CHANNEL_TYPE_LUMA );
    
                    double cost = double( minSadHad ) + double( fracModeBits ) * sqrtLambdaForFirstPass;
                    DTRACE( g_trace_ctx, D_INTRA_COST, "IntraTPM: %u, %llu, %f (%d)\n", minSadHad, fracModeBits, cost, 0 );
    
    
                    updateCandList( ModeInfo( 0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1 ), cost, uiRdModeList, candCostList, numModesForFullRD );
    
                    updateCandList( ModeInfo( 0, 0, 0, NOT_INTRA_SUBPARTITIONS, 0, 1 ), 0.8 * double( minSadHad ), uiHadModeList, candHadList, numHadCand );
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
                //*** Derive MIP candidates using Hadamard
                if (testMip && !supportedMipBlkSize)
                {
                  // avoid estimation for unsupported blk sizes
                  const int transpOff    = getNumModesMip(pu.Y());
                  const int numModesFull = (transpOff << 1);
                  for (uint32_t uiModeFull = 0; uiModeFull < numModesFull; uiModeFull++)
                  {
                    const bool     isTransposed = (uiModeFull >= transpOff ? true : false);
                    const uint32_t uiMode       = (isTransposed ? uiModeFull - transpOff : uiModeFull);
    
                    numModesForFullRD++;
                    uiRdModeList.push_back(ModeInfo(true, isTransposed, 0, NOT_INTRA_SUBPARTITIONS, uiMode));
    
                    candCostList.push_back(0);
    
                  }
                }
                else if (testMip)
                {
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #if JVET_V0130_INTRA_TMP
                  cu.tmpFlag = 0;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    #endif
    
                  cu.mipFlag     = true;
                  pu.multiRefIdx = 0;
    
    #if JVET_AB0157_TMRL
                  cu.tmrlFlag = false;
    #endif
    
                  double mipHadCost[MAX_NUM_MIP_MODE] = { MAX_DOUBLE };
    
    #if JVET_AB0157_INTRA_FUSION && JVET_AB0155_SGPM
    
    #if JVET_AJ0249_NEURAL_NETWORK_BASED
                  initIntraPatternChType(cu, pu.Y(), false, 0, false, false, true);
    #else
    
                  initIntraPatternChType(cu, pu.Y(), false, 0, false);
    
    #elif JVET_AB0157_INTRA_FUSION
                  initIntraPatternChType(cu, pu.Y(), false, false);
    #else
    
                  initIntraPatternChType(cu, pu.Y());
    
                  initIntraMip(pu, pu.Y());
    
                  const int transpOff    = getNumModesMip(pu.Y());
                  const int numModesFull = (transpOff << 1);
                  for (uint32_t uiModeFull = 0; uiModeFull < numModesFull; uiModeFull++)
                  {
                    const bool     isTransposed = (uiModeFull >= transpOff ? true : false);
                    const uint32_t uiMode       = (isTransposed ? uiModeFull - transpOff : uiModeFull);
    
                    pu.mipTransposedFlag           = isTransposed;
                    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
    
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
                    Distortion sadCost = distParamSad.distFunc(distParamSad);
                    Distortion minSadHad = std::min(sadCost * 2, distParamHad.distFunc(distParamHad));
    #else
    
                    Distortion minSadHad =
                      std::min(distParamSad.distFunc(distParamSad) * 2, distParamHad.distFunc(distParamHad));
    
                    uint64_t fracModeBits = xFracModeBitsIntra(pu, uiMode, CHANNEL_TYPE_LUMA);
    
                    double cost            = double(minSadHad) + double(fracModeBits) * sqrtLambdaForFirstPass;
    
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
                    m_bestIntraSADCost = std::min(m_bestIntraSADCost, cost - double(minSadHad) + (double)sadCost);
    #endif
    
                    mipHadCost[uiModeFull] = cost;
                    DTRACE(g_trace_ctx, D_INTRA_COST, "IntraMIP: %u, %llu, %f (%d)\n", minSadHad, fracModeBits, cost,
                           uiModeFull);
    
                    updateCandList(ModeInfo(true, isTransposed, 0, NOT_INTRA_SUBPARTITIONS, uiMode), cost, uiRdModeList,
    
                                   candCostList, numModesForFullRD + 1);
    
                    updateCandList(ModeInfo(true, isTransposed, 0, NOT_INTRA_SUBPARTITIONS, uiMode),
    
                                   0.8 * double(minSadHad), uiHadModeList, candHadList, numHadCand);
    
    #if !JVET_AJ0061_TIMD_MERGE
    
                  const double thresholdHadCost = 1.0 + 1.4 / sqrt((double) (pu.lwidth() * pu.lheight()));
    
                  reduceHadCandList(uiRdModeList, candCostList, numModesForFullRD, thresholdHadCost, mipHadCost, pu,
    
                                    fastMip
    #if JVET_AB0157_TMRL
                    , tmrlCostList
    
    #endif
    #if JVET_AC0105_DIRECTIONAL_PLANAR
                    , dirPlanarCostList
    
    #else
                  std::memcpy(mipHadCostStore, mipHadCost, MAX_NUM_MIP_MODE * sizeof(double));
    #endif
    
    #if JVET_AH0076_OBIC
                if (obicSaveFlag || dimdSaveFlag)
                {
                  cu.dimd = false;
                  cu.timd = false;
                  cu.mipFlag = false;
                  pu.multiRefIdx = 0;
    #if JVET_V0130_INTRA_TMP
                  cu.tmpFlag = false;
    #endif
                  cu.sgpm = false;
    #if JVET_AB0157_INTRA_FUSION
                  initIntraPatternChType(cu, pu.Y(), true, 0, false);
    #else
                  initIntraPatternChType(cu, pu.Y(), true);
    #endif
                  if (obicSaveFlag)
                  {
                    for (int idx = 0; idx < OBIC_FUSION_NUM; idx++)
                    {
                      int iMode = cu.obicMode[idx];
                      if (iMode < 0)
                      {
                        continue;
                      }
                      if (dimdNeededMode[iMode] && !m_intraModeReady[iMode])
                      {
                        pu.intraDir[0] = iMode;
                        initPredIntraParams(pu, pu.Y(), sps);
    #if JVET_AB0157_INTRA_FUSION
    
    #if JVET_AK0118_BF_FOR_INTRA_PRED
                        predIntraAng( COMPONENT_Y, piPred, pu, true, false, false );
    #else
    
                        predIntraAng( COMPONENT_Y, piPred, pu, false, false );
    
                        predIntraAng(COMPONENT_Y, piPred, pu, false);
    
    #else
                        predIntraAng(COMPONENT_Y, piPred, pu);
    #endif
                        PelBuf predBuf(m_intraPredBuf[iMode], tmpArea);
                        predBuf.copyFrom(piPred);
                        m_intraModeReady[iMode] = 1;
                      }
                    }
                  }
                  if (dimdSaveFlag)
                  {
                    if (dimdNeededMode[PLANAR_IDX] && !m_intraModeReady[PLANAR_IDX])
                    {
                      pu.intraDir[0] = PLANAR_IDX;
                      initPredIntraParams(pu, pu.Y(), sps);
    #if JVET_AB0157_INTRA_FUSION
    
    #if JVET_AK0118_BF_FOR_INTRA_PRED
                      predIntraAng( COMPONENT_Y, piPred, pu, true, false, false );
    #else
    
                      predIntraAng( COMPONENT_Y, piPred, pu, false, false );
    
                      predIntraAng(COMPONENT_Y, piPred, pu, false);
    
    #else
                      predIntraAng(COMPONENT_Y, piPred, pu);
    #endif
                      PelBuf predBuf(m_intraPredBuf[PLANAR_IDX], tmpArea);
                      predBuf.copyFrom(piPred);
                      m_intraModeReady[PLANAR_IDX] = 1;
                    }
                  }
                  for (int dimdIdx = 0; dimdIdx < DIMD_FUSION_NUM - 1; dimdIdx++)
                  {
    
                    int dimdMode = (dimdIdx == 0 ? cu.dimdMode : cu.dimdBlendMode[dimdIdx-1]);
    
    #if JVET_AH0209_PDP
                    if (dimdNeededMode[dimdMode] && !m_intraModeReady[dimdMode] && !m_pdpIntraPredReady[dimdMode])
    #else
    
                    if (dimdNeededMode[dimdMode] && !m_intraModeReady[dimdMode])
    
                    {
                      pu.intraDir[0] = dimdMode;
                      initPredIntraParams(pu, pu.Y(), sps);
    #if JVET_AB0157_INTRA_FUSION
    
    #if JVET_AK0118_BF_FOR_INTRA_PRED
                      predIntraAng( COMPONENT_Y, piPred, pu, true, false, false );
    #else
    
                      predIntraAng( COMPONENT_Y, piPred, pu, false, false );
    
                      predIntraAng(COMPONENT_Y, piPred, pu, false);
    
    #else
                      predIntraAng(COMPONENT_Y, piPred, pu);
    #endif
                      PelBuf predBuf(m_intraPredBuf[dimdMode], tmpArea);
                      predBuf.copyFrom(piPred);
                      m_intraModeReady[dimdMode] = 1;
                    }
                  }
                }
    
    #endif
    #if JVET_AJ0061_TIMD_MERGE
                m_skipDimdMode = !testDimd;
                m_skipObicMode = !testObic;
                m_skipDimdLfnstMtsPass = !testDimd;
                m_skipObicLfnstMtsPass = !testObic;
                m_skipTimdMode[Timd]      = !testTimd;
                m_skipTimdMode[TimdMrg]   = !testTimdMerge;
                m_skipTimdMode[TimdMrl1]  = !testTimdMrl;
                m_skipTimdMode[TimdMrl3]  = !testTimdMrl;
                m_skipTimdLfnstMtsPass    = !testTimd;
                m_skipTimdMrgLfnstMtsPass = !testTimdMerge;
    #if JVET_AH0076_OBIC
                if (obicSaveFlag || dimdSaveFlag)
                {
                  cu.dimd = true;
                  cu.obicFlag = false;
                  cu.timd = false;
                  cu.mipFlag = false;
                  cu.tmpFlag = false;
                  cu.tmrlFlag = false;
                  cu.firstPU->multiRefIdx = 0;
                  cu.ispMode = NOT_INTRA_SUBPARTITIONS;
                  int iWidth = cu.lwidth();
                  int iHeight = cu.lheight();
                  if (obicSaveFlag)
                  {
                    cu.obicFlag = true;
                    int obicMode = cu.obicMode[0];
                    pu.intraDir[CHANNEL_TYPE_LUMA] = obicMode;
                    bool blendModes[OBIC_FUSION_NUM - 1] = {false};
                    PelBuf predFusion[OBIC_FUSION_NUM - 1];
    #if JVET_AH0209_PDP
    
                    CHECK(!m_intraModeReady[obicMode] && !m_pdpIntraPredReady[obicMode], "OBIC mode is not ready!");
    
    #else
                    CHECK(!m_intraModeReady[obicMode], "OBIC mode is not ready!");
    #endif
    
                    const UnitArea localUnitArea( pu.chromaFormat, Area( 0, 0, iWidth, iHeight ) );
    
    #if JVET_AH0209_PDP
                    PelBuf predBuf(m_pdpIntraPredReady[obicMode]? m_pdpIntraPredBuf[obicMode]: m_intraPredBuf[obicMode], pu.Y());
    #else
    
                    PelBuf predBuf(m_intraPredBuf[obicMode], pu.Y());
    
    #endif
                    piPred.copyFrom(predBuf);
                    int planarIdx = 0;
                    for (int idx = 0; idx < OBIC_FUSION_NUM - 1; idx++)
                    {
                      blendModes[idx] = false;
                      predFusion[idx] = m_tempBuffer[idx].getBuf( localUnitArea.Y() );
                      int iMode = cu.obicMode[idx + 1];
                      if (iMode >= 0)
                      {
                        blendModes[idx] = true;