Skip to content
Snippets Groups Projects
IntraSearch.cpp 442 KiB
Newer Older
  • Learn to ignore specific revisions
  • #if JVET_Z0050_CCLM_SLOPE
    #if MMLM
          for (int32_t uiMode = 0; uiMode < 2; uiMode++)
          {
            int chromaIntraMode = uiMode ? MMLM_CHROMA_IDX : LM_CHROMA_IDX;
    #else
          for (int32_t uiMode = 0; uiMode < 1; uiMode++)
          {
            int chromaIntraMode = LM_CHROMA_IDX;
    #endif
    
            if ( PU::isLMCModeEnabled( pu, chromaIntraMode ) && PU::hasCclmDeltaFlag( pu, chromaIntraMode ) )
            {
              if ( satdCclmOffsetsBest[chromaIntraMode - LM_CHROMA_IDX].isActive() )
              {
                pu.intraDir[1] = chromaIntraMode;
                pu.cclmOffsets = satdCclmOffsetsBest[chromaIntraMode - LM_CHROMA_IDX];
    #if JVET_Z0050_DIMD_CHROMA_FUSION
    
    #if JVET_AC0119_LM_CHROMA_FUSION
                pu.isChromaFusion = 0;
    #else
    
                pu.isChromaFusion = false;
    
    #endif
    
                // RD search replicated from above
                cs.setDecomp( pu.Cb(), false );
                cs.dist = baseDist;
                //----- restore context models -----
                m_CABACEstimator->getCtx() = ctxStart;
    
    
                xRecurIntraChromaCodingQT( cs, partitioner, bestCostSoFar, ispType 
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS && (JVET_AB0143_CCCM_TS || JVET_AC0119_LM_CHROMA_FUSION)
                                         , UnitBuf<Pel>()
    #endif
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
                                         , pcInterPred
    #endif
                );
    
                if( lumaUsesISP && cs.dist == MAX_UINT )
                {
                  continue;
                }
    
                if (cs.sps->getTransformSkipEnabledFlag())
                {
                  m_CABACEstimator->getCtx() = ctxStart;
                }
    
                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 JVET_AG0154_DECODER_DERIVED_CCP_FUSION
                  if (uiDist < bestDist)
                  {
                    bestDist = uiDist;
                  }
    #endif
    
                  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 ) );
    #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;
                  bestCclmOffsets = pu.cclmOffsets;
    #if JVET_Z0050_DIMD_CHROMA_FUSION
                  isChromaFusion  = pu.isChromaFusion;
    
    Che-Wei Kuo's avatar
    Che-Wei Kuo committed
    #endif
    #if JVET_AA0126_GLM
                  bestGlmIdc      = pu.glmIdc;
    
    #endif
                }
              }
            }
          }
          
          pu.cclmOffsets.setAllZero();
    
    Jani Lainema's avatar
    Jani Lainema committed
    #if JVET_AA0057_CCCM
    
    #if JVET_AB0143_CCCM_TS
          int chromaIntraModeInCCCM = LM_CHROMA_IDX;
    
    #if JVET_AC0147_CCCM_NO_SUBSAMPLING
          bool isCCCMEnabled = isCccmFullEnabled;
    #else
    
          isCCCMEnabled = isCccmFullEnabled;
    
          pu.cccmFlag = 1;
    
    Vadim Seregin's avatar
    Vadim Seregin committed
    
          for (int32_t uiMode = 0; uiMode < CCCM_NUM_MODES; uiMode++)
    
          {
            if (uiMode == 1)
            {
              chromaIntraModeInCCCM = MDLM_L_IDX;
              isCCCMEnabled = isCccmLeftEnabled;
              pu.cccmFlag = 2;
            }
            else if (uiMode == 2)
            {
              chromaIntraModeInCCCM = MDLM_T_IDX;
              isCCCMEnabled = isCccmTopEnabled;
              pu.cccmFlag = 3;
            }
    #if MMLM
            else if (uiMode == 3)
            {
              chromaIntraModeInCCCM = MMLM_CHROMA_IDX;
              isCCCMEnabled = isMultiCccmFullEnabled;
              pu.cccmFlag = 1;
            }
            else if (uiMode == 4)
            {
              chromaIntraModeInCCCM = MMLM_L_IDX;
              isCCCMEnabled = isMultiCccmLeftEnabled;
              pu.cccmFlag = 2;
            }
            else if (uiMode == 5)
            {
              chromaIntraModeInCCCM = MMLM_T_IDX;
              isCCCMEnabled = isMultiCccmTopEnabled;
              pu.cccmFlag = 3;
            }
    #endif
    
              
    #if JVET_AC0054_GLCCCM
            pu.glCccmFlag = 0;
            if (uiMode >= CCCM_NUM_MODES / 2)
            {
              pu.glCccmFlag = 1;
    #if MMLM
              chromaIntraModeInCCCM = uiMode == 6 ? LM_CHROMA_IDX
              : uiMode == 7 ? MDLM_L_IDX
              : uiMode == 8 ? MDLM_T_IDX
              : uiMode == 9 ? MMLM_CHROMA_IDX
              : uiMode == 10 ? MMLM_L_IDX : MMLM_T_IDX;
              isCCCMEnabled = uiMode == 6 ? isCccmFullEnabled
              : uiMode == 7 ? isCccmLeftEnabled
              : uiMode == 8 ? isCccmTopEnabled
              : uiMode == 9 ? isMultiCccmFullEnabled
              : uiMode == 10 ? isMultiCccmLeftEnabled : isMultiCccmTopEnabled;
              pu.cccmFlag =   uiMode == 6 ? 1
              : uiMode == 7 ? 2
              : uiMode == 8 ? 3
              : uiMode == 9 ? 1
              : uiMode == 10 ? 2 : 3;
    #else
              chromaIntraModeInCCCM = uiMode == 3 ? LM_CHROMA_IDX
              : uiMode == 4 ? MDLM_L_IDX : MDLM_T_IDX;
              isCCCMEnabled = uiMode == 3 ? isCccmFullEnabled
              : uiMode == 4 ? isCccmLeftEnabled : isCccmTopEnabled;
              pu.cccmFlag  =  uiMode == 3 ? 1
              : uiMode == 4 ? 2 : 3;
    #endif
              if (!isGlCccmModeEnabledInRdo[chromaIntraModeInCCCM])
              {
                continue;
              }
            }
    
    #endif // JVET_AC0054_GLCCCM
    
    #if JVET_AC0147_CCCM_NO_SUBSAMPLING
    
              if (!isCccmModeEnabledInRdo[0][chromaIntraModeInCCCM] && !isCccmModeEnabledInRdo[1][chromaIntraModeInCCCM])
    
              if (!isCccmModeEnabledInRdo[chromaIntraModeInCCCM])
    
            if (isCCCMEnabled)
            {
    #else
    
    Jani Lainema's avatar
    Jani Lainema committed
    #if MMLM
          for (int32_t uiMode = 0; uiMode < 2; uiMode++)
          {
            int chromaIntraMode = uiMode ? MMLM_CHROMA_IDX : LM_CHROMA_IDX;
    #else
          for (int32_t uiMode = 0; uiMode < 1; uiMode++)
          {
            int chromaIntraMode = LM_CHROMA_IDX;
    #endif
    
            if ( PU::cccmSingleModeAvail(pu, chromaIntraMode) || PU::cccmMultiModeAvail(pu, chromaIntraMode) )
            {
              pu.cccmFlag = 1;
    
    Jani Lainema's avatar
    Jani Lainema committed
    
    
    #if JVET_AC0147_CCCM_NO_SUBSAMPLING
              for (int sub = 0; sub < pu.cu->slice->getSPS()->getUseCccm(); sub++)
              {
    
    #if JVET_AD0202_CCCM_MDF
                for (int32_t filterIdx = 0; filterIdx < CCCM_NUM_PRED_FILTER; filterIdx++)
                {
                  if (filterIdx > 0 && (sub == 1 || uiMode > 5))
                  {
                    continue;
                  }
                  pu.cccmMultiFilterIdx = filterIdx;
    
                  pu.cccmNoSubFlag = sub;
    #if JVET_AC0054_GLCCCM
                  if (sub && ((uiMode >= CCCM_NUM_MODES / 2) || pu.glCccmFlag))
                  {
                    continue;
                  }
    
    #if JVET_AD0202_CCCM_MDF
                  else if (sub == 0 && uiMode < 6)
                  {
                    if (!isCccmWithMulDownSamplingEnabledInRdo[chromaIntraModeInCCCM][filterIdx])
                    {
                      continue;
                    }
                  }
                  else if (sub)
    #else
    
                  {
                    if (!isCccmModeEnabledInRdo[sub][chromaIntraModeInCCCM])
                    {
                      continue;
                    }
                  }
    #else // else of JVET_AC0054_GLCCCM
                  if (!isCccmModeEnabledInRdo[sub][chromaIntraModeInCCCM])
                  {
                    continue;
                  }
    #endif // end of JVET_AC0054_GLCCCM
    
    Jani Lainema's avatar
    Jani Lainema committed
              // Original RD check code replicated from above
              cs.setDecomp( pu.Cb(), false );
              cs.dist = baseDist;
              //----- restore context models -----
              m_CABACEstimator->getCtx() = ctxStart;
    
              //----- chroma coding -----
    
    #if JVET_AB0143_CCCM_TS
              pu.intraDir[1] = chromaIntraModeInCCCM;
    
    
    #if JVET_AC0147_CCCM_NO_SUBSAMPLING
    
    #if JVET_AD0202_CCCM_MDF
              const int cccmBufferIdx = filterIdx * CCCM_NUM_MODES + uiMode;
    
              if (pu.cs->slice->isIntra())
    
              {
    #if JVET_AD0202_CCCM_MDF
                pu.curCand = m_ccmParamsStorage[sub][cccmBufferIdx];
    #else
                pu.curCand = m_ccmParamsStorage[sub][uiMode];
    #endif
              }
    #endif
    #if JVET_AD0202_CCCM_MDF
    
              xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, cccmStorage[sub][cccmBufferIdx]
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
                                      , pcInterPred
    #endif
    		  );
    
              xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, cccmStorage[sub][uiMode]
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
                                      , pcInterPred
    #endif
    	      );
    
              xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, cccmStorage[uiMode]
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
                                      , pcInterPred
    #endif
              );
    
    Jani Lainema's avatar
    Jani Lainema committed
              pu.intraDir[1] = chromaIntraMode;
    
    
              xRecurIntraChromaCodingQT( cs, partitioner, bestCostSoFar, ispType 
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS && JVET_AC0119_LM_CHROMA_FUSION
                                       , UnitBuf<Pel>()
    #endif
    #if JVET_AD0208_IBC_ADAPT_FOR_CAM_CAPTURED_CONTENTS
                                       , pcInterPred
    #endif
              );
    
    Jani Lainema's avatar
    Jani Lainema committed
              if( lumaUsesISP && cs.dist == MAX_UINT )
              {
                continue;
              }
    
              if (cs.sps->getTransformSkipEnabledFlag())
              {
                m_CABACEstimator->getCtx() = ctxStart;
              }
    
              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 JVET_AG0154_DECODER_DERIVED_CCP_FUSION
                if (uiDist < bestDist)
                {
                  bestDist = uiDist;
                }
    #endif
    
    Jani Lainema's avatar
    Jani Lainema committed
                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 ) );
    #endif
                  saveCS.getPredBuf     ( area ).copyFrom( cs.getPredBuf   (area ) );
                  cs.picture->getPredBuf( area ).copyFrom( cs.getPredBuf   (area ) );
    
    #if !JVET_AB0143_CCCM_TS
    
    Jani Lainema's avatar
    Jani Lainema committed
                  cs.picture->getRecoBuf( area ).copyFrom( cs.getRecoBuf( area ) );
    
    Jani Lainema's avatar
    Jani Lainema committed
    
                  for( uint32_t j = 0; j < saveCS.tus.size(); j++ )
                  {
                    saveCS.tus[j]->copyComponentFrom( *orgTUs[j], area.compID );
                  }
                }
    
                dBestCost  = dCost;
                uiBestDist = uiDist;
    
    #if JVET_AB0143_CCCM_TS
                uiBestMode = chromaIntraModeInCCCM;
    #else
    
    Jani Lainema's avatar
    Jani Lainema committed
                uiBestMode = chromaIntraMode;
    
    Jani Lainema's avatar
    Jani Lainema committed
                bestBDPCMMode = cu.bdpcmModeChroma;
    #if JVET_Z0050_DIMD_CHROMA_FUSION
                isChromaFusion  = pu.isChromaFusion;
    #endif
    #if JVET_Z0050_CCLM_SLOPE
                bestCclmOffsets = pu.cclmOffsets;
    #endif
                cccmModeBest    = pu.cccmFlag;
    
    Che-Wei Kuo's avatar
    Che-Wei Kuo committed
    #if JVET_AA0126_GLM
                bestGlmIdc      = pu.glmIdc;
    
    #endif
    #if JVET_AC0054_GLCCCM
                glCccmBest      = pu.glCccmFlag;
    #endif
    
    #if JVET_AD0202_CCCM_MDF
                cccmMultiFilterIdxBest = pu.cccmMultiFilterIdx;
    #endif
    
    #if JVET_AC0147_CCCM_NO_SUBSAMPLING 
                cccmNoSubBest  = pu.cccmNoSubFlag;
                }
    
    Jani Lainema's avatar
    Jani Lainema committed
          pu.cccmFlag = 0;
    
    #if JVET_AD0202_CCCM_MDF
          pu.cccmMultiFilterIdx = 0;
    #endif
    
    #if JVET_AD0120_LBCCP && MMLM
          pu.intraDir[1]    = MMLM_CHROMA_IDX;
          pu.ccInsideFilter = 1;
          if (pu.cs->sps->getUseLMChroma())
          {
    #if JVET_AA0057_CCCM
            pu.cccmFlag = 0;
    #endif
    #if JVET_AC0147_CCCM_NO_SUBSAMPLING
            pu.cccmNoSubFlag = 0;
    #endif
    #if JVET_AC0054_GLCCCM
            pu.glCccmFlag = 0;
    #endif
    #if JVET_AD0202_CCCM_MDF
            pu.cccmMultiFilterIdx = 0;
    #endif
            filterPredInside(COMPONENT_Cb, lmPredFilterStorage[lmPredFiltIdx].Cb(), pu);
            filterPredInside(COMPONENT_Cr, lmPredFilterStorage[lmPredFiltIdx].Cr(), pu);
            fillLmPredFiltList(pu, lmPredFilterStorage[lmPredFiltIdx], lmPredFiltIdx, miLmPredFiltList);
    
    #if JVET_AA0057_CCCM
            if (isMultiCccmFullEnabled)
            {
              pu.cccmFlag  = 1;
              int idxStart = lmPredFiltIdx;
    #if JVET_AD0202_CCCM_MDF
              int idxEnd   = lmPredFiltIdx + (isMultiCccmFullEnabled2 ? CCCM_NUM_PRED_FILTER : 1);
    #else
              int idxEnd   = lmPredFiltIdx + 1;
    #endif
              for (int i = idxStart; i < idxEnd; i++)
              {
    #if JVET_AD0202_CCCM_MDF
                pu.cccmMultiFilterIdx = i - idxStart;
    #endif
    #if JVET_AD0188_CCP_MERGE
                pu.curCand = {};
    #endif
                predIntraCCCM(pu, lmPredFilterStorage[lmPredFiltIdx].Cb(), lmPredFilterStorage[lmPredFiltIdx].Cr(), pu.intraDir[1]);
    #if JVET_AD0188_CCP_MERGE
                ccpCandlmPredFilt[lmPredFiltIdx] = pu.curCand;
    #endif
                fillLmPredFiltList(pu, lmPredFilterStorage[lmPredFiltIdx], lmPredFiltIdx, miLmPredFiltList);
              }
    #if JVET_AD0202_CCCM_MDF
              pu.cccmMultiFilterIdx = 0;
    #endif
    #if JVET_AC0054_GLCCCM
              pu.glCccmFlag = 1;
    #if JVET_AD0188_CCP_MERGE
              pu.curCand = {};
    #endif
              predIntraCCCM(pu, lmPredFilterStorage[lmPredFiltIdx].Cb(), lmPredFilterStorage[lmPredFiltIdx].Cr(), pu.intraDir[1]);
    #if JVET_AD0188_CCP_MERGE
              ccpCandlmPredFilt[lmPredFiltIdx] = pu.curCand;
    #endif
              fillLmPredFiltList(pu, lmPredFilterStorage[lmPredFiltIdx], lmPredFiltIdx, miLmPredFiltList);
              pu.glCccmFlag = 0;
    #endif
    #if JVET_AC0147_CCCM_NO_SUBSAMPLING
              if (pu.cu->slice->getSPS()->getUseCccm() > 1)
              {
                pu.cccmNoSubFlag = 1;
    #if JVET_AD0188_CCP_MERGE
                pu.curCand = {};
    #endif
                predIntraCCCM(pu, lmPredFilterStorage[lmPredFiltIdx].Cb(), lmPredFilterStorage[lmPredFiltIdx].Cr(), pu.intraDir[1]);
    #if JVET_AD0188_CCP_MERGE
                ccpCandlmPredFilt[lmPredFiltIdx] = pu.curCand;
    #endif
                fillLmPredFiltList(pu, lmPredFilterStorage[lmPredFiltIdx], lmPredFiltIdx, miLmPredFiltList);
                pu.cccmNoSubFlag = 0;
              }
    #endif
              std::stable_sort(miLmPredFiltList.begin(), miLmPredFiltList.end(), [](const lmPredFiltModeInfo &l, const lmPredFiltModeInfo &r) { return l.cost < r.cost; });
            }
    #endif
          }
    
          int numLmPredFilterRdo = std::min(1, lmPredFiltIdx);
          if (lmPredFiltIdx > 2 && miLmPredFiltList[2].cost != miLmPredFiltList[1].cost && miLmPredFiltList[2].cost < 1.5 * miLmPredFiltList[1].cost)
          {
            numLmPredFilterRdo += 1;
          }
          for (int idx = 0; idx < numLmPredFilterRdo; idx++)
          {
    #if JVET_AA0057_CCCM
            pu.cccmFlag           = miLmPredFiltList[idx].isCccm;
    #endif
    #if JVET_AC0147_CCCM_NO_SUBSAMPLING
            pu.cccmNoSubFlag      = miLmPredFiltList[idx].isCccmNoSub;
    #endif
    #if JVET_AC0054_GLCCCM
            pu.glCccmFlag         = miLmPredFiltList[idx].isGlcccm;
    #endif
    #if JVET_AD0202_CCCM_MDF
            pu.cccmMultiFilterIdx = miLmPredFiltList[idx].cccmMdfIdx;
    #endif
    
            // Original RD check code replicated from above
            cs.setDecomp(pu.Cb(), false);
            cs.dist = baseDist;
            //----- restore context models -----
            m_CABACEstimator->getCtx() = ctxStart;
    
            //----- chroma coding -----
            xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, lmPredFilterStorage[miLmPredFiltList[idx].bufIdx]);
            if (lumaUsesISP && cs.dist == MAX_UINT)
            {
              continue;
            }
    
            if (cs.sps->getTransformSkipEnabledFlag())
            {
              m_CABACEstimator->getCtx() = ctxStart;
            }
    
            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 JVET_AG0154_DECODER_DERIVED_CCP_FUSION
              if (uiDist < bestDist)
              {
                bestDist = uiDist;
              }
    #endif
    
              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));
    #endif
                saveCS.getPredBuf(area).copyFrom(cs.getPredBuf(area));
                cs.picture->getPredBuf(area).copyFrom(cs.getPredBuf(area));
    #if !JVET_AB0143_CCCM_TS
                cs.picture->getRecoBuf(area).copyFrom(cs.getRecoBuf(area));
    #endif
    
                for (uint32_t j = 0; j < saveCS.tus.size(); j++)
                {
                  saveCS.tus[j]->copyComponentFrom(*orgTUs[j], area.compID);
                }
              }
    
              dBestCost  = dCost;
              uiBestDist = uiDist;
    
              uiBestMode = pu.intraDir[1];
    
              bestBDPCMMode = cu.bdpcmModeChroma;
    #if JVET_Z0050_DIMD_CHROMA_FUSION
              isChromaFusion = pu.isChromaFusion;
    #endif
    #if JVET_Z0050_CCLM_SLOPE
              bestCclmOffsets = pu.cclmOffsets;
    #endif
    #if JVET_AA0057_CCCM
              cccmModeBest = pu.cccmFlag;
    #endif
    #if JVET_AA0126_GLM
              bestGlmIdc = pu.glmIdc;
    #endif
              bestCCInsideFilter = pu.ccInsideFilter;
    #if JVET_AC0054_GLCCCM
              glCccmBest = pu.glCccmFlag;
    #endif
    #if JVET_AD0202_CCCM_MDF
              cccmMultiFilterIdxBest = pu.cccmMultiFilterIdx;
    #endif
    #if JVET_AC0147_CCCM_NO_SUBSAMPLING
              cccmNoSubBest = pu.cccmNoSubFlag;
    #endif
    #if JVET_AD0188_CCP_MERGE
              ccpModelBest = ccpCandlmPredFilt[miLmPredFiltList[idx].bufIdx];
    #endif
            }
          }
          pu.ccInsideFilter = 0;
    #if JVET_AA0057_CCCM
          pu.cccmFlag = 0;
    #endif
    #if JVET_AC0147_CCCM_NO_SUBSAMPLING
          pu.cccmNoSubFlag = 0;
    #endif
    #if JVET_AC0054_GLCCCM
          pu.glCccmFlag = 0;
    #endif
    #if JVET_AD0202_CCCM_MDF
          pu.cccmMultiFilterIdx = 0;
    #endif
    #if JVET_AD0188_CCP_MERGE
          pu.curCand = {};
    #endif
    #endif
    
    
    #if JVET_AD0188_CCP_MERGE
          if (PU::hasNonLocalCCP(pu))
          {
            pu.cccmFlag      = 0;
            pu.cccmNoSubFlag = 0;
            pu.glCccmFlag    = 0;
            CCPModelCandidate candList[MAX_CCP_CAND_LIST_SIZE];
    
    #if JVET_AG0059_CCP_MERGE_ENHANCEMENT
            double            orderedCCPcost[MAX_CCP_CAND_LIST_SIZE * 3];
            int               orderedCCPCand[MAX_CCP_CAND_LIST_SIZE * 3];
            PelUnitBuf        ccpCandStorage[MAX_CCP_CAND_LIST_SIZE * 3];
    #else
    
            double            orderedCCPcost[MAX_CCP_CAND_LIST_SIZE];
            int               orderedCCPCand[MAX_CCP_CAND_LIST_SIZE];
            PelUnitBuf        ccpCandStorage[MAX_CCP_CAND_LIST_SIZE];
    
    #if JVET_AG0154_DECODER_DERIVED_CCP_FUSION
            PelUnitBuf ccpFusionStorage[MAX_CCP_FUSION_NUM];
            int        FusionList[MAX_CCP_FUSION_NUM * 2] = { MAX_CCP_FUSION_NUM };
            reorderCCPCandidates(pu, candList, numPos, FusionList);
    #else
    
    
            const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda() * FRAC_BITS_SCALE;
    
    
    #if JVET_AG0059_CCP_MERGE_ENHANCEMENT
            int fusionModeNum = PU::hasCCPMergeFusionFlag(pu) ? 2 : 0;
            PelUnitBuf predCCPFusionStorage[2];
            if (fusionModeNum)
            {
              for (int i = 0; i < 2; i++)
              {
                pu.ccpMergeFusionType = i;
                predCCPFusionStorage[i] = m_predCCPFusionStorage[i].getBuf(localArea);
                getPredForCCPMrgFusion(pu, predCCPFusionStorage[i].Cb(), predCCPFusionStorage[i].Cr());
              }
            }
            for (int nlCCPFusionMode = 0; nlCCPFusionMode <= fusionModeNum; nlCCPFusionMode++)
            {
              for (int ccpMergeIdx = 0; ccpMergeIdx < numPos; ccpMergeIdx++)
              {
                pu.intraDir[1] = LM_CHROMA_IDX;   // temporary assigned, for SATD checking.
                pu.idxNonLocalCCP = ccpMergeIdx + 1;
                pu.ccpMergeFusionFlag = nlCCPFusionMode > 0;
                pu.ccpMergeFusionType = nlCCPFusionMode > 1;
                int nonAdjCCCMCand = ccpMergeIdx + nlCCPFusionMode * numPos;
                if (pu.ccpMergeFusionFlag == 0)
                {
                  ccpCandStorage[nonAdjCCCMCand] = m_cccmStorage[0][nonAdjCCCMCand].getBuf(localUnitArea);   // Borrow the CCCM storage
                }
                else
                {
                  ccpCandStorage[nonAdjCCCMCand] = m_cccmStorage[1][nonAdjCCCMCand].getBuf(localUnitArea);   // Borrow the CCCM storage
                  ccpCandStorage[nonAdjCCCMCand].Cb().copyFrom(ccpCandStorage[ccpMergeIdx].Cb());
                  ccpCandStorage[nonAdjCCCMCand].Cr().copyFrom(ccpCandStorage[ccpMergeIdx].Cr());
                }
    #else
    
            for (int nonAdjCCCMCand = 0; nonAdjCCCMCand < numPos; nonAdjCCCMCand++)
            {
    
              pu.intraDir[1] = LM_CHROMA_IDX;   // temporary assigned, for SATD checking.
    
              pu.idxNonLocalCCP = nonAdjCCCMCand + 1;
              ccpCandStorage[nonAdjCCCMCand] = m_cccmStorage[0][nonAdjCCCMCand].getBuf(localUnitArea);   // Borrow the CCCM storage
    
    
              uint64_t         sad    = 0;
              uint64_t         sadCb  = 0;
              uint64_t         satdCb = 0;
              uint64_t         sadCr  = 0;
              uint64_t         satdCr = 0;
              CodingStructure &cs     = *(pu.cs);
    
              CompArea areaCb = pu.Cb();
              PelBuf   orgCb  = cs.getOrgBuf(areaCb);
              PelBuf   predCb = ccpCandStorage[nonAdjCCCMCand].Cb();
    
              CompArea areaCr = pu.Cr();
              PelBuf   orgCr  = cs.getOrgBuf(areaCr);
              PelBuf   predCr = ccpCandStorage[nonAdjCCCMCand].Cr();
              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 JVET_AG0059_CCP_MERGE_ENHANCEMENT
              if (pu.ccpMergeFusionFlag == 0)
              {
    #endif
    
              pu.curCand = candList[nonAdjCCCMCand];
              predCCPCandidate(pu, predCb, predCr);
              candList[nonAdjCCCMCand] = pu.curCand;
    
    #if JVET_AG0059_CCP_MERGE_ENHANCEMENT
              }
              else
              {
                pu.curCand = candList[ccpMergeIdx];
                xCalcCcpMrgPred(pu, COMPONENT_Cb, predCCPFusionStorage[pu.ccpMergeFusionType].Cb(), ccpCandStorage[nonAdjCCCMCand].Cb());
                xCalcCcpMrgPred(pu, COMPONENT_Cr, predCCPFusionStorage[pu.ccpMergeFusionType].Cr(), ccpCandStorage[nonAdjCCCMCand].Cr());
              }
    #endif
    
    
              sadCb  = distParamSad.distFunc(distParamSad) * 2;
              satdCb = distParamSatd.distFunc(distParamSatd);
              sad += std::min(sadCb, satdCb);
    
              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;
    
              sadCr  = distParamSad.distFunc(distParamSad) * 2;
              satdCr = distParamSatd.distFunc(distParamSatd);
              sad += std::min(sadCr, satdCr);
    
              m_CABACEstimator->resetBits();
              m_CABACEstimator->nonLocalCCPIndex(pu);
              uint64_t estbits               = m_CABACEstimator->getEstFracBits();
              double   curCost               = (double) sad + sqrtLambdaForFirstPass * (double) estbits;
              orderedCCPcost[nonAdjCCCMCand] = curCost;
              orderedCCPCand[nonAdjCCCMCand] = nonAdjCCCMCand;
    
              for (int i = 0; i < nonAdjCCCMCand; i++)
              {
                if (curCost < orderedCCPcost[i])
                {
                  for (int j = nonAdjCCCMCand; j > i; j--)
                  {
                    orderedCCPcost[j] = orderedCCPcost[j - 1];
                    orderedCCPCand[j] = orderedCCPCand[j - 1];
                  }
                  orderedCCPcost[i] = curCost;
                  orderedCCPCand[i] = nonAdjCCCMCand;
                  break;
                }
              }
            }
    
    #if JVET_AG0154_DECODER_DERIVED_CCP_FUSION
            if ((pu.cu->slice->getSPS()->getUseDdCcpFusion()) && (!m_skipDdCcpMergeFusionList || !(cs.slice->getSliceType() == I_SLICE)))
            {
              pu.idxNonLocalCCP = 1;
              int numRDtestFusion = 2;
              int numRDtestFusionMinusOne = numRDtestFusion - 1;
              int orderedCCPFusionCand[MAX_CCP_FUSION_NUM];
    
              int ccpfusionIdx;
    
              double orderedCCPFusioncost[MAX_CCP_FUSION_NUM];
              for (ccpfusionIdx = 0; ccpfusionIdx < MAX_CCP_FUSION_NUM; ccpfusionIdx++)
              {
                int ccpMergeIndex0 = FusionList[2 * ccpfusionIdx];
                int ccpMergeIndex1 = FusionList[2 * ccpfusionIdx + 1];
                if (ccpMergeIndex0 >= numPos || ccpMergeIndex1 >= numPos)
                {
                  continue;
                }
    
                pu.intraDir[1] = LM_CHROMA_IDX;
                pu.ddNonLocalCCPFusion = ccpfusionIdx + 1;
    
                uint64_t         sad = 0;
                uint64_t         sadCb = 0;
                uint64_t         satdCb = 0;
                uint64_t         sadCr = 0;
                uint64_t         satdCr = 0;
                CodingStructure &cs = *(pu.cs);
    
                CompArea areaCb = pu.Cb();
                PelBuf   orgCb = cs.getOrgBuf(areaCb);
                PelBuf   srcCb0 = ccpCandStorage[ccpMergeIndex0].Cb();
                PelBuf   srcCb1 = ccpCandStorage[ccpMergeIndex1].Cb();
    
                CompArea areaCr = pu.Cr();
                PelBuf   orgCr = cs.getOrgBuf(areaCr);
                PelBuf   srcCr0 = ccpCandStorage[ccpMergeIndex0].Cr();
                PelBuf   srcCr1 = ccpCandStorage[ccpMergeIndex1].Cr();
    
                ccpFusionStorage[ccpfusionIdx] = m_cccmStorage[0][MAX_CCP_CAND_LIST_SIZE + ccpfusionIdx].getBuf(localUnitArea);   // Borrow the CCCM storage
    
                PelBuf   predCb = ccpFusionStorage[ccpfusionIdx].Cb();
                PelBuf   predCr = ccpFusionStorage[ccpfusionIdx].Cr();
                for (int y = 0; y < areaCb.height; y++)
                {
                  for (int x = 0; x < areaCb.width; x++)
                  {
                    predCb.at(x, y) = (srcCb0.at(x, y) + srcCb1.at(x, y) + 1) >> 1;
                    predCr.at(x, y) = (srcCr0.at(x, y) + srcCr1.at(x, y) + 1) >> 1;
                  }
                }
    
                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;
                sadCb = distParamSad.distFunc(distParamSad) * 2;
                satdCb = distParamSatd.distFunc(distParamSatd);
                sad += std::min(sadCb, satdCb);
    
                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;
                sadCr = distParamSad.distFunc(distParamSad) * 2;
                satdCr = distParamSatd.distFunc(distParamSatd);
                sad += std::min(sadCr, satdCr);
    
                m_CABACEstimator->resetBits();
                m_CABACEstimator->nonLocalCCPIndex(pu);
                uint64_t estbits = m_CABACEstimator->getEstFracBits();
                double   curCost = (double)sad + sqrtLambdaForFirstPass * (double)estbits;
                orderedCCPFusioncost[ccpfusionIdx] = curCost;
                orderedCCPFusionCand[ccpfusionIdx] = ccpfusionIdx;
                int maxNumFusionModeIdxForComparison = std::min(numRDtestFusion, ccpfusionIdx);
                for (int i = 0; i < maxNumFusionModeIdxForComparison; i++)
                {
                  if (curCost < orderedCCPFusioncost[i])
                  {
                    for (int j = numRDtestFusionMinusOne; j > i; j--)
                    {
                      orderedCCPFusioncost[j] = orderedCCPFusioncost[j - 1];
                      orderedCCPFusionCand[j] = orderedCCPFusionCand[j - 1];
                    }
                    orderedCCPFusioncost[i] = curCost;
                    orderedCCPFusionCand[i] = ccpfusionIdx;
                    break;
                  }
                }
              }
              m_numCcpMergefusionRdo = std::min(ccpfusionIdx, numRDtestFusion);
              for (int i = 0; i < m_numCcpMergefusionRdo; i++)
              {
                m_ddccpMergeFusionCost[i] = orderedCCPFusioncost[i];
                m_ddCcpMergeFusionModeIndex[i] = orderedCCPFusionCand[i];
                PelBuf   predCb = m_ddCcpFusionStorageTemp[i].Cb();
                PelBuf   predCr = m_ddCcpFusionStorageTemp[i].Cr();
                predCb.copyFrom(ccpFusionStorage[m_ddCcpMergeFusionModeIndex[i]].Cb());
                predCr.copyFrom(ccpFusionStorage[m_ddCcpMergeFusionModeIndex[i]].Cr());
              }
              m_skipDdCcpMergeFusionList = true;
              pu.ddNonLocalCCPFusion = 0;
            }
    
            const int finalNumRDtestFusion = m_numCcpMergefusionRdo;
    #endif
    
    
    #if JVET_AG0059_CCP_MERGE_ENHANCEMENT
            const int numRDtest = std::min(2, numPos) + fusionModeNum;
    #else
    
            for (int rdIdx = 0; rdIdx < numRDtest; rdIdx++)
            {
              int chromaIntraMode = LM_CHROMA_IDX;
    
              pu.cccmFlag = 0;
              pu.cccmNoSubFlag = 0;
              pu.glCccmFlag = 0;
    
              int nonAdjCCCMCand = orderedCCPCand[rdIdx];
    
    
    #if JVET_AG0059_CCP_MERGE_ENHANCEMENT
              int nlCCPFusionMode = nonAdjCCCMCand / numPos;
              int ccpMergeIdx = nonAdjCCCMCand - nlCCPFusionMode * numPos;
    
              pu.idxNonLocalCCP = ccpMergeIdx + 1;
              pu.ccpMergeFusionFlag = nlCCPFusionMode > 0;
              pu.ccpMergeFusionType = nlCCPFusionMode > 1;
              pu.curCand = candList[ccpMergeIdx];
    #else
    
              pu.curCand = candList[nonAdjCCCMCand];
    #endif
    
    
              // Original RD check code replicated from above
              cs.setDecomp(pu.Cb(), false);
              cs.dist = baseDist;
              //----- restore context models -----
              m_CABACEstimator->getCtx() = ctxStart;
    
              //----- chroma coding -----
              pu.intraDir[1] = chromaIntraMode;
    #if JVET_AB0143_CCCM_TS
              xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, ccpCandStorage[nonAdjCCCMCand]);
    #else
              xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType);
    #endif
              if (lumaUsesISP && cs.dist == MAX_UINT)
              {
                continue;
              }
    
              if (cs.sps->getTransformSkipEnabledFlag())
              {
                m_CABACEstimator->getCtx() = ctxStart;
              }
    
              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 JVET_AG0154_DECODER_DERIVED_CCP_FUSION
                if (uiDist < bestDist)
                {
                  bestDist = uiDist;
                }
    #endif
    
                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));
    #endif
                  saveCS.getPredBuf(area).copyFrom(cs.getPredBuf(area));
                  cs.picture->getPredBuf(area).copyFrom(cs.getPredBuf(area));
    #if !JVET_AB0143_CCCM_TS
                  cs.picture->getRecoBuf(area).copyFrom(cs.getRecoBuf(area));
    #endif
    
                  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;
    #if JVET_Z0050_DIMD_CHROMA_FUSION
                isChromaFusion = pu.isChromaFusion;
    #endif
    #if JVET_Z0050_CCLM_SLOPE
                bestCclmOffsets = pu.cclmOffsets;
    #endif
                cccmModeBest = pu.cccmFlag;
    #if JVET_AA0126_GLM
                bestGlmIdc = pu.glmIdc;
    #endif
    
    #if JVET_AC0147_CCCM_NO_SUBSAMPLING
    
                cccmNoSubBest  = pu.cccmNoSubFlag;
    #endif
    #if JVET_AC0054_GLCCCM
                glCccmBest     = pu.glCccmFlag;
    #endif
    #if JVET_AD0202_CCCM_MDF
                cccmMultiFilterIdxBest = pu.cccmMultiFilterIdx;
    
    #endif
    #if JVET_AG0059_CCP_MERGE_ENHANCEMENT
                bestCCInsideFilter = pu.ccInsideFilter;
                bestCcpMergeFusionFlag = pu.ccpMergeFusionFlag;
                bestCcpMergeFusionType = pu.ccpMergeFusionType;