Skip to content
Snippets Groups Projects
EncCu.cpp 174 KiB
Newer Older
  • Learn to ignore specific revisions
  • Nan Hu's avatar
    Nan Hu committed
    
    #if JVET_M0428_ENC_DB_OPT
    
    Nan Hu's avatar
    Nan Hu committed
        if ( m_bestModeUpdated && bestCS->cost != MAX_DOUBLE )
        {
          xCalDebCost( *bestCS, partitioner );
        }
    
    Nan Hu's avatar
    Nan Hu committed
    #endif
    
      }
      tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
    
      if (cu.lwidth() != 64)
      {
        isPerfectMatch = false;
      }
      m_modeCtrl->setIsHashPerfectMatch(isPerfectMatch);
    }
    #endif
    
    
    void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
    {
      const Slice &slice = *tempCS->slice;
    
      CHECK( slice.getSliceType() == I_SLICE, "Merge modes not available for I-slices" );
    
      tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
    
      MergeCtx mergeCtx;
      const SPS &sps = *tempCS->sps;
    
    
      if( sps.getSBTMVPEnabledFlag() )
    
      {
        Size bufSize = g_miScaling.scale( tempCS->area.lumaSize() );
        mergeCtx.subPuMvpMiBuf    = MotionBuf( m_SubPuMiBuf,    bufSize );
      }
    
    
    #if JVET_M0147_DMVR
      Mv   refinedMvdL0[MAX_NUM_PARTS_IN_CTU][MRG_MAX_NUM_CANDS];
    #endif
    
      setMergeBestSATDCost( MAX_DOUBLE );
    
    
      {
        // first get merge candidates
        CodingUnit cu( tempCS->area );
        cu.cs       = tempCS;
        cu.predMode = MODE_INTER;
        cu.slice    = tempCS->slice;
    #if HEVC_TILES_WPP
        cu.tileIdx  = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
    #endif
    
        PredictionUnit pu( tempCS->area );
        pu.cu = &cu;
        pu.cs = tempCS;
    
    #if JVET_M0170_MRG_SHARELIST
        pu.shareParentPos = tempCS->sharedBndPos;
        pu.shareParentSize = tempCS->sharedBndSize;
    #endif
    
        PU::getInterMergeCandidates(pu, mergeCtx
          , 0
        );
    
    #if !JVET_M0068_M0171_MMVD_CLEANUP
    
        PU::restrictBiPredMergeCands(pu, mergeCtx);
    
        PU::getInterMMVDMergeCandidates(pu, mergeCtx);
    
      bool candHasNoResidual[MRG_MAX_NUM_CANDS + MMVD_ADD_NUM];
      for (uint32_t ui = 0; ui < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; ui++)
      {
        candHasNoResidual[ui] = false;
      }
    
      bool                                        bestIsSkip = false;
      bool                                        bestIsMMVDSkip = true;
    
      PelUnitBuf                                  acMergeBuffer[MRG_MAX_NUM_CANDS];
    
      PelUnitBuf                                  acMergeRealBuffer[MMVD_MRG_MAX_RD_BUF_NUM];
      PelUnitBuf *                                acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM];
      PelUnitBuf *                                singleMergeTempBuffer;
      int                                         insertPos;
      unsigned                                    uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM;
    
      static_vector<unsigned, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  RdModeList;
      bool                                        mrgTempBufSet = false;
    
      for (unsigned i = 0; i < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; i++)
      {
        RdModeList.push_back(i);
      }
    
      const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height));
      for (unsigned i = 0; i < MMVD_MRG_MAX_RD_BUF_NUM; i++)
      {
        acMergeRealBuffer[i] = m_acMergeBuffer[i].getBuf(localUnitArea);
        if (i < MMVD_MRG_MAX_RD_NUM)
        {
          acMergeTempBuffer[i] = acMergeRealBuffer + i;
        }
        else
        {
          singleMergeTempBuffer = acMergeRealBuffer + i;
        }
      }
    
    
      static_vector<unsigned, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  RdModeList2; // store the Intra mode for Intrainter
      RdModeList2.clear();
    
      bool isIntrainterEnabled = sps.getUseMHIntra();
    
      if (bestCS->area.lwidth() * bestCS->area.lheight() < 64 || bestCS->area.lwidth() >= MAX_CU_SIZE || bestCS->area.lheight() >= MAX_CU_SIZE)
      {
        isIntrainterEnabled = false;
      }
    
      bool isTestSkipMerge[MRG_MAX_NUM_CANDS]; // record if the merge candidate has tried skip mode
    
      for (uint32_t idx = 0; idx < MRG_MAX_NUM_CANDS; idx++)
      {
        isTestSkipMerge[idx] = false;
      }
      if( m_pcEncCfg->getUseFastMerge() || isIntrainterEnabled)
    
        if (isIntrainterEnabled)
        {
          uiNumMrgSATDCand += 1;
        }
    
        bestIsSkip       = false;
    
        if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) )
        {
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC
          if (slice.getSPS()->getIBCFlag())
    #else
    
          if (slice.getSPS()->getIBCMode())
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          {
            ComprCUCtx cuECtx = m_modeCtrl->getComprCUCtx();
            bestIsSkip = blkCache->isSkip(tempCS->area) && cuECtx.bestCU;
          }
          else
    
          bestIsSkip = blkCache->isSkip( tempCS->area );
    
          bestIsMMVDSkip = blkCache->isMMVDSkip(tempCS->area);
    
    
        if (isIntrainterEnabled) // always perform low complexity check
        {
          bestIsSkip = false;
        }
    
    
        static_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> candCostList;
    
        // 1. Pass: get SATD-cost for selected candidates and reduce their count
        if( !bestIsSkip )
        {
          RdModeList.clear();
          mrgTempBufSet       = true;
          const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda( encTestMode.lossless );
    
          CodingUnit &cu      = tempCS->addCU( tempCS->area, partitioner.chType );
    
          const double sqrtLambdaForFirstPassIntra = m_pcRdCost->getMotionLambda(cu.transQuantBypass) / double(1 << SCALE_BITS);
    
    
          partitioner.setCUData( cu );
          cu.slice            = tempCS->slice;
    #if HEVC_TILES_WPP
          cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
    #endif
          cu.skip             = false;
    
        //cu.affine
          cu.predMode         = MODE_INTER;
        //cu.LICFlag
          cu.transQuantBypass = encTestMode.lossless;
          cu.chromaQpAdj      = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
          cu.qp               = encTestMode.qp;
        //cu.emtFlag  is set below
    
          PredictionUnit &pu  = tempCS->addPU( cu, partitioner.chType );
    
          DistParam distParam;
          const bool bUseHadamard= !encTestMode.lossless;
          m_pcRdCost->setDistParam (distParam, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y(), sps.getBitDepth (CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);
    
          const UnitArea localUnitArea( tempCS->area.chromaFormat, Area( 0, 0, tempCS->area.Y().width, tempCS->area.Y().height) );
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
          uint32_t ibcCand = 0;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          uint32_t numValidMv = mergeCtx.numValidMergeCand;
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
          for( uint32_t uiMergeCand = 0; uiMergeCand < mergeCtx.numValidMergeCand; uiMergeCand++ )
          {
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            if ((mergeCtx.interDirNeighbours[uiMergeCand] == 1 || mergeCtx.interDirNeighbours[uiMergeCand] == 3) && tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[uiMergeCand << 1].refIdx)->getPOC() == tempCS->slice->getPOC())
            {
    
    Yu Han's avatar
    Yu Han committed
              ibcCand++;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
              numValidMv--;
              continue;
            }
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
            mergeCtx.setMergeInfo( pu, uiMergeCand );
    
            PU::spanMotionInfo( pu, mergeCtx );
    
    #if JVET_M0147_DMVR
            pu.mvRefine = true;
    #endif
    
            distParam.cur = singleMergeTempBuffer->Y();
            m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer);
    
            acMergeBuffer[uiMergeCand] = m_acRealMergeBuffer[uiMergeCand].getBuf(localUnitArea);
            acMergeBuffer[uiMergeCand].copyFrom(*singleMergeTempBuffer);
    
    #if JVET_M0147_DMVR
            pu.mvRefine = false;
    #endif
    
            if( mergeCtx.interDirNeighbours[uiMergeCand] == 3 && mergeCtx.mrgTypeNeighbours[uiMergeCand] == MRG_TYPE_DEFAULT_N )
            {
              mergeCtx.mvFieldNeighbours[2*uiMergeCand].mv   = pu.mv[0];
              mergeCtx.mvFieldNeighbours[2*uiMergeCand+1].mv = pu.mv[1];
    
    #if JVET_M0147_DMVR
              {
                int dx, dy, i, j, num = 0;
                dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT);
                dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH);
                if (PU::checkDMVRCondition(pu))
                {
                  for (i = 0; i < (pu.lumaSize().height); i += dy)
                  {
                    for (j = 0; j < (pu.lumaSize().width); j += dx)
                    {
                      refinedMvdL0[num][uiMergeCand] = pu.mvdL0SubPu[num];
                      num++;
                    }
                  }
                }
              }
    #endif
    
            }
    
            Distortion uiSad = distParam.distFunc(distParam);
            uint32_t uiBitsCand = uiMergeCand + 1;
            if( uiMergeCand == tempCS->slice->getMaxNumMergeCand() - 1 )
            {
              uiBitsCand--;
            }
    
            uiBitsCand++; // for mmvd_flag
    
            double cost     = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass;
    
            updateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
    
            if (insertPos != -1)
            {
              if (insertPos == RdModeList.size() - 1)
              {
                swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
              }
              else
              {
                for (uint32_t i = uint32_t(RdModeList.size()) - 1; i > insertPos; i--)
                {
                  swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
                }
                swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
              }
            }
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Yu Han's avatar
    Yu Han committed
            CHECK(std::min(uiMergeCand + 1 - ibcCand, uiNumMrgSATDCand) != RdModeList.size(), "");
    
    Yu Han's avatar
    Yu Han committed
    #else
            CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), "");
    #endif
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          if (numValidMv < uiNumMrgSATDCand)
            uiNumMrgSATDCand = numValidMv;
          if (numValidMv == 0)
            return;
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    
          if (isIntrainterEnabled)
          {
            int numTestIntraMode = 4;
            // prepare for Intra bits calculation
            const TempCtx ctxStart(m_CtxCache, m_CABACEstimator->getCtx());
            const TempCtx ctxStartIntraMode(m_CtxCache, SubCtx(Ctx::MHIntraPredMode, m_CABACEstimator->getCtx()));
    
            // for Intrainter fast, recored the best intra mode during the first round for mrege 0
            int bestMHIntraMode = -1;
            double bestMHIntraCost = MAX_DOUBLE;
    
    
            pu.mhIntraFlag = true;
    
    
            // save the to-be-tested merge candidates
            uint32_t MHIntraMergeCand[NUM_MRG_SATD_CAND];
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, (const int) uiNumMrgSATDCand); mergeCnt++)
    
    Yu Han's avatar
    Yu Han committed
    #else
            for (uint32_t mergeCnt = 0; mergeCnt < NUM_MRG_SATD_CAND; mergeCnt++)
    #endif
    
            {
              MHIntraMergeCand[mergeCnt] = RdModeList[mergeCnt];
            }
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
            for (uint32_t mergeCnt = 0; mergeCnt < std::min( std::min(NUM_MRG_SATD_CAND, (const int)uiNumMrgSATDCand), 4); mergeCnt++)
    
    Yu Han's avatar
    Yu Han committed
    #else
            for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, 4); mergeCnt++)
    #endif
    
            {
              uint32_t mergeCand = MHIntraMergeCand[mergeCnt];
              acMergeBuffer[mergeCand] = m_acRealMergeBuffer[mergeCand].getBuf(localUnitArea);
    
              // estimate merge bits
              uint32_t bitsCand = mergeCand + 1;
              if (mergeCand == pu.cs->slice->getMaxNumMergeCand() - 1)
              {
                bitsCand--;
              }
    
              // first round
              for (uint32_t intraCnt = 0; intraCnt < numTestIntraMode; intraCnt++)
              {
                pu.intraDir[0] = (intraCnt < 2) ? intraCnt : ((intraCnt == 2) ? HOR_IDX : VER_IDX);
    
                // fast 2
                if (mergeCnt > 0 && bestMHIntraMode != pu.intraDir[0])
                {
                  continue;
                }
                int narrowCase = PU::getNarrowShape(pu.lwidth(), pu.lheight());
                if (narrowCase == 1 && pu.intraDir[0] == HOR_IDX)
                {
                  continue;
                }
                if (narrowCase == 2 && pu.intraDir[0] == VER_IDX)
                {
                  continue;
                }
                // generate intrainter Y prediction
                if (mergeCnt == 0)
                {
                  bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Y, pu, true, pu);
                  m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Y(), isUseFilter);
                  m_pcIntraSearch->predIntraAng(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, isUseFilter);
                  m_pcIntraSearch->switchBuffer(pu, COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));
                }
                pu.cs->getPredBuf(pu).copyFrom(acMergeBuffer[mergeCand]);
    
    Taoran Lu's avatar
    Taoran Lu committed
    #if JVET_M0427_INLOOP_RESHAPER
                if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
                {
                  pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getFwdLUT());
                }
    #endif
    
                m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));
    
                // calculate cost
    
    Taoran Lu's avatar
    Taoran Lu committed
    #if JVET_M0427_INLOOP_RESHAPER
                if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
                {
                   pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getInvLUT());
                }
    #endif
    
                distParam.cur = pu.cs->getPredBuf(pu).Y();
                Distortion sadValue = distParam.distFunc(distParam);
    
    #if JVET_M0427_INLOOP_RESHAPER
    
    Taoran Lu's avatar
    Taoran Lu committed
                if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
                {
                  pu.cs->getPredBuf(pu).Y().rspSignal(m_pcReshape->getFwdLUT());
                }
    #endif
    
                m_CABACEstimator->getCtx() = SubCtx(Ctx::MHIntraPredMode, ctxStartIntraMode);
                uint64_t fracModeBits = m_pcIntraSearch->xFracModeBitsIntra(pu, pu.intraDir[0], CHANNEL_TYPE_LUMA);
                double cost = (double)sadValue + (double)(bitsCand + 1) * sqrtLambdaForFirstPass + (double)fracModeBits * sqrtLambdaForFirstPassIntra;
                insertPos = -1;
                updateDoubleCandList(mergeCand + MRG_MAX_NUM_CANDS + MMVD_ADD_NUM, cost, RdModeList, candCostList, RdModeList2, pu.intraDir[0], uiNumMrgSATDCand, &insertPos);
                if (insertPos != -1)
                {
                  for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
                  {
                    swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
                  }
                  swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
                }
                // fast 2
                if (mergeCnt == 0 && cost < bestMHIntraCost)
                {
                  bestMHIntraMode = pu.intraDir[0];
                  bestMHIntraCost = cost;
                }
              }
            }
    
            pu.mhIntraFlag = false;
    
            m_CABACEstimator->getCtx() = ctxStart;
          }
    
    
          cu.mmvdSkip = true;
          int tempNum = 0;
          tempNum = MMVD_ADD_NUM;
    
          bool allowDirection[4] = { true, true, true, true };
    
          for (uint32_t mergeCand = mergeCtx.numValidMergeCand; mergeCand < mergeCtx.numValidMergeCand + tempNum; mergeCand++)
          {
            const int mmvdMergeCand = mergeCand - mergeCtx.numValidMergeCand;
            int bitsBaseIdx = 0;
            int bitsRefineStep = 0;
            int bitsDirection = 2;
            int bitsCand = 0;
            int baseIdx;
            int refineStep;
    
            baseIdx = mmvdMergeCand / MMVD_MAX_REFINE_NUM;
            refineStep = (mmvdMergeCand - (baseIdx * MMVD_MAX_REFINE_NUM)) / 4;
    
            direction = (mmvdMergeCand - baseIdx * MMVD_MAX_REFINE_NUM - refineStep * 4) % 4;
            if (refineStep == 0)
            {
              allowDirection[direction] = true;
            }
            if (allowDirection[direction] == false)
            {
              continue;
            }
    
            bitsBaseIdx = baseIdx + 1;
            if (baseIdx == MMVD_BASE_MV_NUM - 1)
            {
              bitsBaseIdx--;
            }
    
            bitsRefineStep = refineStep + 1;
            if (refineStep == MMVD_REFINE_STEP - 1)
            {
              bitsRefineStep--;
            }
    
            bitsCand = bitsBaseIdx + bitsRefineStep + bitsDirection;
            bitsCand++; // for mmvd_flag
    
            mergeCtx.setMmvdMergeCandiInfo(pu, mmvdMergeCand);
    
            PU::spanMotionInfo(pu, mergeCtx);
    
    #if JVET_M0147_DMVR
            pu.mvRefine = true;
    #endif
    
            distParam.cur = singleMergeTempBuffer->Y();
    
    #if JVET_M0823_MMVD_ENCOPT
            pu.mmvdEncOptMode = (refineStep > 2 ? 2 : 1);
    
            CHECK(!pu.mmvdMergeFlag, "MMVD merge should be set");
            // Don't do chroma MC here
            m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer, REF_PIC_LIST_X, true, false);
    
    #else
            m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer);
    
    #endif
    #if JVET_M0147_DMVR // store the refined MV
            pu.mvRefine = false;
    
            Distortion uiSad = distParam.distFunc(distParam);
    
    
            double cost = (double)uiSad + (double)bitsCand * sqrtLambdaForFirstPass;
    
            allowDirection[direction] = cost >  1.3 * candCostList[0] ? 0 : 1;
    
            updateDoubleCandList(mergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
    
            if (insertPos != -1)
            {
              for (int i = int(RdModeList.size()) - 1; i > insertPos; i--)
              {
                swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);
              }
              swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
            }
          }
    
          // Try to limit number of candidates using SATD-costs
          for( uint32_t i = 1; i < uiNumMrgSATDCand; i++ )
          {
            if( candCostList[i] > MRG_FAST_RATIO * candCostList[0] )
            {
              uiNumMrgSATDCand = i;
              break;
            }
          }
    
    
          setMergeBestSATDCost( candCostList[0] );
    
    
            pu.mhIntraFlag = true;
    
            for (uint32_t mergeCnt = 0; mergeCnt < uiNumMrgSATDCand; mergeCnt++)
            {
              if (RdModeList[mergeCnt] >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
              {
                pu.intraDir[0] = RdModeList2[mergeCnt];
                pu.intraDir[1] = DM_CHROMA_IDX;
                uint32_t bufIdx = (pu.intraDir[0] > 1) ? (pu.intraDir[0] == HOR_IDX ? 2 : 3) : pu.intraDir[0];
                bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cb, pu, true, pu);
                m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cb(), isUseFilter);
                m_pcIntraSearch->predIntraAng(COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), pu, isUseFilter);
                m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx));
                isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cr, pu, true, pu);
                m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cr(), isUseFilter);
                m_pcIntraSearch->predIntraAng(COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), pu, isUseFilter);
                m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx));
              }
            }
    
            pu.mhIntraFlag = false;
    
          tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
        }
        else
        {
    
          if (bestIsMMVDSkip)
          {
            uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM;
          }
          else
          {
            uiNumMrgSATDCand = mergeCtx.numValidMergeCand;
          }
    
    Nan Hu's avatar
    Nan Hu committed
    #if JVET_M0428_ENC_DB_OPT
      m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
    #endif
    
    #if !JVET_M0253_HASH_ME
    
      const uint32_t iteration = encTestMode.lossless ? 1 : 2;
    
      // 2. Pass: check candidates using full RD test
      for( uint32_t uiNoResidualPass = 0; uiNoResidualPass < iteration; uiNoResidualPass++ )
    
    #else
      uint32_t iteration;
      uint32_t iterationBegin = m_modeCtrl->getIsHashPerfectMatch() ? 1 : 0;
      if (encTestMode.lossless)
      {
        iteration = 1;
        iterationBegin = 0;
      }
      else
      {
        iteration = 2;
      }
      for (uint32_t uiNoResidualPass = iterationBegin; uiNoResidualPass < iteration; ++uiNoResidualPass)
    #endif
    
      {
        for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ )
        {
          uint32_t uiMergeCand = RdModeList[uiMrgHADIdx];
    
    Yu Han's avatar
    Yu Han committed
    #if JVET_M0483_IBC==0
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
          if(uiMergeCand < mergeCtx.numValidMergeCand)
            if ((mergeCtx.interDirNeighbours[uiMergeCand] == 1 || mergeCtx.interDirNeighbours[uiMergeCand] == 3) && tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[uiMergeCand << 1].refIdx)->getPOC() == tempCS->slice->getPOC())
            {
              continue;
            }
    
    Yu Han's avatar
    Yu Han committed
    #endif
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
    
    
          if (uiNoResidualPass != 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)) // intrainter does not support skip mode
          {
            uiMergeCand -= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM); // for skip, map back to normal merge candidate idx and try RDO
            if (isTestSkipMerge[uiMergeCand])
            {
              continue;
            }
          }
    
    
          if (((uiNoResidualPass != 0) && candHasNoResidual[uiMrgHADIdx])
    
           || ( (uiNoResidualPass == 0) && bestIsSkip ) )
          {
            continue;
          }
    
          // first get merge candidates
          CodingUnit &cu      = tempCS->addCU( tempCS->area, partitioner.chType );
    
          partitioner.setCUData( cu );
          cu.slice            = tempCS->slice;
    #if HEVC_TILES_WPP
          cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
    #endif
          cu.skip             = false;
    
        //cu.affine
          cu.predMode         = MODE_INTER;
        //cu.LICFlag
          cu.transQuantBypass = encTestMode.lossless;
          cu.chromaQpAdj      = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
          cu.qp               = encTestMode.qp;
          PredictionUnit &pu  = tempCS->addPU( cu, partitioner.chType );
    
    
          if (uiNoResidualPass == 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
          {
            uiMergeCand -= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM);
            cu.mmvdSkip = false;
            mergeCtx.setMergeInfo(pu, uiMergeCand);
    
            pu.mhIntraFlag = true;
    
            pu.intraDir[0] = RdModeList2[uiMrgHADIdx];
            CHECK(pu.intraDir[0]<0 || pu.intraDir[0]>(NUM_LUMA_MODE - 1), "out of intra mode");
            pu.intraDir[1] = DM_CHROMA_IDX;
          }
    
          else if (uiMergeCand >= mergeCtx.numValidMergeCand && uiMergeCand < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)
    
          {
            cu.mmvdSkip = true;
            mergeCtx.setMmvdMergeCandiInfo(pu, uiMergeCand - mergeCtx.numValidMergeCand);
          }
          else
          {
            cu.mmvdSkip = false;
            mergeCtx.setMergeInfo(pu, uiMergeCand);
          }
    
    #if JVET_M0147_DMVR
            {
              int dx, dy, i, j, num = 0;
              dy = std::min<int>(pu.lumaSize().height, DMVR_SUBCU_HEIGHT);
              dx = std::min<int>(pu.lumaSize().width, DMVR_SUBCU_WIDTH);
              if (PU::checkDMVRCondition(pu))
              {
                for (i = 0; i < (pu.lumaSize().height); i += dy)
                {
                  for (j = 0; j < (pu.lumaSize().width); j += dx)
                  {
                    pu.mvdL0SubPu[num] = refinedMvdL0[num][uiMergeCand];
                    num++;
                  }
                }
              }
            }
    #endif
    
            if (pu.mhIntraFlag)
    
            {
              uint32_t bufIdx = (pu.intraDir[0] > 1) ? (pu.intraDir[0] == HOR_IDX ? 2 : 3) : pu.intraDir[0];
              PelBuf tmpBuf = tempCS->getPredBuf(pu).Y();
              tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Y());
    
    Taoran Lu's avatar
    Taoran Lu committed
    #if JVET_M0427_INLOOP_RESHAPER
              if (pu.cs->slice->getReshapeInfo().getUseSliceReshaper() && m_pcReshape->getCTUFlag())
              {
                tmpBuf.rspSignal(m_pcReshape->getFwdLUT());
              }
    #endif
    
              m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, bufIdx));
              tmpBuf = tempCS->getPredBuf(pu).Cb();
              tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cb());
              m_pcIntraSearch->geneWeightedPred(COMPONENT_Cb, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx));
              tmpBuf = tempCS->getPredBuf(pu).Cr();
              tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cr());
              m_pcIntraSearch->geneWeightedPred(COMPONENT_Cr, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx));
            }
            else
            {
    
    #if JVET_M0823_MMVD_ENCOPT
              if (uiMergeCand >= mergeCtx.numValidMergeCand && uiMergeCand < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM) {
                pu.mmvdEncOptMode = 0;
                m_pcInterSearch->motionCompensation(pu);
              }
              else
    #endif
    
              if (uiNoResidualPass != 0 && uiMergeCand < mergeCtx.numValidMergeCand && RdModeList[uiMrgHADIdx] >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
              {
                tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]);
              }
              else
              {
                tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]);
              }
            }
    
    #if JVET_M0147_DMVR
            pu.mvRefine = true;
    #endif
    
    #if JVET_M0147_DMVR
            pu.mvRefine = false;
    
          if (!cu.mmvdSkip && !pu.mhIntraFlag && uiNoResidualPass != 0)
    
          {
            CHECK(uiMergeCand >= mergeCtx.numValidMergeCand, "out of normal merge");
            isTestSkipMerge[uiMergeCand] = true;
          }
    
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #if JVET_M0464_UNI_MTS
          xEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, NULL, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL );
    #else
    
          xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass
            , NULL
            , 1
            , uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL);
    
    Tung Nguyen's avatar
    Tung Nguyen committed
    #endif
    
          if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip && !pu.mhIntraFlag)
    
          {
            bestIsSkip = bestCS->getCU( partitioner.chType )->rootCbf == 0;
          }
          tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
        }// end loop uiMrgHADIdx
    
        if( uiNoResidualPass == 0 && m_pcEncCfg->getUseEarlySkipDetection() )
        {
          const CodingUnit     &bestCU = *bestCS->getCU( partitioner.chType );
          const PredictionUnit &bestPU = *bestCS->getPU( partitioner.chType );
    
          if( bestCU.rootCbf == 0 )
          {
            if( bestPU.mergeFlag )
            {
              m_modeCtrl->setEarlySkipDetected();
            }
            else if( m_pcEncCfg->getMotionEstimationSearchMethod() != MESEARCH_SELECTIVE )
            {
              int absolute_MV = 0;
    
              for( uint32_t uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ )
              {
                if( slice.getNumRefIdx( RefPicList( uiRefListIdx ) ) > 0 )
                {
                  absolute_MV += bestPU.mvd[uiRefListIdx].getAbsHor() + bestPU.mvd[uiRefListIdx].getAbsVer();
                }
              }
    
              if( absolute_MV == 0 )
              {
                m_modeCtrl->setEarlySkipDetected();
              }
            }
          }
        }
      }
    
    Nan Hu's avatar
    Nan Hu committed
    #if JVET_M0428_ENC_DB_OPT
      if ( m_bestModeUpdated && bestCS->cost != MAX_DOUBLE )
    
    Nan Hu's avatar
    Nan Hu committed
      {
    
    Nan Hu's avatar
    Nan Hu committed
        xCalDebCost( *bestCS, partitioner );
    
    Nan Hu's avatar
    Nan Hu committed
      }
    
    Nan Hu's avatar
    Nan Hu committed
    #endif
    
    void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
    {
      const Slice &slice = *tempCS->slice;
      const SPS &sps = *tempCS->sps;
    
      CHECK( slice.getSliceType() != B_SLICE, "Triangle mode is only applied to B-slices" );
    
      tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
    
    rlliao's avatar
    rlliao committed
      bool trianglecandHasNoResidual[TRIANGLE_MAX_NUM_CANDS];
      for( int mergeCand = 0; mergeCand < TRIANGLE_MAX_NUM_CANDS; mergeCand++ )
    
    rlliao's avatar
    rlliao committed
        trianglecandHasNoResidual[mergeCand] = false;
    
    Xiaozhong Xu's avatar
    Xiaozhong Xu committed
      bool bestIsSkip;
      CodingUnit* cuTemp = bestCS->getCU(partitioner.chType);
      if (cuTemp)
        bestIsSkip = m_pcEncCfg->getUseFastDecisionForMerge() ? bestCS->getCU(partitioner.chType)->rootCbf == 0 : false;
      else
        bestIsSkip = false;
    
    rlliao's avatar
    rlliao committed
      uint8_t                                         numTriangleCandidate   = TRIANGLE_MAX_NUM_CANDS;
      uint8_t                                         triangleNumMrgSATDCand = TRIANGLE_MAX_NUM_SATD_CANDS;
      PelUnitBuf                                      triangleBuffer[TRIANGLE_MAX_NUM_UNI_CANDS];
      PelUnitBuf                                      triangleWeightedBuffer[TRIANGLE_MAX_NUM_CANDS];
      static_vector<uint8_t, TRIANGLE_MAX_NUM_CANDS> triangleRdModeList;
      static_vector<double,  TRIANGLE_MAX_NUM_CANDS> tianglecandCostList;
    
    
      if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) )
      {
        bestIsSkip |= blkCache->isSkip( tempCS->area );
      }
    
      DistParam distParam;
    
    rlliao's avatar
    rlliao committed
      const bool useHadamard = !encTestMode.lossless;
      m_pcRdCost->setDistParam( distParam, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y(), sps.getBitDepth( CHANNEL_TYPE_LUMA ), COMPONENT_Y, useHadamard );
    
    
      const UnitArea localUnitArea( tempCS->area.chromaFormat, Area( 0, 0, tempCS->area.Y().width, tempCS->area.Y().height) );
    
      const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda(encTestMode.lossless);
    
    
    rlliao's avatar
    rlliao committed
      MergeCtx triangleMrgCtx;
    
      {
        CodingUnit cu( tempCS->area );
        cu.cs       = tempCS;
        cu.predMode = MODE_INTER;
        cu.slice    = tempCS->slice;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
    #if HEVC_TILES_WPP
        cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
    #endif
    
        cu.triangle = true;
        cu.mmvdSkip = false;
        cu.GBiIdx   = GBI_DEFAULT;
    
        PredictionUnit pu( tempCS->area );
        pu.cu = &cu;
        pu.cs = tempCS;
    
    
    
    rlliao's avatar
    rlliao committed
        PU::getTriangleMergeCandidates( pu, triangleMrgCtx );
        for( uint8_t mergeCand = 0; mergeCand < TRIANGLE_MAX_NUM_UNI_CANDS; mergeCand++ )
    
    rlliao's avatar
    rlliao committed
          triangleBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea);
          triangleMrgCtx.setMergeInfo( pu, mergeCand );
          PU::spanMotionInfo( pu, triangleMrgCtx );
    
    rlliao's avatar
    rlliao committed
          m_pcInterSearch->motionCompensation( pu, triangleBuffer[mergeCand] );
    
    rlliao's avatar
    rlliao committed
      bool tempBufSet = bestIsSkip ? false : true;
      triangleNumMrgSATDCand = bestIsSkip ? TRIANGLE_MAX_NUM_CANDS : TRIANGLE_MAX_NUM_SATD_CANDS;
    
      if( bestIsSkip )
      {
        for( uint8_t i = 0; i < TRIANGLE_MAX_NUM_CANDS; i++ )
        {
    
    rlliao's avatar
    rlliao committed
          triangleRdModeList.push_back(i);
    
        }
      }
      else
      {
        CodingUnit &cu      = tempCS->addCU( tempCS->area, partitioner.chType );
    
        partitioner.setCUData( cu );
        cu.slice            = tempCS->slice;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
    #if HEVC_TILES_WPP
        cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
    #endif
    
        cu.skip             = false;
        cu.predMode         = MODE_INTER;
        cu.transQuantBypass = encTestMode.lossless;
        cu.chromaQpAdj      = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
        cu.qp               = encTestMode.qp;
        cu.triangle         = true;
        cu.mmvdSkip         = false;
        cu.GBiIdx           = GBI_DEFAULT;
    
        PredictionUnit &pu  = tempCS->addPU( cu, partitioner.chType );
    
    rlliao's avatar
    rlliao committed
        if( abs(g_aucLog2[cu.lwidth()] - g_aucLog2[cu.lheight()]) >= 2 )
    
    rlliao's avatar
    rlliao committed
          numTriangleCandidate = 30;
    
    rlliao's avatar
    rlliao committed
          numTriangleCandidate = TRIANGLE_MAX_NUM_CANDS;
    
    rlliao's avatar
    rlliao committed
        for( uint8_t mergeCand = 0; mergeCand < numTriangleCandidate; mergeCand++ )
    
    #if JVET_M0883_TRIANGLE_SIGNALING
          bool    splitDir = m_triangleModeTest[mergeCand].m_splitDir;
          uint8_t candIdx0 = m_triangleModeTest[mergeCand].m_candIdx0;
          uint8_t candIdx1 = m_triangleModeTest[mergeCand].m_candIdx1;
    #else
    
    rlliao's avatar
    rlliao committed
          bool    splitDir = g_triangleCombination[mergeCand][0];
          uint8_t candIdx0 = g_triangleCombination[mergeCand][1];
          uint8_t candIdx1 = g_triangleCombination[mergeCand][2];
    
    #if JVET_M0883_TRIANGLE_SIGNALING
          pu.triangleSplitDir = splitDir;
          pu.triangleMergeIdx0 = candIdx0;
          pu.triangleMergeIdx1 = candIdx1;
    #else
    
    rlliao's avatar
    rlliao committed
          pu.mergeIdx  = mergeCand;
    
    rlliao's avatar
    rlliao committed
          triangleWeightedBuffer[mergeCand] = m_acTriangleWeightedBuffer[mergeCand].getBuf( localUnitArea );
          triangleBuffer[candIdx0] = m_acMergeBuffer[candIdx0].getBuf( localUnitArea );
          triangleBuffer[candIdx1] = m_acMergeBuffer[candIdx1].getBuf( localUnitArea );
    
    #if JVET_M0328_KEEP_ONE_WEIGHT_GROUP
          m_pcInterSearch->weightedTriangleBlk( pu, splitDir, CHANNEL_TYPE_LUMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
    #else
    
    rlliao's avatar
    rlliao committed
          m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, CHANNEL_TYPE_LUMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
    
    rlliao's avatar
    rlliao committed
          distParam.cur = triangleWeightedBuffer[mergeCand].Y();
    
    
          Distortion uiSad = distParam.distFunc( distParam );
    
    
    #if JVET_M0883_TRIANGLE_SIGNALING
          uint32_t uiBitsCand = m_triangleIdxBins[splitDir][candIdx0][candIdx1];
    #else
    
    rlliao's avatar
    rlliao committed
          uint32_t uiBitsCand = g_triangleIdxBins[mergeCand];
    
    
          double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass;
    
    
          static_vector<int, TRIANGLE_MAX_NUM_CANDS> * nullList = nullptr;
          updateCandList( mergeCand, cost, triangleRdModeList, tianglecandCostList
            , *nullList, -1
            , triangleNumMrgSATDCand );
    
        // limit number of candidates using SATD-costs
    
    rlliao's avatar
    rlliao committed
        for( uint8_t i = 0; i < triangleNumMrgSATDCand; i++ )
    
    rlliao's avatar
    rlliao committed
          if( tianglecandCostList[i] > MRG_FAST_RATIO * tianglecandCostList[0] || tianglecandCostList[i] > getMergeBestSATDCost() )
    
    rlliao's avatar
    rlliao committed
            triangleNumMrgSATDCand = i;
    
            break;
          }
        }
    
        // perform chroma weighting process
    
    rlliao's avatar
    rlliao committed
        for( uint8_t i = 0; i < triangleNumMrgSATDCand; i++ )
    
    rlliao's avatar
    rlliao committed
          uint8_t  mergeCand = triangleRdModeList[i];
    
    #if JVET_M0883_TRIANGLE_SIGNALING
          bool     splitDir  = m_triangleModeTest[mergeCand].m_splitDir;
          uint8_t  candIdx0  = m_triangleModeTest[mergeCand].m_candIdx0;
          uint8_t  candIdx1  = m_triangleModeTest[mergeCand].m_candIdx1;
    #else
    
    rlliao's avatar
    rlliao committed
          bool     splitDir  = g_triangleCombination[mergeCand][0];
          uint8_t  candIdx0  = g_triangleCombination[mergeCand][1];
          uint8_t  candIdx1  = g_triangleCombination[mergeCand][2];
    
    #if JVET_M0883_TRIANGLE_SIGNALING
          pu.triangleSplitDir = splitDir;
          pu.triangleMergeIdx0 = candIdx0;
          pu.triangleMergeIdx1 = candIdx1;
    #else
    
    rlliao's avatar
    rlliao committed
          pu.mergeIdx  = mergeCand;
    
    #if JVET_M0328_KEEP_ONE_WEIGHT_GROUP
          m_pcInterSearch->weightedTriangleBlk( pu, splitDir, CHANNEL_TYPE_CHROMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
    #else
    
    rlliao's avatar
    rlliao committed
          m_pcInterSearch->weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, CHANNEL_TYPE_CHROMA, triangleWeightedBuffer[mergeCand], triangleBuffer[candIdx0], triangleBuffer[candIdx1] );
    
        }
    
        tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
      }
    
    Nan Hu's avatar
    Nan Hu committed
    #if JVET_M0428_ENC_DB_OPT
      m_bestModeUpdated = tempCS->useDbCost = bestCS->useDbCost = false;
    #endif
    
    #if !JVET_M0253_HASH_ME
    
        const uint8_t iteration = encTestMode.lossless ? 1 : 2;
    
    rlliao's avatar
    rlliao committed
        for( uint8_t noResidualPass = 0; noResidualPass < iteration; noResidualPass++ )
    
    #else
        uint8_t iteration;
        uint8_t iterationBegin = m_modeCtrl->getIsHashPerfectMatch() ? 1 : 0;
        if (encTestMode.lossless)
        {
          iteration = 1;
          iterationBegin = 0;
        }
        else
        {
          iteration = 2;
        }
        for (uint8_t noResidualPass = iterationBegin; noResidualPass < iteration; ++noResidualPass)
    #endif
    
    rlliao's avatar
    rlliao committed
          for( uint8_t mrgHADIdx = 0; mrgHADIdx < triangleNumMrgSATDCand; mrgHADIdx++ )
    
    rlliao's avatar
    rlliao committed
            uint8_t mergeCand = triangleRdModeList[mrgHADIdx];
    
    rlliao's avatar
    rlliao committed
            if ( ( (noResidualPass != 0) && trianglecandHasNoResidual[mergeCand] )
              || ( (noResidualPass == 0) && bestIsSkip ) )
    
    #if JVET_M0883_TRIANGLE_SIGNALING
            bool    splitDir = m_triangleModeTest[mergeCand].m_splitDir;
            uint8_t candIdx0 = m_triangleModeTest[mergeCand].m_candIdx0;
            uint8_t candIdx1 = m_triangleModeTest[mergeCand].m_candIdx1;
    #else
    
    rlliao's avatar
    rlliao committed
            bool    splitDir = g_triangleCombination[mergeCand][0];
            uint8_t candIdx0 = g_triangleCombination[mergeCand][1];
            uint8_t candIdx1 = g_triangleCombination[mergeCand][2];
    
    
            CodingUnit &cu = tempCS->addCU(tempCS->area, partitioner.chType);
    
            partitioner.setCUData(cu);
            cu.slice = tempCS->slice;
    
    Karsten Suehring's avatar
    Karsten Suehring committed
    #if HEVC_TILES_WPP
            cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
    #endif
    
            cu.skip = false;
            cu.predMode = MODE_INTER;
            cu.transQuantBypass = encTestMode.lossless;
            cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
            cu.qp = encTestMode.qp;
            cu.triangle = true;
            cu.mmvdSkip = false;
            cu.GBiIdx   = GBI_DEFAULT;
            PredictionUnit &pu = tempCS->addPU(cu, partitioner.chType);
    
    
    #if JVET_M0883_TRIANGLE_SIGNALING
            pu.triangleSplitDir = splitDir;
            pu.triangleMergeIdx0 = candIdx0;
            pu.triangleMergeIdx1 = candIdx1;
    #else
    
    rlliao's avatar
    rlliao committed
            pu.mergeIdx = mergeCand;