From cf0eff9f2703021554da39d264c591b12d563c37 Mon Sep 17 00:00:00 2001
From: Yu Han <yuhan@qti.qualcomm.com>
Date: Tue, 29 Jan 2019 17:30:53 -0800
Subject: [PATCH] Add IBC from VTM3.0 to master

---
 source/Lib/CommonLib/CodingStructure.cpp  |  12 +
 source/Lib/CommonLib/ContextModelling.cpp |  22 +
 source/Lib/CommonLib/ContextModelling.h   |   3 +
 source/Lib/CommonLib/Contexts.cpp         |  15 +
 source/Lib/CommonLib/Contexts.h           |   3 +
 source/Lib/CommonLib/InterPrediction.cpp  |  27 +-
 source/Lib/CommonLib/MotionInfo.h         |  15 +
 source/Lib/CommonLib/Slice.cpp            |  82 ++-
 source/Lib/CommonLib/Slice.h              |   8 +-
 source/Lib/CommonLib/TypeDef.h            |  20 +
 source/Lib/CommonLib/Unit.cpp             |   4 +
 source/Lib/CommonLib/Unit.h               |   2 +
 source/Lib/CommonLib/UnitTools.cpp        | 730 +++++++++++++++++++++-
 source/Lib/CommonLib/UnitTools.h          |  18 +
 source/Lib/DecoderLib/CABACReader.cpp     | 203 ++++++
 source/Lib/DecoderLib/DecCu.cpp           |  64 ++
 source/Lib/DecoderLib/DecLib.cpp          |   2 +
 source/Lib/DecoderLib/VLCReader.cpp       |  11 +
 source/Lib/EncoderLib/CABACWriter.cpp     | 156 +++++
 source/Lib/EncoderLib/EncCu.cpp           | 102 ++-
 source/Lib/EncoderLib/EncGOP.cpp          |  10 +
 source/Lib/EncoderLib/EncLib.cpp          |   2 +
 source/Lib/EncoderLib/EncModeCtrl.cpp     |  41 +-
 source/Lib/EncoderLib/EncModeCtrl.h       |   3 +
 source/Lib/EncoderLib/EncSlice.cpp        |   4 +
 source/Lib/EncoderLib/InterSearch.cpp     |  46 +-
 source/Lib/EncoderLib/IntraSearch.cpp     |   4 +
 source/Lib/EncoderLib/VLCWriter.cpp       |   9 +
 28 files changed, 1600 insertions(+), 18 deletions(-)

diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp
index 8d5013fcc1..dfbc5b4cb0 100644
--- a/source/Lib/CommonLib/CodingStructure.cpp
+++ b/source/Lib/CommonLib/CodingStructure.cpp
@@ -746,7 +746,11 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C
   if( cpyResi ) picture->getResiBuf( clippedArea ).copyFrom( subResiBuf );
   if( cpyReco ) picture->getRecoBuf( clippedArea ).copyFrom( subRecoBuf );
 
+#if IBC_SEPERATE_MODE 
+  if (!subStruct.m_isTuEnc && ((!slice->isIntra() || slice->getSPS()->getSpsNext().getIBCMode()) && subStruct.chType != CHANNEL_TYPE_CHROMA))
+#else
   if (!subStruct.m_isTuEnc && (!slice->isIntra() && subStruct.chType != CHANNEL_TYPE_CHROMA))
+#endif
   {
     // copy motion buffer
     MotionBuf ownMB  = getMotionBuf          ( clippedArea );
@@ -926,7 +930,11 @@ void CodingStructure::copyStructure( const CodingStructure& other, const Channel
     pu = *ppu;
   }
 
+#if IBC_SEPERATE_MODE 
+  if (!other.slice->isIntra() || other.slice->getSPS()->getSpsNext().getIBCMode())
+#else
   if( !other.slice->isIntra() )
+#endif
   {
     // copy motion buffer
     MotionBuf  ownMB = getMotionBuf();
@@ -981,7 +989,11 @@ void CodingStructure::initStructData( const int &QP, const bool &_isLosses, cons
     isLossless            = _isLosses;
   }
 
+#if IBC_SEPERATE_MODE
+  if (!skipMotBuf && (!parent || ((!slice->isIntra() || slice->getSPS()->getSpsNext().getIBCMode()) && !m_isTuEnc)))
+#else
   if( !skipMotBuf && ( !parent || ( ( slice->getSliceType() != I_SLICE ) && !m_isTuEnc ) ) )
+#endif
   {
     getMotionBuf()      .memset( 0 );
   }
diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp
index d52ea51e00..134d430ff5 100644
--- a/source/Lib/CommonLib/ContextModelling.cpp
+++ b/source/Lib/CommonLib/ContextModelling.cpp
@@ -451,6 +451,20 @@ unsigned DeriveCtx::CtxPredModeFlag( const CodingUnit& cu )
 }
 #endif
 
+#if IBC_SEPERATE_MODE
+unsigned DeriveCtx::CtxIBCFlag(const CodingUnit& cu)
+{
+  const CodingStructure *cs = cu.cs;
+  unsigned ctxId = 0;
+  const CodingUnit *cuLeft = cs->getCURestricted(cu.lumaPos().offset(-1, 0), cu, CH_L);
+  ctxId = (cuLeft && CU::isIBC(*cuLeft)) ? 1 : 0;
+
+  const CodingUnit *cuAbove = cs->getCURestricted(cu.lumaPos().offset(0, -1), cu, CH_L);
+  ctxId = (cuAbove && CU::isIBC(*cuAbove)) ? 1 : 0;
+  return ctxId;
+}
+#endif
+
 void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx )
 {
   CHECK( candIdx >= numValidMergeCand, "Merge candidate does not exist" );
@@ -470,12 +484,20 @@ void MergeCtx::setMergeInfo( PredictionUnit& pu, int candIdx )
   pu.mvpIdx [REF_PIC_LIST_1] = NOT_VALID;
   pu.mvpNum [REF_PIC_LIST_0] = NOT_VALID;
   pu.mvpNum [REF_PIC_LIST_1] = NOT_VALID;
+#if IBC_SEPERATE_MODE // remove macro VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE
+  if (CU::isIBC(*pu.cu))
+  {
+    pu.bv = pu.mv[REF_PIC_LIST_0];
+    pu.bv >>= (2 + MV_FRACTIONAL_BITS_DIFF); // used for only integer resolution
+  }
+#else
   if (interDirNeighbours[candIdx] == 1 && pu.cs->slice->getRefPic(REF_PIC_LIST_0, mvFieldNeighbours[candIdx << 1].refIdx)->getPOC() == pu.cs->slice->getPOC())
   {
     pu.cu->ibc = true;
     pu.bv = pu.mv[REF_PIC_LIST_0];
     pu.bv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_INT); // used for only integer resolution
   }
+#endif
   pu.cu->GBiIdx = ( interDirNeighbours[candIdx] == 3 ) ? GBiIdx[candIdx] : GBI_DEFAULT;
 
 #if JVET_M0068_M0171_MMVD_CLEANUP
diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h
index 4f2c0d9032..d726c25888 100644
--- a/source/Lib/CommonLib/ContextModelling.h
+++ b/source/Lib/CommonLib/ContextModelling.h
@@ -317,6 +317,9 @@ unsigned CtxTriangleFlag( const CodingUnit& cu );
 #if JVET_M0502_PRED_MODE_CTX
 unsigned CtxPredModeFlag( const CodingUnit& cu );
 #endif
+#if IBC_SEPERATE_MODE
+unsigned CtxIBCFlag(const CodingUnit& cu);
+#endif
 }
 
 #endif // __CONTEXTMODELLING__
diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp
index 5dd621fe0a..db264e715a 100644
--- a/source/Lib/CommonLib/Contexts.cpp
+++ b/source/Lib/CommonLib/Contexts.cpp
@@ -1326,6 +1326,21 @@ const CtxSet ContextSetCfg::TriangleIdx = ContextSetCfg::addCtxSet
 });
 // clang-format on
 
+#if IBC_SEPERATE_MODE
+const CtxSet ContextSetCfg::IBCFlag = ContextSetCfg::addCtxSet
+({
+#if TRAINED_CABAC_INIT_TABLES
+  { 165, 137, 153, },
+  { 106, 122, 138, },
+  { CNU, CNU, CNU, },
+#else
+  { 151, 137, 154, },
+  { 151, 137, 154, },
+  { CNU, CNU, CNU, },
+#endif
+});
+#endif
+
 const unsigned ContextSetCfg::NumberOfContexts = (unsigned)ContextSetCfg::sm_InitTables[0].size();
 
 
diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h
index fcc59f0152..261f6c4186 100644
--- a/source/Lib/CommonLib/Contexts.h
+++ b/source/Lib/CommonLib/Contexts.h
@@ -306,6 +306,9 @@ public:
   static const CtxSet   TriangleIdx;
 #if JVET_M0444_SMVD
   static const CtxSet   SmvdFlag;
+#endif
+#if IBC_SEPERATE_MODE
+  static const CtxSet   IBCFlag;
 #endif
   static const unsigned NumberOfContexts;
 
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index 629426aa7c..ff6634136d 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -375,7 +375,11 @@ void InterPrediction::xPredInterUni(const PredictionUnit& pu, const RefPicList&
   int iRefIdx = pu.refIdx[eRefPicList];
   Mv mv[3];
   bool isIBC = false;
+#if IBC_SEPERATE_MODE
+  if (CU::isIBC(*pu.cu))
+#else
   if (pu.cs->slice->getRefPic(eRefPicList, iRefIdx)->getPOC() == pu.cs->slice->getPOC())
+#endif
   {
     isIBC = true;
   }
@@ -411,11 +415,27 @@ void InterPrediction::xPredInterUni(const PredictionUnit& pu, const RefPicList&
     }
     else
     {
+#if IBC_SEPERATE_MODE
+      if (isIBC)
+      {
+        xPredInterBlk(compID, pu, pu.cu->slice->getPic(), mv[0], pcYuvPred, bi, pu.cu->slice->clpRng(compID)
+          , bioApplied
+          , isIBC
+        );
+      }
+      else
+      {
+        xPredInterBlk(compID, pu, pu.cu->slice->getRefPic(eRefPicList, iRefIdx), mv[0], pcYuvPred, bi, pu.cu->slice->clpRng(compID)
+          , bioApplied
+          , isIBC
+        );
+      }
+#else     
       xPredInterBlk( compID, pu, pu.cu->slice->getRefPic( eRefPicList, iRefIdx ), mv[0], pcYuvPred, bi, pu.cu->slice->clpRng( compID )
                     , bioApplied
                     , isIBC
                     );
-
+#endif
     }
   }
 }
@@ -468,7 +488,12 @@ void InterPrediction::xPredInterBi(PredictionUnit& pu, PelUnitBuf &pcYuvPred)
 
     RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
 
+#if IBC_SEPERATE_MODE
+    CHECK(pu.refIdx[refList] > slice.getNumRefIdx(eRefPicList), "Invalid reference index");
+    CHECK((CU::isInter(*pu.cu) && pu.refIdx[refList] >= slice.getNumRefIdx(eRefPicList)), "Invalid reference index");
+#else
     CHECK( pu.refIdx[refList] >= slice.getNumRefIdx( eRefPicList ), "Invalid reference index" );
+#endif
     m_iRefListIdx = refList;
 
     PelUnitBuf pcMbBuf = ( pu.chromaFormat == CHROMA_400 ?
diff --git a/source/Lib/CommonLib/MotionInfo.h b/source/Lib/CommonLib/MotionInfo.h
index 2078892974..4093475c21 100644
--- a/source/Lib/CommonLib/MotionInfo.h
+++ b/source/Lib/CommonLib/MotionInfo.h
@@ -101,19 +101,31 @@ struct MvField
 struct MotionInfo
 {
   bool     isInter;
+#if IBC_SEPERATE_MODE
+  bool     isIBCmot;
+#endif
   char     interDir;
   uint16_t   sliceIdx;
 
   Mv      mv     [ NUM_REF_PIC_LIST_01 ];
   int16_t   refIdx [ NUM_REF_PIC_LIST_01 ];
   Mv      bv;
+#if IBC_SEPERATE_MODE
+  MotionInfo() : isInter(false), isIBCmot(false), interDir(0), sliceIdx(0), refIdx{ NOT_VALID, NOT_VALID } { }
+  // ensure that MotionInfo(0) produces '\x000....' bit pattern - needed to work with AreaBuf - don't use this constructor for anything else
+  MotionInfo(int i) : isInter(i != 0), isIBCmot(false), interDir(0), sliceIdx(0), refIdx{ 0,         0 } { CHECKD(i != 0, "The argument for this constructor has to be '0'"); }
+#else
   MotionInfo()        : isInter(  false ), interDir( 0 ), sliceIdx( 0 ), refIdx{ NOT_VALID, NOT_VALID } { }
   // ensure that MotionInfo(0) produces '\x000....' bit pattern - needed to work with AreaBuf - don't use this constructor for anything else
   MotionInfo( int i ) : isInter( i != 0 ), interDir( 0 ), sliceIdx( 0 ), refIdx{         0,         0 } { CHECKD( i != 0, "The argument for this constructor has to be '0'" ); }
+#endif
 
   bool operator==( const MotionInfo& mi ) const
   {
     if( isInter != mi.isInter  ) return false;
+#if IBC_SEPERATE_MODE
+    if (isIBCmot != mi.isIBCmot) return false;
+#endif
     if( isInter )
     {
       if( sliceIdx != mi.sliceIdx ) return false;
@@ -211,5 +223,8 @@ struct LutMotionCand
 {
   MotionInfo*   motionCand;
   int  currCnt;
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+  int  currCntIBC;
+#endif
 };
 #endif // __MOTIONINFO__
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index 00f16676bc..61ae73d43b 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -435,6 +435,7 @@ void Slice::setRefPicList( PicList& rcListPic, bool checkNumPocTotalCurr, bool b
       pcRefPic = xGetLongTermRefPic(rcListPic, m_pRPS->getPOC(i), m_pRPS->getCheckLTMSBPresent(i));
     }
   }
+#if IBC_SEPERATE_MODE==0
   if (getSPS()->getSpsNext().getIBCMode())
   {
     RefPicSetLtCurr[NumPicLtCurr] = getPic();
@@ -442,6 +443,7 @@ void Slice::setRefPicList( PicList& rcListPic, bool checkNumPocTotalCurr, bool b
     getPic()->longTerm = true;
     NumPicLtCurr++;
   }
+#endif
   // ref_pic_list_init
   Picture*  rpsCurrList0[MAX_NUM_REF+1];
   Picture*  rpsCurrList1[MAX_NUM_REF+1];
@@ -454,11 +456,13 @@ void Slice::setRefPicList( PicList& rcListPic, bool checkNumPocTotalCurr, bool b
     // - Otherwise, when the current picture contains a P or B slice, the value of NumPocTotalCurr shall not be equal to 0.
     if (getRapPicFlag())
     {
+#if IBC_SEPERATE_MODE==0
       if (getSPS()->getSpsNext().getIBCMode())
       {
         CHECK(numPicTotalCurr != 1, "Invalid state");
       }
       else
+#endif
         CHECK(numPicTotalCurr != 0, "Invalid state");
     }
 
@@ -529,11 +533,13 @@ void Slice::setRefPicList( PicList& rcListPic, bool checkNumPocTotalCurr, bool b
       m_bIsUsedAsLongTerm[REF_PIC_LIST_1][rIdx] = ( cIdx >= NumPicStCurr0 + NumPicStCurr1 );
     }
   }
+#if IBC_SEPERATE_MODE==0
   if (getSPS()->getSpsNext().getIBCMode())
   {
     m_apcRefPicList[REF_PIC_LIST_0][m_aiNumRefIdx[REF_PIC_LIST_0] - 1] = getPic();
     m_bIsUsedAsLongTerm[REF_PIC_LIST_0][m_aiNumRefIdx[REF_PIC_LIST_0] - 1] = true;
   }
+#endif
     // For generalized B
   // note: maybe not existed case (always L0 is copied to L1 if L1 is empty)
   if( bCopyL0toL1ErrorCase && isInterB() && getNumRefIdx(REF_PIC_LIST_1) == 0)
@@ -1612,14 +1618,28 @@ void Slice::initMotionLUTs()
 {
   m_MotionCandLut = new LutMotionCand;
   m_MotionCandLut->currCnt = 0;
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+  m_MotionCandLut->currCntIBC = 0;
+#endif
   m_MotionCandLut->motionCand = nullptr;
+#if IBC_SEPERATE_MODE
+  m_MotionCandLut->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2];
+#else
   m_MotionCandLut->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS];
+#endif
 #if  JVET_M0170_MRG_SHARELIST
   m_MotionCandLuTsBkup = new LutMotionCand;
   m_MotionCandLuTsBkup->currCnt = 0;
+#if IBC_SEPERATE_MODE_AND_MER && IBC_SEPERATE_MODE_REDUCTION==0
+  m_MotionCandLuTsBkup->currCntIBC = 0;
+#endif
   m_MotionCandLuTsBkup->motionCand = nullptr;
+#if IBC_SEPERATE_MODE_AND_MER
+  m_MotionCandLuTsBkup->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2];
+#else
   m_MotionCandLuTsBkup->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS];
 #endif
+#endif
 }
 void Slice::destroyMotionLUTs()
 {
@@ -1637,8 +1657,14 @@ void Slice::destroyMotionLUTs()
 void Slice::resetMotionLUTs()
 {
   m_MotionCandLut->currCnt = 0;
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+  m_MotionCandLut->currCntIBC = 0;
+#endif
 #if  JVET_M0170_MRG_SHARELIST
   m_MotionCandLuTsBkup->currCnt = 0;
+#if IBC_SEPERATE_MODE_AND_MER && IBC_SEPERATE_MODE_REDUCTION==0
+  m_MotionCandLuTsBkup->currCntIBC = 0;
+#endif
 #endif
 }
 
@@ -1653,8 +1679,46 @@ MotionInfo Slice::getMotionInfoFromLUTBkup(int MotCandIdx) const
 }
 #endif
 
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+void Slice::addMotionInfoToLUTs(LutMotionCand* lutMC, MotionInfo newMi, bool ibcflag)
+#else
 void Slice::addMotionInfoToLUTs(LutMotionCand* lutMC, MotionInfo newMi)
+#endif
 {
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+  int currCntIBC = ibcflag ? lutMC->currCntIBC : lutMC->currCnt;
+  int offset = ibcflag ? MAX_NUM_HMVP_CANDS : 0;
+  bool pruned = false;
+  int  sameCandIdx = 0;
+  for (int idx = 0; idx < currCntIBC; idx++)
+  {
+    if (lutMC->motionCand[idx + offset] == newMi)
+    {
+      sameCandIdx = idx;
+      pruned = true;
+      break;
+    }
+  }
+  if (pruned || currCntIBC == MAX_NUM_HMVP_CANDS)
+  {
+    memmove(&lutMC->motionCand[sameCandIdx + offset], &lutMC->motionCand[sameCandIdx + offset + 1],
+      sizeof(MotionInfo) * (currCntIBC - sameCandIdx - 1));
+    memcpy(&lutMC->motionCand[currCntIBC + offset - 1], &newMi, sizeof(MotionInfo));
+  }
+  else
+  {
+    if (ibcflag)
+    {
+      memcpy(&lutMC->motionCand[currCntIBC + offset], &newMi, sizeof(MotionInfo));
+      lutMC->currCntIBC++;
+    }
+    else
+    {
+      memcpy(&lutMC->motionCand[currCntIBC], &newMi, sizeof(MotionInfo));
+      lutMC->currCnt++;
+    }
+  }
+#else
   int currCnt = lutMC->currCnt ;
 
   bool pruned = false;
@@ -1678,6 +1742,7 @@ void Slice::addMotionInfoToLUTs(LutMotionCand* lutMC, MotionInfo newMi)
   {
     memcpy(&lutMC->motionCand[lutMC->currCnt++], &newMi, sizeof(MotionInfo));
   }
+#endif
 }
 
 void Slice::updateMotionLUTs(LutMotionCand* lutMC, CodingUnit & cu)
@@ -1686,19 +1751,34 @@ void Slice::updateMotionLUTs(LutMotionCand* lutMC, CodingUnit & cu)
   if (cu.affine) { return; }
   if (cu.triangle) { return; }
 
-  MotionInfo newMi = selectedPU->getMotionInfo(); 
+  MotionInfo newMi = selectedPU->getMotionInfo();
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+  addMotionInfoToLUTs(lutMC, newMi, CU::isIBC(cu));
+#else
   addMotionInfoToLUTs(lutMC, newMi);
+#endif
 }
 
 void Slice::copyMotionLUTs(LutMotionCand* Src, LutMotionCand* Dst)
 {
    memcpy(Dst->motionCand, Src->motionCand, sizeof(MotionInfo)*(std::min(Src->currCnt, MAX_NUM_HMVP_CANDS)));
    Dst->currCnt = Src->currCnt;
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+   memcpy(Dst->motionCand + MAX_NUM_HMVP_CANDS, Src->motionCand + MAX_NUM_HMVP_CANDS, sizeof(MotionInfo)*(std::min(Src->currCntIBC, MAX_NUM_HMVP_CANDS)));
+   Dst->currCntIBC = Src->currCntIBC;
+#endif
 }
 
 unsigned Slice::getMinPictureDistance() const
 {
   int minPicDist = MAX_INT;
+#if IBC_SEPERATE_MODE
+  if (getSPS()->getSpsNext().getIBCMode())
+  {
+    minPicDist = 0;
+  }
+  else
+#endif
   if( ! isIntra() )
   {
     const int currPOC  = getPOC();
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index 05b8ea8f04..84e2cb998c 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -1949,6 +1949,9 @@ public:
   void                        initMotionLUTs       ();
   void                        destroyMotionLUTs    ();
   void                        resetMotionLUTs();
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+  int                         getAvailableLUTIBCMrgNum() const { return m_MotionCandLut->currCntIBC; }
+#endif
   int                         getAvailableLUTMrgNum() const  { return m_MotionCandLut->currCnt; }
 #if JVET_M0170_MRG_SHARELIST
   int                         getAvailableLUTBkupMrgNum() const  { return m_MotionCandLuTsBkup->currCnt; }
@@ -1957,8 +1960,11 @@ public:
   MotionInfo                  getMotionInfoFromLUTs(int MotCandIdx) const;
   LutMotionCand*              getMotionLUTs() { return m_MotionCandLut; }
 
-
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+  void                        addMotionInfoToLUTs(LutMotionCand* lutMC, MotionInfo newMi, bool ibcflag);
+#else
   void                        addMotionInfoToLUTs(LutMotionCand* lutMC, MotionInfo newMi);
+#endif
 
   void                        updateMotionLUTs(LutMotionCand* lutMC, CodingUnit & cu);
   void                        copyMotionLUTs(LutMotionCand* Src, LutMotionCand* Dst);
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 0add5d415e..6db76d61dd 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,6 +50,21 @@
 #include <assert.h>
 #include <cassert>
 
+#define JVET_M0483_IBC                                    1 //
+#if JVET_M0483_IBC
+#define IBC_SEPERATE_MODE                                 1   //JVET-M0483_method3
+#define IBC_SEPERATE_MODE_FIX                             1   //JVET-M0483_method3 bug fix ticket 129 and 140
+#define IBC_SEPERATE_MODE_REDUCTION                       0   
+#define IBC_SIZE_CONSTRAINT                               0
+#define IBC_SEPERATE_FUNCTION                             1
+
+#define CLEAN_getInterMergeCandidates                     1
+#define CLEAN_fillMvpCand                                 1
+#define MODIFY_for_vtm4                      1
+#define IBC_SEPERATE_MODE_AND_MER                         1
+#define DEBUG_M0483                                       1
+#endif
+
 #define JVET_M0145_AFFINE_MV_CLIP                         1 // Missing clipping for MV storage in affine
 
 #define JVET_M0381_ONE_CTX_FOR_SUBBLOCK_MRG_IDX           1 // CE2.2.2 a: one context for subblock Merge index
@@ -443,7 +458,12 @@ enum PredMode
 {
   MODE_INTER                 = 0,     ///< inter-prediction mode
   MODE_INTRA                 = 1,     ///< intra-prediction mode
+#if IBC_SEPERATE_MODE
+  MODE_IBC                   = 2,     ///< ibc-prediction mode
+  NUMBER_OF_PREDICTION_MODES = 3,
+#else
   NUMBER_OF_PREDICTION_MODES = 2,
+#endif
 };
 
 /// reference list index
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index ecaf89ca16..7d586a2283 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -277,7 +277,9 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other )
   shareParentPos    = other.shareParentPos;
   shareParentSize   = other.shareParentSize;
 #endif
+#if IBC_SEPERATE_MODE==0
   ibc               = other.ibc;
+#endif
 #if JVET_M0444_SMVD
   smvdMode        = other.smvdMode;
 #endif
@@ -319,7 +321,9 @@ void CodingUnit::initData()
   shareParentSize.width = -1;
   shareParentSize.height = -1;
 #endif
+#if IBC_SEPERATE_MODE==0
   ibc               = false;
+#endif
 #if JVET_M0444_SMVD
   smvdMode        = 0;
 #endif
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index 4eb057dde4..fae1f4f6d0 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -316,7 +316,9 @@ struct CodingUnit : public UnitArea
   Position       shareParentPos;
   Size           shareParentSize;
 #endif
+#if IBC_SEPERATE_MODE ==0
   bool           ibc;
+#endif
 #if JVET_M0444_SMVD
   uint8_t          smvdMode;
 #endif
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 0559434c4c..a093910d45 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -78,6 +78,13 @@ bool CU::isInter(const CodingUnit &cu)
   return cu.predMode == MODE_INTER;
 }
 
+#if IBC_SEPERATE_MODE
+bool CU::isIBC(const CodingUnit &cu)
+{
+  return cu.predMode == MODE_IBC;
+}
+#endif
+
 bool CU::isRDPCMEnabled(const CodingUnit& cu)
 {
   return cu.cs->sps->getSpsRangeExtension().getRdpcmEnabledFlag(cu.predMode == MODE_INTRA ? RDPCM_SIGNAL_IMPLICIT : RDPCM_SIGNAL_EXPLICIT);
@@ -711,7 +718,12 @@ bool PU::xCheckSimilarMotion(const int mergeCandIndex, const int prevCnt, const
 #if JVET_L0090_PAIR_AVG
 
 bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool canFastExit, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const int prevCnt, bool isAvailableSubPu, unsigned subPuMvpPos
+#if IBC_SEPERATE_MODE==0
   , int mmvdList
+#endif
+#if IBC_SEPERATE_MODE&& IBC_SEPERATE_MODE_REDUCTION==0
+  , bool ibc_flag
+#endif
 #if JVET_M0170_MRG_SHARELIST
   , bool isShared
 #endif
@@ -723,7 +735,9 @@ bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter
 )
 #endif
 {
+#if IBC_SEPERATE_MODE==0
   int mrgCandIdxIBC = mrgCandIdx;
+#endif
   MotionInfo miNeighbor;
   bool hasPruned[MRG_MAX_NUM_CANDS];
   memset(hasPruned, 0, MRG_MAX_NUM_CANDS * sizeof(bool));
@@ -732,17 +746,35 @@ bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter
     hasPruned[subPuMvpPos] = true;
   }
 #if JVET_M0170_MRG_SHARELIST
+#if IBC_SEPERATE_MODE_AND_MER && IBC_SEPERATE_MODE_REDUCTION==0 // Todo: remove
   int num_avai_candInLUT = (isShared ? slice.getAvailableLUTBkupMrgNum() : slice.getAvailableLUTMrgNum());
+  int offset = ibc_flag ? MAX_NUM_HMVP_CANDS : 0;
+#else
+  int num_avai_candInLUT = (isShared ? slice.getAvailableLUTBkupMrgNum() : slice.getAvailableLUTMrgNum());
+#endif
+#else
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+  int num_avai_candInLUT = ibc_flag ? slice.getAvailableLUTIBCMrgNum() : slice.getAvailableLUTMrgNum();
+  int offset = ibc_flag ? MAX_NUM_HMVP_CANDS : 0;
 #else
   int num_avai_candInLUT = slice.getAvailableLUTMrgNum();
+#endif
 #endif
 
   for (int mrgIdx = 1; mrgIdx <= num_avai_candInLUT; mrgIdx++)
   {
 #if JVET_M0170_MRG_SHARELIST
+#if IBC_SEPERATE_MODE_AND_MER && IBC_SEPERATE_MODE_REDUCTION==0//Todo: remove
     miNeighbor = isShared ? slice.getMotionInfoFromLUTBkup(num_avai_candInLUT - mrgIdx) : slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx);
+#else
+    miNeighbor = isShared ? slice.getMotionInfoFromLUTBkup(num_avai_candInLUT - mrgIdx) : slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx);
+#endif
+#else
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+    miNeighbor = slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx + offset);
 #else
     miNeighbor = slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx);
+#endif
 #endif
     mrgCtx.interDirNeighbours[cnt] = miNeighbor.interDir;
     mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miNeighbor.mv[0], miNeighbor.refIdx[0]);
@@ -755,6 +787,7 @@ bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter
 #if !JVET_L0090_PAIR_AVG
       isCandInter[cnt] = true;
 #endif
+#if IBC_SEPERATE_MODE==0
       if (miNeighbor.interDir == 1 && slice.getRefPic(REF_PIC_LIST_0, miNeighbor.refIdx[0])->getPOC() == slice.getPOC())
       {
         mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
@@ -762,6 +795,9 @@ bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter
           mrgCandIdxIBC++;
       }
       if (mrgCandIdxIBC == cnt && canFastExit)
+#else
+      if (mrgCandIdx == cnt && canFastExit)
+#endif
       {
         return true;
       }
@@ -775,6 +811,293 @@ bool PU::addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter
   return false;
 }
 
+#if IBC_SEPERATE_FUNCTION
+void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx)
+{
+  const CodingStructure &cs = *pu.cs;
+  const Slice &slice = *pu.cs->slice;
+  const uint32_t maxNumMergeCand = slice.getMaxNumMergeCand();
+  const bool canFastExit = pu.cs->pps->getLog2ParallelMergeLevelMinus2() == 0;
+
+  for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
+  {
+    mrgCtx.GBiIdx[ui] = GBI_DEFAULT;
+    mrgCtx.interDirNeighbours[ui] = 0;
+    mrgCtx.mrgTypeNeighbours[ui] = MRG_TYPE_IBC;
+    mrgCtx.mvFieldNeighbours[(ui << 1)].refIdx = NOT_VALID;
+    mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;
+  }
+
+  mrgCtx.numValidMergeCand = maxNumMergeCand;
+  // compute the location of the current PU
+
+  int cnt = 0;
+
+  const Position posLT = pu.Y().topLeft();
+  const Position posRT = pu.Y().topRight();
+  const Position posLB = pu.Y().bottomLeft();
+
+  MotionInfo miAbove, miLeft, miAboveLeft, miAboveRight, miBelowLeft;
+
+  //left
+  const PredictionUnit* puLeft = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType);
+  const bool isAvailableA1 = puLeft && isDiffMER(pu, *puLeft) && pu.cu != puLeft->cu && CU::isIBC(*puLeft->cu);
+  if (isAvailableA1)
+  {
+    miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
+
+    // get Inter Dir
+    mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
+    // get Mv from Left
+    mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
+    if (mrgCandIdx == cnt && canFastExit)
+    {
+      return;
+    }
+    cnt++;
+  }
+
+  // early termination
+  if (cnt == maxNumMergeCand)
+  {
+    return;
+  }
+
+
+  // above
+  const PredictionUnit *puAbove = cs.getPURestricted(posRT.offset(0, -1), pu, pu.chType);
+  bool isAvailableB1 = puAbove && isDiffMER(pu, *puAbove) && pu.cu != puAbove->cu && CU::isIBC(*puAbove->cu);
+  if (isAvailableB1)
+  {
+    miAbove = puAbove->getMotionInfo(posRT.offset(0, -1));
+
+    if (!isAvailableA1 || (miAbove != miLeft))
+    {
+      // get Inter Dir
+      mrgCtx.interDirNeighbours[cnt] = miAbove.interDir;
+      // get Mv from Above
+      mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAbove.mv[0], miAbove.refIdx[0]);
+      if (mrgCandIdx == cnt && canFastExit)
+      {
+        return;
+      }
+
+      cnt++;
+    }
+  }
+
+  // early termination
+  if (cnt == maxNumMergeCand)
+  {
+    return;
+  }
+
+  // above right
+  const PredictionUnit *puAboveRight = cs.getPURestricted(posRT.offset(1, -1), pu, pu.chType);
+  bool isAvailableB0 = puAboveRight && isDiffMER(pu, *puAboveRight) && CU::isIBC(*puAboveRight->cu);
+  if (isAvailableB0)
+  {
+    miAboveRight = puAboveRight->getMotionInfo(posRT.offset(1, -1));
+
+#if HM_JEM_MERGE_CANDS
+    if ((!isAvailableB1 || (miAbove != miAboveRight)) && (!isAvailableA1 || (miLeft != miAboveRight)))
+#else
+    if (!isAvailableB1 || (miAbove != miAboveRight))
+#endif
+    {
+      // get Inter Dir
+      mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir;
+      // get Mv from Above-right
+      mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAboveRight.mv[0], miAboveRight.refIdx[0]);
+
+      if (mrgCandIdx == cnt && canFastExit)
+      {
+        return;
+      }
+
+      cnt++;
+    }
+  }
+  // early termination
+  if (cnt == maxNumMergeCand)
+  {
+    return;
+  }
+
+  //left bottom
+  const PredictionUnit *puLeftBottom = cs.getPURestricted(posLB.offset(-1, 1), pu, pu.chType);
+  bool isAvailableA0 = puLeftBottom && isDiffMER(pu, *puLeftBottom) && CU::isIBC(*puLeftBottom->cu);
+  if (isAvailableA0)
+  {
+    miBelowLeft = puLeftBottom->getMotionInfo(posLB.offset(-1, 1));
+
+#if HM_JEM_MERGE_CANDS
+    if ((!isAvailableA1 || (miBelowLeft != miLeft)) && (!isAvailableB1 || (miBelowLeft != miAbove)) && (!isAvailableB0 || (miBelowLeft != miAboveRight)))
+#else
+    if (!isAvailableA1 || (miBelowLeft != miLeft))
+#endif
+    {
+      // get Inter Dir
+      mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir;
+      mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miBelowLeft.mv[0], miBelowLeft.refIdx[0]);
+      if (mrgCandIdx == cnt && canFastExit)
+      {
+        return;
+      }
+
+      cnt++;
+    }
+  }
+  // early termination
+  if (cnt == maxNumMergeCand)
+  {
+    return;
+  }
+
+  // above left
+  if (cnt < 4)
+  {
+    const PredictionUnit *puAboveLeft = cs.getPURestricted(posLT.offset(-1, -1), pu, pu.chType);
+    bool isAvailableB2 = puAboveLeft && isDiffMER(pu, *puAboveLeft) && CU::isIBC(*puAboveLeft->cu);
+    if (isAvailableB2)
+    {
+      miAboveLeft = puAboveLeft->getMotionInfo(posLT.offset(-1, -1));
+
+#if HM_JEM_MERGE_CANDS
+      if ((!isAvailableA1 || (miLeft != miAboveLeft)) && (!isAvailableB1 || (miAbove != miAboveLeft)) && (!isAvailableA0 || (miBelowLeft != miAboveLeft)) && (!isAvailableB0 || (miAboveRight != miAboveLeft)))
+#else
+      if ((!isAvailableA1 || (miLeft != miAboveLeft)) && (!isAvailableB1 || (miAbove != miAboveLeft)))
+#endif
+      {
+        // get Inter Dir
+        mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir;
+        mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miAboveLeft.mv[0], miAboveLeft.refIdx[0]);
+        if (mrgCandIdx == cnt && canFastExit)
+        {
+          return;
+        }
+
+        cnt++;
+      }
+    }
+  }
+  // early termination
+  if (cnt == maxNumMergeCand)
+  {
+    return;
+  }
+
+  int maxNumMergeCandMin1 = maxNumMergeCand - 1;
+#if IBC_SEPERATE_MODE_REDUCTION
+  if (cnt != maxNumMergeCandMin1 && pu.cu->predMode == MODE_INTER)
+#else
+  if (cnt != maxNumMergeCandMin1)
+#endif
+  {
+    bool isAvailableSubPu = false;
+    unsigned subPuMvpPos = 0;
+
+#if JVET_L0090_PAIR_AVG
+#if MODIFY_for_vtm4
+#if JVET_M0170_MRG_SHARELIST
+    bool  isShared = ((pu.Y().lumaSize().width != pu.shareParentSize.width) || (pu.Y().lumaSize().height != pu.shareParentSize.height));
+#endif
+#endif
+    bool bFound = addMergeHMVPCand(slice, mrgCtx, canFastExit
+      , mrgCandIdx
+      , maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+      , true
+#endif
+#if MODIFY_for_vtm4
+#if JVET_M0170_MRG_SHARELIST
+      , isShared
+#endif
+#endif
+    );
+#else
+    bool bFound = addMergeHMVPCand(slice, mrgCtx, isCandInter, canFastExit
+      , mrgCandIdx
+      , maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos
+    );
+#endif
+    if (bFound)
+    {
+      return;
+    }
+  }
+
+#if JVET_L0090_PAIR_AVG
+  // pairwise-average candidates
+#if IBC_SEPERATE_MODE_REDUCTION
+  if (pu.cu->predMode == MODE_INTER)
+#endif
+  {
+    const int cutoff = std::min(cnt, 4);
+    const int end = cutoff * (cutoff - 1) / 2;
+    constexpr int PRIORITY_LIST0[] = { 0, 0, 1, 0, 1, 2 };
+    constexpr int PRIORITY_LIST1[] = { 1, 2, 2, 3, 3, 3 };
+
+    for (int idx = 0; idx < end && cnt != maxNumMergeCand; idx++)
+    {
+      const int i = PRIORITY_LIST0[idx];
+      const int j = PRIORITY_LIST1[idx];
+
+      mrgCtx.mvFieldNeighbours[cnt * 2].setMvField(Mv(0, 0), NOT_VALID);
+      mrgCtx.mvFieldNeighbours[cnt * 2 + 1].setMvField(Mv(0, 0), NOT_VALID);
+      // calculate average MV for L0 and L1 seperately
+      unsigned char interDir = 0;
+
+      for (int refListId = 0; refListId < 1; refListId++)
+      {
+        const short refIdxI = mrgCtx.mvFieldNeighbours[i * 2 + refListId].refIdx;
+        const short refIdxJ = mrgCtx.mvFieldNeighbours[j * 2 + refListId].refIdx;
+
+        // both MVs are invalid, skip
+        if ((refIdxI == NOT_VALID) && (refIdxJ == NOT_VALID))
+        {
+          continue;
+        }
+
+        interDir += 1 << refListId;
+        // both MVs are valid, average these two MVs
+        if ((refIdxI != NOT_VALID) && (refIdxJ != NOT_VALID))
+        {
+          const Mv& MvI = mrgCtx.mvFieldNeighbours[i * 2 + refListId].mv;
+          const Mv& MvJ = mrgCtx.mvFieldNeighbours[j * 2 + refListId].mv;
+
+          // average two MVs
+          Mv avgMv = MvI;
+
+          avgMv += MvJ;
+          mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
+          avgMv.setHor(avgMv.getHor() / 2);
+          avgMv.setVer(avgMv.getVer() / 2);
+          avgMv.setHor((avgMv.getHor() / 16) << 4);
+          avgMv.setVer((avgMv.getVer() / 16) << 4);
+          mrgCtx.mvFieldNeighbours[cnt * 2 + refListId].setMvField(avgMv, refIdxI);
+        }
+      }
+      mrgCtx.interDirNeighbours[cnt] = interDir;
+      if (interDir > 0)
+      {
+        cnt++;
+      }
+    }
+
+    // early termination
+    if (cnt == maxNumMergeCand)
+    {
+      return;
+    }
+  }
+#endif
+
+  mrgCtx.numValidMergeCand = cnt;
+
+}
+#endif
+
 void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
                                  int mmvdList,
                                  const int& mrgCandIdx )
@@ -796,7 +1119,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 #endif
     mrgCtx.GBiIdx[ui] = GBI_DEFAULT;
     mrgCtx.interDirNeighbours[ui] = 0;
+#if IBC_SEPERATE_MODE && CLEAN_getInterMergeCandidates==0
+    mrgCtx.mrgTypeNeighbours[ui] = CU::isIBC(*pu.cu) ? MRG_TYPE_IBC : MRG_TYPE_DEFAULT_N;
+#else
     mrgCtx.mrgTypeNeighbours [ui] = MRG_TYPE_DEFAULT_N;
+#endif
     mrgCtx.mvFieldNeighbours[(ui << 1)    ].refIdx = NOT_VALID;
     mrgCtx.mvFieldNeighbours[(ui << 1) + 1].refIdx = NOT_VALID;
   }
@@ -806,8 +1133,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 
   int cnt = 0;
 
-
+#if IBC_SEPERATE_MODE==0
   int mrgCandIdxIBC = mrgCandIdx;
+#endif
 
 #if JVET_M0170_MRG_SHARELIST
   const Position posLT = pu.shareParentPos;
@@ -823,7 +1151,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
   //left
   const PredictionUnit* puLeft = cs.getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
 
+#if IBC_SEPERATE_MODE
+  const bool isAvailableA1 = puLeft && isDiffMER(pu, *puLeft) && pu.cu != puLeft->cu && (puLeft->cu->predMode == pu.cu->predMode);
+#else
   const bool isAvailableA1 = puLeft && isDiffMER( pu, *puLeft ) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu );
+#endif
 
   if( isAvailableA1 )
   {
@@ -837,19 +1169,25 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
     mrgCtx.interDirNeighbours[cnt] = miLeft.interDir;
     mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeft->cu->GBiIdx : GBI_DEFAULT;
     // get Mv from Left
+#if IBC_SEPERATE_MODE==0
     if (puLeft->cu->ibc)
     {
       mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
       if (mmvdList != 0 && mrgCandIdx != -1)
         mrgCandIdxIBC++;
     }
+#endif
     mrgCtx.mvFieldNeighbours[cnt << 1].setMvField(miLeft.mv[0], miLeft.refIdx[0]);
 
     if (slice.isInterB())
     {
       mrgCtx.mvFieldNeighbours[(cnt << 1) + 1].setMvField(miLeft.mv[1], miLeft.refIdx[1]);
     }
+#if IBC_SEPERATE_MODE==0
     if (mrgCandIdxIBC == cnt && canFastExit)
+#else
+    if (mrgCandIdx == cnt && canFastExit)
+#endif
     {
       return;
     }
@@ -867,7 +1205,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
   // above
   const PredictionUnit *puAbove = cs.getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType );
 
+#if IBC_SEPERATE_MODE
+  bool isAvailableB1 = puAbove && isDiffMER(pu, *puAbove) && pu.cu != puAbove->cu && puAbove->cu->predMode == pu.cu->predMode;
+#else
   bool isAvailableB1 = puAbove && isDiffMER( pu, *puAbove ) && pu.cu != puAbove->cu && CU::isInter( *puAbove->cu );
+#endif
 
   if( isAvailableB1 )
   {
@@ -883,19 +1225,25 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
       mrgCtx.interDirNeighbours[cnt] = miAbove.interDir;
       // get Mv from Above
       mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAbove->cu->GBiIdx : GBI_DEFAULT;
+#if IBC_SEPERATE_MODE==0
       if (puAbove->cu->ibc)
       {
         mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
         if (mmvdList != 0 && mrgCandIdx != -1)
           mrgCandIdxIBC++;
       }
+#endif
       mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAbove.mv[0], miAbove.refIdx[0] );
 
       if( slice.isInterB() )
       {
         mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAbove.mv[1], miAbove.refIdx[1] );
       }
+#if IBC_SEPERATE_MODE==0
       if (mrgCandIdxIBC == cnt && canFastExit)
+#else
+      if (mrgCandIdx == cnt && canFastExit)
+#endif
       {
         return;
       }
@@ -913,7 +1261,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
   // above right
   const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
 
+#if IBC_SEPERATE_MODE
+  bool isAvailableB0 = puAboveRight && isDiffMER(pu, *puAboveRight) && (puAboveRight->cu->predMode == pu.cu->predMode);
+#else
   bool isAvailableB0 = puAboveRight && isDiffMER( pu, *puAboveRight ) && CU::isInter( *puAboveRight->cu );
+#endif
 
   if( isAvailableB0 )
   {
@@ -933,12 +1285,14 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
       mrgCtx.interDirNeighbours[cnt] = miAboveRight.interDir;
       // get Mv from Above-right
       mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveRight->cu->GBiIdx : GBI_DEFAULT;
+#if IBC_SEPERATE_MODE==0
       if (puAboveRight->cu->ibc)
       {
         mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
         if (mmvdList != 0 && mrgCandIdx != -1)
           mrgCandIdxIBC++;
       }
+#endif
       mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveRight.mv[0], miAboveRight.refIdx[0] );
 
       if( slice.isInterB() )
@@ -946,7 +1300,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
         mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveRight.mv[1], miAboveRight.refIdx[1] );
       }
 
+#if IBC_SEPERATE_MODE==0
       if (mrgCandIdxIBC == cnt && canFastExit)
+#else
+      if (mrgCandIdx == cnt && canFastExit)
+#endif
       {
         return;
       }
@@ -963,7 +1321,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
   //left bottom
   const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
 
+#if IBC_SEPERATE_MODE
+  bool isAvailableA0 = puLeftBottom && isDiffMER(pu, *puLeftBottom) && (puLeftBottom->cu->predMode == pu.cu->predMode);
+#else
   bool isAvailableA0 = puLeftBottom && isDiffMER( pu, *puLeftBottom ) && CU::isInter( *puLeftBottom->cu );
+#endif
 
   if( isAvailableA0 )
   {
@@ -983,12 +1345,14 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
       mrgCtx.interDirNeighbours[cnt] = miBelowLeft.interDir;
       mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puLeftBottom->cu->GBiIdx : GBI_DEFAULT;
       // get Mv from Bottom-Left
+#if IBC_SEPERATE_MODE==0
       if (puLeftBottom->cu->ibc)
       {
         mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
         if (mmvdList != 0 && mrgCandIdx != -1)
           mrgCandIdxIBC++;
       }
+#endif
       mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miBelowLeft.mv[0], miBelowLeft.refIdx[0] );
 
       if( slice.isInterB() )
@@ -996,7 +1360,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
         mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miBelowLeft.mv[1], miBelowLeft.refIdx[1] );
       }
 
+#if IBC_SEPERATE_MODE==0
       if (mrgCandIdxIBC == cnt && canFastExit)
+#else
+      if (mrgCandIdx == cnt && canFastExit)
+#endif
       {
         return;
       }
@@ -1016,7 +1384,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
   {
     const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
 
+#if IBC_SEPERATE_MODE
+    bool isAvailableB2 = puAboveLeft && isDiffMER(pu, *puAboveLeft) && (puAboveLeft->cu->predMode == pu.cu->predMode);
+#else
     bool isAvailableB2 = puAboveLeft && isDiffMER( pu, *puAboveLeft ) && CU::isInter( *puAboveLeft->cu );
+#endif
 
     if( isAvailableB2 )
     {
@@ -1036,12 +1408,14 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
         mrgCtx.interDirNeighbours[cnt] = miAboveLeft.interDir;
         mrgCtx.GBiIdx[cnt] = (mrgCtx.interDirNeighbours[cnt] == 3) ? puAboveLeft->cu->GBiIdx : GBI_DEFAULT;
         // get Mv from Above-Left
+#if IBC_SEPERATE_MODE==0
         if (puAboveLeft->cu->ibc)
         {
           mrgCtx.mrgTypeNeighbours[cnt] = MRG_TYPE_IBC;
           if (mmvdList != 0 && mrgCandIdx != -1)
             mrgCandIdxIBC++;
         }
+#endif
         mrgCtx.mvFieldNeighbours[cnt << 1].setMvField( miAboveLeft.mv[0], miAboveLeft.refIdx[0] );
 
         if( slice.isInterB() )
@@ -1049,7 +1423,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
           mrgCtx.mvFieldNeighbours[( cnt << 1 ) + 1].setMvField( miAboveLeft.mv[1], miAboveLeft.refIdx[1] );
         }
 
+#if IBC_SEPERATE_MODE==0
         if (mrgCandIdxIBC == cnt && canFastExit)
+#else
+        if (mrgCandIdx == cnt && canFastExit)
+#endif
         {
           return;
         }
@@ -1064,7 +1442,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
     return;
   }
 
+#if IBC_SEPERATE_MODE_REDUCTION && CLEAN_getInterMergeCandidates==0
+  if (slice.getEnableTMVPFlag() && pu.cu->predMode == MODE_INTER)
+#else
   if (slice.getEnableTMVPFlag())
+#endif
   {
     //>> MTK colocated-RightBottom
     // offset the pos to be sure to "point" to the same position the uiAbsPartIdx would've pointed to
@@ -1150,7 +1532,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 
     if( dir != 0 )
     {
+#if IBC_SEPERATE_MODE
+      bool addTMvp = !CU::isIBC(*pu.cu);
+#else
       bool addTMvp = true;
+#endif
 #if HM_JEM_MERGE_CANDS
       int iSpanCand = cnt;
       for( int i = 0; i < iSpanCand; i++ )
@@ -1170,7 +1556,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
         isCandInter              [uiArrayAddr] = true;
 #endif
         mrgCtx.GBiIdx[uiArrayAddr] = GBI_DEFAULT;
+#if IBC_SEPERATE_MODE==0
         if (mrgCandIdxIBC == cnt && canFastExit)
+#else
+        if (mrgCandIdx == cnt && canFastExit)
+#endif
         {
           return;
         }
@@ -1187,7 +1577,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
   }
 
   int maxNumMergeCandMin1 = maxNumMergeCand - 1;
+#if IBC_SEPERATE_MODE_REDUCTION && CLEAN_getInterMergeCandidates==0
+  if (cnt != maxNumMergeCandMin1 && pu.cu->predMode == MODE_INTER)
+#else
   if (cnt != maxNumMergeCandMin1)
+#endif
   {
     bool isAvailableSubPu = false;
     unsigned subPuMvpPos = 0;
@@ -1196,9 +1590,18 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
     bool  isShared = ((pu.Y().lumaSize().width != pu.shareParentSize.width) || (pu.Y().lumaSize().height != pu.shareParentSize.height));
 #endif
     bool bFound = addMergeHMVPCand(slice, mrgCtx, canFastExit
+#if IBC_SEPERATE_MODE==0
       , (mmvdList != 0 && mrgCandIdx != -1) ? (const int) mrgCandIdxIBC : mrgCandIdx
+#else
+      , mrgCandIdx
+#endif
       , maxNumMergeCandMin1, cnt, cnt, isAvailableSubPu, subPuMvpPos
+#if IBC_SEPERATE_MODE==0
       , mmvdList
+#endif
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+      , CU::isIBC(*pu.cu)
+#endif
 #if JVET_M0170_MRG_SHARELIST
       , isShared
 #endif
@@ -1218,6 +1621,9 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 
 #if JVET_L0090_PAIR_AVG
   // pairwise-average candidates
+#if IBC_SEPERATE_MODE_REDUCTION && CLEAN_getInterMergeCandidates==0
+  if (pu.cu->predMode == MODE_INTER)
+#endif
   {
     const int cutoff = std::min( cnt, 4 );
     const int end = cutoff * (cutoff - 1) / 2;
@@ -1353,7 +1759,11 @@ void PU::getInterMergeCandidates( const PredictionUnit &pu, MergeCtx& mrgCtx,
 
   int r = 0;
   int refcnt = 0;
+#if IBC_SEPERATE_MODE && CLEAN_getInterMergeCandidates==0
+  while (uiArrayAddr < maxNumMergeCand && CU::isIBC(*pu.cu) == false)
+#else
   while (uiArrayAddr < maxNumMergeCand)
+#endif
   {
 #if !JVET_L0090_PAIR_AVG
     isCandInter               [uiArrayAddr     ] = true;
@@ -1584,7 +1994,17 @@ bool PU::getColocatedMVP(const PredictionUnit &pu, const RefPicList &eRefPicList
   {
     return false;
   }
+#if IBC_SEPERATE_MODE//Todo: really need?
+  if (mi.isIBCmot)
+  {
+    return false;
+  }
+#endif
+#if IBC_SEPERATE_MODE
+  if (CU::isIBC(*pu.cu))
+#else
   if (eRefPicList == REF_PIC_LIST_0 && pu.cs->slice->getRefPic(eRefPicList, refIdx)->getPOC() == pu.cs->slice->getPOC())
+#endif
   {
     return false;
   }
@@ -1687,7 +2107,11 @@ void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred)
   //left
   const PredictionUnit *neibLeftPU = NULL;
   neibLeftPU = pu.cs->getPURestricted(posLB.offset(-1, 0), pu, pu.cs->chType);
+#if IBC_SEPERATE_MODE
+  left = (neibLeftPU) ? CU::isIBC(*neibLeftPU->cu) : 0;
+#else
   left = (neibLeftPU) ? neibLeftPU->cu->ibc : 0;
+#endif
 
   if (left)
   {
@@ -1699,7 +2123,11 @@ void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred)
   //above
   const PredictionUnit *neibAbovePU = NULL;
   neibAbovePU = pu.cs->getPURestricted(posRT.offset(0, -1), pu, pu.cs->chType);
+#if IBC_SEPERATE_MODE
+  above = (neibAbovePU) ? CU::isIBC(*neibAbovePU->cu) : 0;
+#else
   above = (neibAbovePU) ? neibAbovePU->cu->ibc : 0;
+#endif
 
   if (above)
   {
@@ -1711,7 +2139,11 @@ void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred)
   // Below Left predictor search
   const PredictionUnit *neibBelowLeftPU = NULL;
   neibBelowLeftPU = pu.cs->getPURestricted(posLB.offset(-1, 1), pu, pu.cs->chType);
+#if IBC_SEPERATE_MODE
+  unsigned int belowLeft = (neibBelowLeftPU) ? CU::isIBC(*neibBelowLeftPU->cu) : 0;
+#else
   unsigned int belowLeft = (neibBelowLeftPU) ? neibBelowLeftPU->cu->ibc : 0;
+#endif
 
   if (belowLeft)
   {
@@ -1724,7 +2156,11 @@ void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred)
   // Above Right predictor search
   const PredictionUnit *neibAboveRightPU = NULL;
   neibAboveRightPU = pu.cs->getPURestricted(posRT.offset(1, -1), pu, pu.cs->chType);
+#if IBC_SEPERATE_MODE
+  unsigned int aboveRight = (neibAboveRightPU) ? CU::isIBC(*neibAboveRightPU->cu) : 0;
+#else
   unsigned int aboveRight = (neibAboveRightPU) ? neibAboveRightPU->cu->ibc : 0;
+#endif
 
   if (aboveRight)
   {
@@ -1737,7 +2173,11 @@ void PU::getIbcMVPsEncOnly(PredictionUnit &pu, Mv* MvPred, int& nbPred)
   // Above Left predictor search
   const PredictionUnit *neibAboveLeftPU = NULL;
   neibAboveLeftPU = pu.cs->getPURestricted(posLT.offset(-1, -1), pu, pu.cs->chType);
+#if IBC_SEPERATE_MODE
+  unsigned int aboveLeft = (neibAboveLeftPU) ? CU::isIBC(*neibAboveLeftPU->cu) : 0;
+#else
   unsigned int aboveLeft = (neibAboveLeftPU) ? neibAboveLeftPU->cu->ibc : 0;
+#endif
 
   if (aboveLeft)
   {
@@ -1765,7 +2205,11 @@ bool PU::getDerivedBV(PredictionUnit &pu, const Mv& currentMv, Mv& derivedMv)
   const PredictionUnit *neibRefPU = NULL;
   neibRefPU = pu.cs->getPURestricted(pu.lumaPos().offset(offsetX, offsetY), pu, pu.cs->chType);
 
+#if IBC_SEPERATE_MODE
+  bool isIBC = (neibRefPU) ? CU::isIBC(*neibRefPU->cu) : 0;
+#else
   bool isIBC = (neibRefPU) ? neibRefPU->cu->ibc : 0;
+#endif
   if (isIBC)
   {
     derivedMv = neibRefPU->bv;
@@ -1773,6 +2217,168 @@ bool PU::getDerivedBV(PredictionUnit &pu, const Mv& currentMv, Mv& derivedMv)
   }
   return isIBC;
 }
+
+#if IBC_SEPERATE_FUNCTION
+/** Constructs a list of candidates for IBC AMVP (See specification, section "Derivation process for motion vector predictor candidates")
+* \param uiPartIdx
+* \param uiPartAddr
+* \param eRefPicList
+* \param iRefIdx
+* \param pInfo
+*/
+void PU::fillIBCMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AMVPInfo &amvpInfo)
+{
+  CodingStructure &cs = *pu.cs;
+
+  AMVPInfo *pInfo = &amvpInfo;
+
+  pInfo->numCand = 0;
+
+  if (refIdx < 0)
+  {
+    return;
+  }
+
+  //-- Get Spatial MV
+  Position posLT = pu.Y().topLeft();
+  Position posRT = pu.Y().topRight();
+  Position posLB = pu.Y().bottomLeft();
+
+  bool isScaledFlagLX = false; /// variable name from specification; true when the PUs below left or left are available (availableA0 || availableA1).
+  {
+    const PredictionUnit* tmpPU = cs.getPURestricted(posLB.offset(-1, 1), pu, pu.chType); // getPUBelowLeft(idx, partIdxLB);
+    isScaledFlagLX = tmpPU != NULL && CU::isIBC(*tmpPU->cu);
+    if (!isScaledFlagLX)
+    {
+      tmpPU = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType);
+      isScaledFlagLX = tmpPU != NULL && CU::isIBC(*tmpPU->cu);
+    }
+  }
+
+  // Left predictor search
+  if (isScaledFlagLX)
+  {
+    bool bAdded = addMVPCandUnscaled(pu, eRefPicList, refIdx, posLB, MD_BELOW_LEFT, *pInfo);
+
+    if (!bAdded)
+    {
+      bAdded = addMVPCandUnscaled(pu, eRefPicList, refIdx, posLB, MD_LEFT, *pInfo);
+    }
+  }
+
+  // Above predictor search
+  {
+    bool bAdded = addMVPCandUnscaled(pu, eRefPicList, refIdx, posRT, MD_ABOVE_RIGHT, *pInfo);
+
+    if (!bAdded)
+    {
+      bAdded = addMVPCandUnscaled(pu, eRefPicList, refIdx, posRT, MD_ABOVE, *pInfo);
+
+      if (!bAdded)
+      {
+        addMVPCandUnscaled(pu, eRefPicList, refIdx, posLT, MD_ABOVE_LEFT, *pInfo);
+      }
+    }
+  }
+
+  if (pu.cu->imv != 0)
+  {
+#if MODIFY_for_vtm4==0
+    unsigned imvShift = pu.cu->imv << 1;
+#if REMOVE_MV_ADAPT_PREC
+    imvShift += VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+#endif
+#endif
+    for (int i = 0; i < pInfo->numCand; i++)
+    {
+#if MODIFY_for_vtm4
+      pInfo->mvCand[i].roundToAmvrSignalPrecision(MV_PRECISION_INTERNAL, pu.cu->imv);
+#else
+      roundMV(pInfo->mvCand[i], imvShift);
+#endif
+    }
+  }
+
+  if (pInfo->numCand == 2)
+  {
+    if (pInfo->mvCand[0] == pInfo->mvCand[1])
+    {
+      pInfo->numCand = 1;
+    }
+  }
+
+  if (pInfo->numCand < AMVP_MAX_NUM_CANDS)
+  {
+#if IBC_SEPERATE_MODE
+    const int        currRefPOC = CU::isIBC(*pu.cu) ? cs.slice->getPOC() : cs.slice->getRefPic(eRefPicList, refIdx)->getPOC();
+#else
+    const int        currRefPOC = cs.slice->getRefPic(eRefPicList, refIdx)->getPOC();
+#endif
+    const RefPicList eRefPicList2nd = (eRefPicList == REF_PIC_LIST_0) ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
+    addAMVPHMVPCand(pu, eRefPicList, eRefPicList2nd, currRefPOC, *pInfo, pu.cu->imv);
+  }
+
+  if (pInfo->numCand > AMVP_MAX_NUM_CANDS)
+  {
+    pInfo->numCand = AMVP_MAX_NUM_CANDS;
+  }
+
+  while (pInfo->numCand < AMVP_MAX_NUM_CANDS)
+  {
+#if !REMOVE_MV_ADAPT_PREC && MODIFY_for_vtm4==0
+    const bool prec = pInfo->mvCand[pInfo->numCand].highPrec;
+    pInfo->mvCand[pInfo->numCand] = Mv(0, 0, prec);
+#else
+    pInfo->mvCand[pInfo->numCand] = Mv(0, 0);
+#endif
+    pInfo->numCand++;
+  }
+#if !REMOVE_MV_ADAPT_PREC && MODIFY_for_vtm4==0
+  if (pu.cs->sps->getSpsNext().getUseHighPrecMv())
+  {
+#endif
+    for (Mv &mv : pInfo->mvCand)
+    {
+#if MODIFY_for_vtm4//Todo : check
+      mv.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER);
+      mv.roundToAmvrSignalPrecision(MV_PRECISION_QUARTER, pu.cu->imv);
+#else
+#if REMOVE_MV_ADAPT_PREC
+      const int nShift = VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+      const int nOffset = 1 << (nShift - 1);
+      mv.hor = mv.hor >= 0 ? (mv.hor + nOffset) >> nShift : -((-mv.hor + nOffset) >> nShift);
+      mv.ver = mv.ver >= 0 ? (mv.ver + nOffset) >> nShift : -((-mv.ver + nOffset) >> nShift);
+#else
+      if (mv.highPrec) mv.setLowPrec();
+#endif
+#endif
+    }
+#if !REMOVE_MV_ADAPT_PREC && MODIFY_for_vtm4==0
+  }
+#endif
+#if MODIFY_for_vtm4==0//Todo : check
+  if (pu.cu->imv != 0)
+  {
+    unsigned imvShift = pu.cu->imv << 1;
+    for (int i = 0; i < pInfo->numCand; i++)
+    {
+      roundMV(pInfo->mvCand[i], imvShift);
+    }
+  }
+#endif
+#if !REMOVE_MV_ADAPT_PREC && MODIFY_for_vtm4==0
+  if (pu.cs->sps->getSpsNext().getUseHighPrecMv())
+  {
+    for (Mv &mv : pInfo->mvCand)
+    {
+      if (mv.highPrec) mv.setLowPrec();
+    }
+  }
+#endif
+}
+
+#endif
+
 /** Constructs a list of candidates for AMVP (See specification, section "Derivation process for motion vector predictor candidates")
 * \param uiPartIdx
 * \param uiPartAddr
@@ -1802,12 +2408,20 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in
 
   {
     const PredictionUnit* tmpPU = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType ); // getPUBelowLeft(idx, partIdxLB);
+#if IBC_SEPERATE_MODE    
+    isScaledFlagLX = tmpPU != NULL && !CU::isIntra(*tmpPU->cu);
+#else
     isScaledFlagLX = tmpPU != NULL && CU::isInter( *tmpPU->cu );
+#endif
 
     if( !isScaledFlagLX )
     {
       tmpPU = cs.getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
+#if IBC_SEPERATE_MODE
+      isScaledFlagLX = tmpPU != NULL && !CU::isIntra(*tmpPU->cu);
+#else
       isScaledFlagLX = tmpPU != NULL && CU::isInter( *tmpPU->cu );
+#endif
     }
   }
 
@@ -1878,7 +2492,11 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in
     }
   }
 
+#if IBC_SEPERATE_MODE && CLEAN_fillMvpCand==0
+  if (cs.slice->getEnableTMVPFlag() && CU::isInter(*pu.cu))
+#else
   if( cs.slice->getEnableTMVPFlag() )
+#endif
   {
     // Get Temporal Motion Predictor
     const int refIdx_Col = refIdx;
@@ -1949,7 +2567,11 @@ void PU::fillMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, const in
   }
   if (pInfo->numCand < AMVP_MAX_NUM_CANDS)
   {
+#if IBC_SEPERATE_MODE && CLEAN_fillMvpCand==0
+    const int        currRefPOC = CU::isIBC(*pu.cu) ? cs.slice->getPOC() : cs.slice->getRefPic(eRefPicList, refIdx)->getPOC();
+#else
     const int        currRefPOC = cs.slice->getRefPic(eRefPicList, refIdx)->getPOC();
+#endif
     const RefPicList eRefPicList2nd = (eRefPicList == REF_PIC_LIST_0) ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
     addAMVPHMVPCand(pu, eRefPicList, eRefPicList2nd, currRefPOC, *pInfo, pu.cu->imv);
   }
@@ -2351,14 +2973,22 @@ bool PU::addMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &eRefPic
 
   neibPU = cs.getPURestricted( neibPos, pu, pu.chType );
 
+#if IBC_SEPERATE_MODE
+  if (neibPU == NULL || neibPU->cu->predMode != pu.cu->predMode)
+#else
   if( neibPU == NULL || !CU::isInter( *neibPU->cu ) )
+#endif
   {
     return false;
   }
 
   const MotionInfo& neibMi        = neibPU->getMotionInfo( neibPos );
 
+#if IBC_SEPERATE_MODE
+  const int        currRefPOC     = CU::isIBC(*pu.cu) ? cs.slice->getPOC() : cs.slice->getRefPic(eRefPicList, iRefIdx)->getPOC();
+#else
   const int        currRefPOC     = cs.slice->getRefPic( eRefPicList, iRefIdx )->getPOC();
+#endif
   const RefPicList eRefPicList2nd = ( eRefPicList == REF_PIC_LIST_0 ) ? REF_PIC_LIST_1 : REF_PIC_LIST_0;
 
   for( int predictorSource = 0; predictorSource < 2; predictorSource++ ) // examine the indicated reference picture list, then if not available, examine the other list.
@@ -2366,7 +2996,11 @@ bool PU::addMVPCandUnscaled( const PredictionUnit &pu, const RefPicList &eRefPic
     const RefPicList eRefPicListIndex = ( predictorSource == 0 ) ? eRefPicList : eRefPicList2nd;
     const int        neibRefIdx       = neibMi.refIdx[eRefPicListIndex];
 
+#if IBC_SEPERATE_MODE
+    if (neibRefIdx >= 0 && currRefPOC == (CU::isIBC(*neibPU->cu) ? cs.slice->getPOC() : cs.slice->getRefPOC(eRefPicListIndex, neibRefIdx)))
+#else
     if( neibRefIdx >= 0 && currRefPOC == cs.slice->getRefPOC( eRefPicListIndex, neibRefIdx ) )
+#endif
     {
       info.mvCand[info.numCand++] = neibMi.mv[eRefPicListIndex];
       return true;
@@ -2414,7 +3048,11 @@ bool PU::addMVPCandWithScaling( const PredictionUnit &pu, const RefPicList &eRef
 
   neibPU = cs.getPURestricted( neibPos, pu, pu.chType );
 
+#if IBC_SEPERATE_MODE
+  if (neibPU == NULL || !CU::isInter(*neibPU->cu) || !CU::isInter(*pu.cu))
+#else
   if( neibPU == NULL || !CU::isInter( *neibPU->cu ) )
+#endif
   {
     return false;
   }
@@ -2466,7 +3104,12 @@ void PU::addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList,
 
   MotionInfo neibMi;
   int i = 0;
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+  int offset = CU::isIBC(*pu.cu) ? MAX_NUM_HMVP_CANDS : 0;
+  int num_avai_candInLUT = CU::isIBC(*pu.cu) ? slice.getAvailableLUTIBCMrgNum() : slice.getAvailableLUTMrgNum();
+#else
   int num_avai_candInLUT = slice.getAvailableLUTMrgNum();
+#endif
   int num_allowedCand = std::min(MAX_NUM_HMVP_AVMPCANDS, num_avai_candInLUT);
 
   for (int mrgIdx = 1; mrgIdx <= num_allowedCand; mrgIdx++)
@@ -2475,14 +3118,22 @@ void PU::addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList,
     {
       return;
     }
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+    neibMi = slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx + offset);
+#else
     neibMi = slice.getMotionInfoFromLUTs(num_avai_candInLUT - mrgIdx);
+#endif
 
     for (int predictorSource = 0; predictorSource < 2; predictorSource++) 
     {
       const RefPicList eRefPicListIndex = (predictorSource == 0) ? eRefPicList : eRefPicList2nd;
       const int        neibRefIdx = neibMi.refIdx[eRefPicListIndex];
 
+#if IBC_SEPERATE_MODE
+      if (neibRefIdx >= 0 && (CU::isIBC(*pu.cu) || (CU::isIBC(*pu.cu) == false && currRefPOC == slice.getRefPOC(eRefPicListIndex, neibRefIdx))))
+#else
       if (neibRefIdx >= 0 && currRefPOC == slice.getRefPOC(eRefPicListIndex, neibRefIdx))
+#endif
       {
         Mv pmv = neibMi.mv[eRefPicListIndex];
         if (imv != 0)
@@ -2739,7 +3390,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
   bool isAvailableSubPu = false;
   if ( enableSubPuMvp && slice.getEnableTMVPFlag() )
   {
-#if !JVET_M0409_ATMVP_FIX
+#if !JVET_M0409_ATMVP_FIX && IBC_SEPERATE_MODE==0
     int  cntIBC = 0;
 #endif
     MergeCtx mrgCtx = *affMrgCtx.mrgCtx;
@@ -2764,7 +3415,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
       mrgCtx.interDirNeighbours[pos] = miLeft.interDir;
 
       // get Mv from Left
-#if !JVET_M0409_ATMVP_FIX
+#if !JVET_M0409_ATMVP_FIX && IBC_SEPERATE_MODE==0
       if (puLeft->cu->ibc)
       {
         cntIBC++;
@@ -2791,7 +3442,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
         // get Inter Dir
         mrgCtx.interDirNeighbours[pos] = miAbove.interDir;
         // get Mv from Left
-#if !JVET_M0409_ATMVP_FIX
+#if !JVET_M0409_ATMVP_FIX && IBC_SEPERATE_MODE==0
         if (puAbove->cu->ibc)
         {
           cntIBC++;
@@ -2824,7 +3475,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
         // get Inter Dir
         mrgCtx.interDirNeighbours[pos] = miAboveRight.interDir;
         // get Mv from Left
-#if !JVET_M0409_ATMVP_FIX
+#if !JVET_M0409_ATMVP_FIX && IBC_SEPERATE_MODE==0
         if (puAboveRight->cu->ibc)
         {
           cntIBC++;
@@ -2857,7 +3508,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
         // get Inter Dir
         mrgCtx.interDirNeighbours[pos] = miBelowLeft.interDir;
         // get Mv from Bottom-Left
-#if !JVET_M0409_ATMVP_FIX
+#if !JVET_M0409_ATMVP_FIX && IBC_SEPERATE_MODE==0
         if (puLeftBottom->cu->ibc)
         {
           cntIBC++;
@@ -2876,7 +3527,7 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
 
     isAvailableSubPu = getInterMergeSubPuMvpCand( pu, mrgCtx, tmpLICFlag, pos
       , 0
-#if !JVET_M0409_ATMVP_FIX
+#if !JVET_M0409_ATMVP_FIX && IBC_SEPERATE_MODE==0
       , cntIBC
 #endif
     );
@@ -2966,7 +3617,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
         const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType );
 
         if ( puNeigh && CU::isInter( *puNeigh->cu )
+#if IBC_SEPERATE_MODE==0
           && !puNeigh->cu->ibc
+#endif
           )
         {
           isAvailable[0] = true;
@@ -2984,7 +3637,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
 
 
         if ( puNeigh && CU::isInter( *puNeigh->cu ) 
+#if IBC_SEPERATE_MODE==0
           && !puNeigh->cu->ibc
+#endif
           )
         {
           isAvailable[1] = true;
@@ -3002,7 +3657,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
 
 
         if ( puNeigh && CU::isInter( *puNeigh->cu ) 
+#if IBC_SEPERATE_MODE==0
           && !puNeigh->cu->ibc
+#endif
           )
         {
           isAvailable[2] = true;
@@ -3309,12 +3966,12 @@ void clipColPos(int& posX, int& posY, const PredictionUnit& pu)
 
 bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, bool& LICFlag, const int count
   , int mmvdList
-#if !JVET_M0409_ATMVP_FIX
+#if !JVET_M0409_ATMVP_FIX && IBC_SEPERATE_MODE==0
   , const int countIBC
 #endif
 )
 {
-#if !JVET_M0409_ATMVP_FIX
+#if !JVET_M0409_ATMVP_FIX && IBC_SEPERATE_MODE==0
   if (count == countIBC && pu.cs->slice->getSPS()->getSpsNext().getIBCMode())
     return false;
 #endif
@@ -3380,7 +4037,11 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b
   // derivation of center motion parameters from the collocated CU
   const MotionInfo &mi = pColPic->cs->getMotionInfo(centerPos);
 
+#if IBC_SEPERATE_MODE
+  if (mi.isInter && mi.isIBCmot == false)
+#else
   if (mi.isInter)
+#endif
   {
     for (unsigned currRefListId = 0; currRefListId < (bBSlice ? 2 : 1); currRefListId++)
     {
@@ -3432,7 +4093,12 @@ bool PU::getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx& mrgCtx, b
 
       mi.isInter = true;
       mi.sliceIdx = slice.getIndependentSliceIdx();
+#if IBC_SEPERATE_MODE
+      mi.isIBCmot = false;
+      if (colMi.isInter && colMi.isIBCmot == false)
+#else
       if (colMi.isInter && !((colMi.interDir == 1 || colMi.interDir == 3) && (pColPic->cs->slice->getRefPOC(REF_PIC_LIST_0, colMi.refIdx[0]) == pColPic->cs->slice->getPOC()) && pu.cs->sps->getSpsNext().getIBCMode()))
+#endif
       {
         for (unsigned currRefListId = 0; currRefListId < (bBSlice ? 2 : 1); currRefListId++)
         {
@@ -3479,7 +4145,12 @@ void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx )
   {
     MotionInfo mi;
 
+#if IBC_SEPERATE_MODE
+    mi.isInter = !CU::isIntra(*pu.cu);
+    mi.isIBCmot = CU::isIBC(*pu.cu);
+#else
     mi.isInter  = CU::isInter( *pu.cu );
+#endif
     mi.sliceIdx = pu.cu->slice->getIndependentSliceIdx();
 
     if( mi.isInter )
@@ -3491,7 +4162,11 @@ void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx )
         mi.mv[i]     = pu.mv[i];
         mi.refIdx[i] = pu.refIdx[i];
       }
+#if IBC_SEPERATE_MODE
+      if (mi.isIBCmot)
+#else
       if (pu.interDir == 1 && pu.cu->slice->getRefPOC(REF_PIC_LIST_0, pu.refIdx[0]) == pu.cu->slice->getPOC())
+#endif
       {
         mi.bv = pu.bv;
       }
@@ -3505,6 +4180,9 @@ void PU::spanMotionInfo( PredictionUnit &pu, const MergeCtx &mrgCtx )
         {
           MotionInfo &dest = mb.at( x, y );
           dest.isInter  = mi.isInter;
+#if IBC_SEPERATE_MODE
+          dest.isIBCmot = false;
+#endif
           dest.interDir = mi.interDir;
           dest.sliceIdx = mi.sliceIdx;
           for( int i = 0; i < NUM_REF_PIC_LIST_01; i++ )
@@ -3559,15 +4237,22 @@ void PU::applyImv( PredictionUnit& pu, MergeCtx &mrgCtx, InterPrediction *interP
       pu.mvd[0].changePrecisionAmvr( pu.cu->imv, MV_PRECISION_QUARTER);
       unsigned mvp_idx = pu.mvpIdx[0];
       AMVPInfo amvpInfo;
+#if IBC_SEPERATE_FUNCTION
+      if (CU::isIBC(*pu.cu))
+        PU::fillIBCMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[0], amvpInfo);
+      else
+#endif
       PU::fillMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[0], amvpInfo);
       pu.mvpNum[0] = amvpInfo.numCand;
       pu.mvpIdx[0] = mvp_idx;
       pu.mv    [0] = amvpInfo.mvCand[mvp_idx] + pu.mvd[0];
       pu.mv[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
+#if IBC_SEPERATE_MODE==0
       if (pu.interDir == 1 && pu.cs->slice->getRefPic(REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0])->getPOC() == pu.cs->slice->getPOC())
       {
         pu.cu->ibc = true;
       }
+#endif
     }
 
     if (pu.interDir != 1 /* PRED_L0 */)
@@ -3679,7 +4364,9 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl
   //left
   const PredictionUnit* puLeft = cs.getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
   const bool isAvailableA1 = puLeft && isDiffMER( pu, *puLeft ) && pu.cu != puLeft->cu && CU::isInter( *puLeft->cu )
+#if IBC_SEPERATE_MODE==0
     && !puLeft->cu->ibc
+#endif
     ;
   if( isAvailableA1 )
   {
@@ -3696,7 +4383,9 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl
   // above
   const PredictionUnit *puAbove = cs.getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType );
   bool isAvailableB1 = puAbove && isDiffMER( pu, *puAbove ) && pu.cu != puAbove->cu && CU::isInter( *puAbove->cu )
+#if IBC_SEPERATE_MODE==0
     && !puAbove->cu->ibc
+#endif
     ;
   if( isAvailableB1 )
   {
@@ -3717,7 +4406,9 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl
   // above right
   const PredictionUnit *puAboveRight = cs.getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
   bool isAvailableB0 = puAboveRight && isDiffMER( pu, *puAboveRight ) && CU::isInter( *puAboveRight->cu )
+#if IBC_SEPERATE_MODE==0
     && !puAboveRight->cu->ibc
+#endif
     ;
 
   if( isAvailableB0 )
@@ -3739,7 +4430,9 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl
   //left bottom
   const PredictionUnit *puLeftBottom = cs.getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
   bool isAvailableA0 = puLeftBottom && isDiffMER( pu, *puLeftBottom ) && CU::isInter( *puLeftBottom->cu )
+#if IBC_SEPERATE_MODE==0
     && !puLeftBottom->cu->ibc
+#endif
     ;
   if( isAvailableA0 )
   {
@@ -3760,7 +4453,9 @@ void PU::getTriangleMergeCandidates( const PredictionUnit &pu, MergeCtx& triangl
   // above left
   const PredictionUnit *puAboveLeft = cs.getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
   bool isAvailableB2 = puAboveLeft && isDiffMER( pu, *puAboveLeft ) && CU::isInter( *puAboveLeft->cu )
+#if IBC_SEPERATE_MODE==0
     && !puAboveLeft->cu->ibc
+#endif
     ;
 
   if( isAvailableB2 )
@@ -4175,6 +4870,11 @@ void CU::resetMVDandMV2Int( CodingUnit& cu, InterPrediction *interPred )
         Mv mv        = pu.mv[0];
         Mv mvPred;
         AMVPInfo amvpInfo;
+#if IBC_SEPERATE_FUNCTION
+        if (CU::isIBC(*pu.cu))
+          PU::fillIBCMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[0], amvpInfo);
+        else
+#endif
         PU::fillMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[0], amvpInfo);
         pu.mvpNum[0] = amvpInfo.numCand;
 
@@ -4284,6 +4984,13 @@ bool CU::isGBiIdxCoded( const CodingUnit &cu )
     return false;
   }
 
+#if IBC_SEPERATE_MODE
+  if (cu.predMode == MODE_IBC)
+  {
+    return false;
+  }
+#endif
+
   if( cu.predMode == MODE_INTRA || cu.cs->slice->isInterP() )
   {
     return false;
@@ -4523,8 +5230,13 @@ uint32_t TU::getCoefScanIdx(const TransformUnit &tu, const ComponentID &compID)
 #endif
 bool TU::hasCrossCompPredInfo( const TransformUnit &tu, const ComponentID &compID )
 {
+#if IBC_SEPERATE_MODE
+  return (isChroma(compID) && tu.cs->pps->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && TU::getCbf(tu, COMPONENT_Y) &&
+    (!CU::isIntra(*tu.cu) || PU::isChromaIntraModeCrossCheckMode(*tu.cs->getPU(tu.blocks[compID].pos(), toChannelType(compID)))));
+#else
   return ( isChroma(compID) && tu.cs->pps->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && TU::getCbf( tu, COMPONENT_Y ) &&
          ( CU::isInter(*tu.cu) || PU::isChromaIntraModeCrossCheckMode( *tu.cs->getPU( tu.blocks[compID].pos(), toChannelType( compID ) ) ) ) );
+#endif
 }
 
 uint32_t TU::getNumNonZeroCoeffsNonTS( const TransformUnit& tu, const bool bLuma, const bool bChroma )
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index 0b7c97f00b..50a40f28c6 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -57,6 +57,9 @@ namespace CU
 {
   bool isIntra                        (const CodingUnit &cu);
   bool isInter                        (const CodingUnit &cu);
+#if IBC_SEPERATE_MODE
+  bool isIBC                          (const CodingUnit &cu);
+#endif
   bool isRDPCMEnabled                 (const CodingUnit &cu);
   bool isLosslessCoded                (const CodingUnit &cu);
   uint32_t getIntraSizeIdx                (const CodingUnit &cu);
@@ -107,11 +110,17 @@ namespace PU
   void getInterMergeCandidates        (const PredictionUnit &pu, MergeCtx& mrgCtx,
     int mmvdList,
     const int& mrgCandIdx = -1 );
+#if IBC_SEPERATE_FUNCTION
+  void getIBCMergeCandidates          (const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx = -1);
+#endif
   void getInterMMVDMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const int& mrgCandIdx = -1);
   int getDistScaleFactor(const int &currPOC, const int &currRefPOC, const int &colPOC, const int &colRefPOC);
   bool isDiffMER                      (const PredictionUnit &pu, const PredictionUnit &pu2);
   bool getColocatedMVP                (const PredictionUnit &pu, const RefPicList &eRefPicList, const Position &pos, Mv& rcMv, const int &refIdx);
   void fillMvpCand                    (      PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AMVPInfo &amvpInfo );
+#if IBC_SEPERATE_FUNCTION
+  void fillIBCMvpCand                 (PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AMVPInfo &amvpInfo);
+#endif
   void fillAffineMvpCand              (      PredictionUnit &pu, const RefPicList &eRefPicList, const int &refIdx, AffineAMVPInfo &affiAMVPInfo);
   bool addMVPCandUnscaled             (const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &amvpInfo);
   bool addMVPCandWithScaling          (const PredictionUnit &pu, const RefPicList &eRefPicList, const int &iRefIdx, const Position &pos, const MvpDir &eDir, AMVPInfo &amvpInfo);
@@ -119,14 +128,21 @@ namespace PU
   bool xCheckSimilarMotion(const int mergeCandIndex, const int prevCnt, const MergeCtx mergeCandList, bool hasPruned[MRG_MAX_NUM_CANDS]);
 #if JVET_L0090_PAIR_AVG
   bool addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool canFastExit, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const int prevCnt, bool isAvailableSubPu, unsigned subPuMvpPos
+#if IBC_SEPERATE_MODE==0 
     , int mmvdList
+#endif
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+    , bool ibc_flag
+#endif
 #if JVET_M0170_MRG_SHARELIST
     , bool isShared
 #endif
   );
 #else
   bool addMergeHMVPCand(const Slice &slice, MergeCtx& mrgCtx, bool isCandInter[MRG_MAX_NUM_CANDS], bool canFastExit, const int& mrgCandIdx, const uint32_t maxNumMergeCandMin1, int &cnt, const int prevCnt, bool isAvailableSubPu, unsigned subPuMvpPos
+#if IBC_SEPERATE_MODE==0 
     , int mmvdList
+#endif
   );
 #endif
   void addAMVPHMVPCand(const PredictionUnit &pu, const RefPicList eRefPicList, const RefPicList eRefPicList2nd, const int currRefPOC, AMVPInfo &info, uint8_t imv);
@@ -143,7 +159,9 @@ namespace PU
   bool getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx &mrgCtx, bool& LICFlag, const int count
     , int mmvdList
 #if !JVET_M0409_ATMVP_FIX
+#if IBC_SEPERATE_MODE==0
     , const int countIBC
+#endif
 #endif
   );
   bool getInterMergeSubPuRecurCand(const PredictionUnit &pu, MergeCtx &mrgCtx, const int count);
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 7f57b25d50..eac3b1e0c2 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -885,7 +885,11 @@ bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx&
   }
 
   // skip flag
+#if IBC_SEPERATE_MODE
+  if ((!cs.slice->isIntra() || cs.slice->getSPS()->getSpsNext().getIBCMode()) && cu.Y().valid())
+#else
   if (!cs.slice->isIntra() && cu.Y().valid())
+#endif
   {
     cu_skip_flag( cu );
   }
@@ -948,12 +952,83 @@ void CABACReader::cu_skip_flag( CodingUnit& cu )
 {
   RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__SKIP_FLAG );
 
+#if IBC_SEPERATE_MODE
+#if IBC_SEPERATE_MODE_FIX
+  if (cu.slice->isIntra() && cu.cs->slice->getSPS()->getSpsNext().getIBCMode())
+#else
+  if (cu.slice->isIntra())
+#endif
+  {
+    cu.skip = false;
+    cu.rootCbf = false;
+    cu.predMode = MODE_INTRA;
+    //cu.partSize = SIZE_2Nx2N; //Todo
+    cu.mmvdSkip = false;
+
+    if (cu.lwidth() > IBC_MAX_CAND_SIZE || cu.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip
+    {
+
+    }
+    else
+    {
+      unsigned ctxId = DeriveCtx::CtxSkipFlag(cu);
+      unsigned skip = m_BinDecoder.decodeBin(Ctx::SkipFlag(ctxId));
+      if (skip)
+      {
+        cu.skip = true;
+        cu.rootCbf = false;
+        cu.predMode = MODE_IBC;
+        //cu.partSize = SIZE_2Nx2N;//Todo
+        cu.mmvdSkip = false;
+      }
+    }
+    return;
+  }
+#endif
+
   unsigned ctxId  = DeriveCtx::CtxSkipFlag(cu);
   unsigned skip   = m_BinDecoder.decodeBin( Ctx::SkipFlag(ctxId) );
 
   DTRACE( g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, skip ? 1 : 0 );
 
+#if IBC_SEPERATE_MODE
+#if IBC_SEPERATE_MODE_FIX
+  if (skip && cu.cs->slice->getSPS()->getSpsNext().getIBCMode())
+#else
+  if (skip)
+#endif
+  {
+    if (cu.lwidth() > IBC_MAX_CAND_SIZE || cu.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip
+    {
+      cu.predMode = MODE_INTER;
+    }
+    else
+    {
+      unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu);
+      if (m_BinDecoder.decodeBin(Ctx::IBCFlag(ctxidx)))
+      {
+        cu.skip = true;
+        cu.rootCbf = false;
+        cu.predMode = MODE_IBC;
+        //cu.partSize = SIZE_2Nx2N;//Todo
+        cu.mmvdSkip = false;
+      }
+      else
+      {
+        cu.predMode = MODE_INTER;
+      }
+      DTRACE(g_trace_ctx, D_SYNTAX, "ibc() ctx=%d cu.predMode=%d\n", ctxidx, cu.predMode);
+    }
+  }
+#if IBC_SEPERATE_MODE_FIX
+  if ((skip && CU::isInter(cu) && cu.cs->slice->getSPS()->getSpsNext().getIBCMode()) ||
+    (skip && !cu.cs->slice->getSPS()->getSpsNext().getIBCMode()))
+#else
+  if (skip && CU::isInter(cu))
+#endif
+#else
   if( skip )
+#endif
   {
     unsigned mmvdSkip = m_BinDecoder.decodeBin(Ctx::MmvdFlag(0));
     cu.mmvdSkip = mmvdSkip;
@@ -983,7 +1058,11 @@ void CABACReader::imv_mode( CodingUnit& cu, MergeCtx& mrgCtx )
 
   unsigned value = 0;
   unsigned ctxId = DeriveCtx::CtxIMVFlag( cu );
+#if IBC_SEPERATE_MODE
+  if (CU::isIBC(cu))
+#else
   if (cu.firstPU->interDir == 1 && cu.cs->slice->getRefPic(REF_PIC_LIST_0, cu.firstPU->refIdx[REF_PIC_LIST_0])->getPOC() == cu.cs->slice->getPOC()) // the first bin of IMV flag does need to be signaled in IBC block
+#endif
     value = 1;
   else
     value = m_BinDecoder.decodeBin( Ctx::ImvFlag( ctxId ) );
@@ -1004,6 +1083,72 @@ void CABACReader::pred_mode( CodingUnit& cu )
 {
   RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__PRED_MODE );
 
+#if IBC_SEPERATE_MODE//Todo : predmode ctx
+#if IBC_SEPERATE_MODE_FIX
+  if (cu.cs->slice->getSPS()->getSpsNext().getIBCMode())
+  {
+#endif
+    if (cu.cs->slice->isIntra())
+    {
+      cu.predMode = MODE_INTRA;
+      if (cu.lwidth() > IBC_MAX_CAND_SIZE || cu.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip
+      {
+
+      }
+      else
+      {
+        unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu);
+        if (m_BinDecoder.decodeBin(Ctx::IBCFlag(ctxidx)))
+        {
+          cu.predMode = MODE_IBC;
+        }
+      }
+    }
+    else
+    {
+#if JVET_M0502_PRED_MODE_CTX
+      if (m_BinDecoder.decodeBin(Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu))))
+#else
+      if (m_BinDecoder.decodeBin(Ctx::PredMode()))
+#endif
+      {
+        cu.predMode = MODE_INTRA;
+      }
+      else
+      {
+        cu.predMode = MODE_INTER;
+        if (cu.lwidth() > IBC_MAX_CAND_SIZE || cu.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip
+        {
+        }
+        else
+        {
+          unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu);
+          if (m_BinDecoder.decodeBin(Ctx::IBCFlag(ctxidx)))
+          {
+            cu.predMode = MODE_IBC;
+          }
+        }
+      }
+    }
+#if IBC_SEPERATE_MODE_FIX
+  }
+  else
+  {
+#if JVET_M0502_PRED_MODE_CTX
+    if (cu.cs->slice->isIntra() || m_BinDecoder.decodeBin(Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu))))
+#else
+    if (cu.cs->slice->isIntra() || m_BinDecoder.decodeBin(Ctx::PredMode()))
+#endif
+    {
+      cu.predMode = MODE_INTRA;
+    }
+    else
+    {
+      cu.predMode = MODE_INTER;
+    }
+  }
+#endif
+#else
 #if JVET_M0502_PRED_MODE_CTX
   if( cu.cs->slice->isIntra() || m_BinDecoder.decodeBin( Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)) ) )
 #else
@@ -1016,6 +1161,7 @@ void CABACReader::pred_mode( CodingUnit& cu )
   {
     cu.predMode = MODE_INTER;
   }
+#endif
 }
 
 void CABACReader::pcm_flag( CodingUnit& cu, Partitioner &partitioner )
@@ -1041,8 +1187,12 @@ void CABACReader::cu_pred_data( CodingUnit &cu )
   }
   if (!cu.Y().valid()) // dual tree chroma CU
   {
+#if IBC_SEPERATE_MODE
+    cu.predMode = MODE_IBC;
+#else
     cu.predMode = MODE_INTER;
     cu.ibc = true;
+#endif
     return;
   }
   MergeCtx mrgCtx;
@@ -1320,7 +1470,11 @@ void CABACReader::intra_chroma_pred_mode( PredictionUnit& pu )
 
 void CABACReader::cu_residual( CodingUnit& cu, Partitioner &partitioner, CUCtx& cuCtx )
 {
+#if IBC_SEPERATE_MODE
+  if (!CU::isIntra(cu))
+#else
   if( CU::isInter( cu ) )
+#endif
   {
     PredictionUnit& pu = *cu.firstPU;
     if( !pu.mergeFlag )
@@ -1404,6 +1558,14 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx )
   }
   if( pu.mergeFlag )
   {
+#if IBC_SEPERATE_MODE
+    if (CU::isIBC(*pu.cu))
+    {
+      merge_idx(pu);
+    }
+    else
+    {
+#endif
     subblock_merge_flag( *pu.cu );
     MHIntra_flag(pu);
     if (pu.mhIntraFlag)
@@ -1418,7 +1580,20 @@ void CABACReader::prediction_unit( PredictionUnit& pu, MergeCtx& mrgCtx )
     }
     else
     merge_data   ( pu );
+#if IBC_SEPERATE_MODE
+    }
+#endif
   }
+#if IBC_SEPERATE_MODE
+  else if (CU::isIBC(*pu.cu))
+  {
+    pu.interDir = 1;
+    pu.cu->affine = false;
+    ref_idx(pu, REF_PIC_LIST_0);
+    mvd_coding(pu.mvd[REF_PIC_LIST_0]);
+    mvp_flag(pu, REF_PIC_LIST_0);
+  }
+#endif
   else
   {
     inter_pred_idc( pu );
@@ -1568,6 +1743,15 @@ void CABACReader::merge_flag( PredictionUnit& pu )
   pu.mergeFlag = ( m_BinDecoder.decodeBin( Ctx::MergeFlag() ) );
 
   DTRACE( g_trace_ctx, D_SYNTAX, "merge_flag() merge=%d pos=(%d,%d) size=%dx%d\n", pu.mergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height );
+  
+#if IBC_SEPERATE_MODE
+  if (pu.mergeFlag && CU::isIBC(*pu.cu))
+  {
+    pu.mmvdMergeFlag = false;
+    return;
+  }
+#endif
+
   if (pu.mergeFlag)
   {
     pu.mmvdMergeFlag = (m_BinDecoder.decodeBin(Ctx::MmvdFlag(0)));
@@ -1781,6 +1965,18 @@ void CABACReader::ref_idx( PredictionUnit &pu, RefPicList eRefList )
 #endif
 
   int numRef  = pu.cs->slice->getNumRefIdx(eRefList);
+
+#if IBC_SEPERATE_MODE //Todo : check
+  if (eRefList == REF_PIC_LIST_0 && pu.cs->sps->getSpsNext().getIBCMode())
+  {
+    if (CU::isIBC(*pu.cu))
+    {
+      pu.refIdx[eRefList] = numRef;
+      return;
+    }
+  }
+#endif
+
   if( numRef <= 1 || !m_BinDecoder.decodeBin( Ctx::RefPic() ) )
   {
     if( numRef > 1 )
@@ -2426,6 +2622,9 @@ void CABACReader::mts_coding( TransformUnit& tu, ComponentID compID )
   const bool  tsAllowed = TU::isTSAllowed ( tu, compID );
   const bool mtsAllowed = TU::isMTSAllowed( tu, compID );
 
+#if IBC_SEPERATE_MODE//Todo
+#endif
+
   if( !mtsAllowed && !tsAllowed ) return;
 
   int symbol = 0;
@@ -2514,7 +2713,11 @@ void CABACReader::emt_cu_flag( CodingUnit& cu )
 {
   const CodingStructure &cs = *cu.cs;
 
+#if IBC_SEPERATE_MODE
+  if (!((cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra(cu)) || (cs.sps->getSpsNext().getUseInterEMT() && !CU::isIntra(cu))) || isChroma(cu.chType))
+#else
   if( !( ( cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra( cu ) ) || ( cs.sps->getSpsNext().getUseInterEMT() && CU::isInter( cu ) ) ) || isChroma( cu.chType ) )
+#endif
   {
     return;
   }
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index 6913f67f69..5571db00a8 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -102,6 +102,8 @@ void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea )
     for( auto &currCU : cs.traverseCUs( CS::getArea( cs, ctuArea, chType ), chType ) )
     {
 #if JVET_M0170_MRG_SHARELIST
+#if IBC_SEPERATE_MODE//Todo : check
+#endif
       if(sharePrepareCondition)
       {
         if ((currCU.shareParentPos.x >= 0) && (!(currCU.shareParentPos.x == prevTmpPos.x && currCU.shareParentPos.y == prevTmpPos.y)))
@@ -125,6 +127,9 @@ void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea )
       switch( currCU.predMode )
       {
       case MODE_INTER:
+#if IBC_SEPERATE_MODE
+      case MODE_IBC:
+#endif
         xReconInter( currCU );
         break;
       case MODE_INTRA:
@@ -364,10 +369,17 @@ void DecCu::xReconInter(CodingUnit &cu)
   m_pcIntraPred->geneIntrainterPred(cu);
 
   // inter prediction
+#if IBC_SEPERATE_MODE
+  CHECK(CU::isIBC(cu) && cu.firstPU->mhIntraFlag, "IBC and MHIntra cannot be used together");
+  CHECK(CU::isIBC(cu) && cu.affine, "IBC and Affine cannot be used together");
+  CHECK(CU::isIBC(cu) && cu.triangle, "IBC and triangle cannot be used together");
+  CHECK(CU::isIBC(cu) && cu.firstPU->mmvdMergeFlag, "IBC and MMVD cannot be used together");
+#else
   CHECK(cu.ibc && cu.firstPU->mhIntraFlag, "IBC and MHIntra cannot be used together");
   CHECK(cu.ibc && cu.affine, "IBC and Affine cannot be used together");
   CHECK(cu.ibc && cu.triangle, "IBC and triangle cannot be used together");
   CHECK(cu.ibc && cu.firstPU->mmvdMergeFlag, "IBC and MMVD cannot be used together");
+#endif
   const bool luma = cu.Y().valid();
   const bool chroma = cu.Cb().valid();
   if (luma && chroma)
@@ -557,6 +569,11 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
 #if JVET_M0170_MRG_SHARELIST
           pu.shareParentPos = cu.shareParentPos;
           pu.shareParentSize = cu.shareParentSize;
+#endif
+#if IBC_SEPERATE_FUNCTION//Todo : check
+          if (CU::isIBC(*pu.cu))
+            PU::getIBCMergeCandidates(pu, mrgCtx, pu.mergeIdx);
+          else
 #endif
             PU::getInterMergeCandidates(pu, mrgCtx, 0, pu.mergeIdx);
 #if !JVET_M0068_M0171_MMVD_CLEANUP
@@ -616,17 +633,60 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
             }
           }
         }
+#if IBC_SEPERATE_FUNCTION//Todo : check mv precision and partsize
+        else if (CU::isIBC(*pu.cu) && pu.interDir == 1)
+        {
+          AMVPInfo amvpInfo;
+          PU::fillIBCMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0], amvpInfo);
+
+          pu.mvpNum[REF_PIC_LIST_0] = amvpInfo.numCand;
+          Mv mvd = pu.mvd[REF_PIC_LIST_0];
+#if REUSE_CU_RESULTS
+          if (!cu.cs->pcv->isEncoder)
+#endif
+            mvd <<= 2;
+          pu.mv[REF_PIC_LIST_0] = amvpInfo.mvCand[pu.mvpIdx[REF_PIC_LIST_0]] + mvd;
+
+#if MODIFY_for_vtm4
+          pu.mv[REF_PIC_LIST_0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
+#else
+#if REMOVE_MV_ADAPT_PREC
+          pu.mv[REF_PIC_LIST_0].hor = pu.mv[REF_PIC_LIST_0].hor << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+          pu.mv[REF_PIC_LIST_0].ver = pu.mv[REF_PIC_LIST_0].ver << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+#else
+          if (pu.cs->sps->getSpsNext().getUseAffine())
+          {
+            pu.mv[REF_PIC_LIST_0].setHighPrec();
+          }
+#endif
+#endif
+        }
+#endif
         else
         {
           for ( uint32_t uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ )
           {
             RefPicList eRefList = RefPicList( uiRefListIdx );
+#if IBC_SEPERATE_MODE
+            if ((pu.cs->slice->getNumRefIdx(eRefList) > 0 || (eRefList == REF_PIC_LIST_0 && CU::isIBC(*pu.cu))) && (pu.interDir & (1 << uiRefListIdx)))
+#else
             if ( pu.cs->slice->getNumRefIdx( eRefList ) > 0 && ( pu.interDir & ( 1 << uiRefListIdx ) ) )
+#endif
             {
               AMVPInfo amvpInfo;
               PU::fillMvpCand(pu, eRefList, pu.refIdx[eRefList], amvpInfo);
               pu.mvpNum [eRefList] = amvpInfo.numCand;
+#if IBC_SEPERATE_FUNCTION==0//Todo : check
               Mv mvd = pu.mvd[eRefList];
+#if IBC_SEPERATE_MODE 
+              if (CU::isIBC(cu))
+              {
+#if REUSE_CU_RESULTS
+                if (!cu.cs->pcv->isEncoder)
+#endif
+                  mvd <<= 2;
+              }
+#else
               if (eRefList == REF_PIC_LIST_0 && pu.cs->slice->getRefPic(eRefList, pu.refIdx[eRefList])->getPOC() == pu.cs->slice->getPOC())
               {
                 pu.cu->ibc = true;
@@ -635,7 +695,11 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
 #endif
                   mvd.changePrecision(MV_PRECISION_INT, MV_PRECISION_QUARTER);
               }
+#endif
               pu.mv     [eRefList] = amvpInfo.mvCand[pu.mvpIdx[eRefList]] + mvd;
+#else
+              pu.mv[eRefList] = amvpInfo.mvCand[pu.mvpIdx[eRefList]] + pu.mvd[eRefList];
+#endif
               pu.mv[eRefList].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
             }
           }
diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index 09b493dd5c..1e5d151c2e 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -1238,10 +1238,12 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl
   m_cSliceDecoder.decompressSlice( pcSlice, &(nalu.getBitstream()) );
 
   m_bFirstSliceInPicture = false;
+#if IBC_SEPERATE_MODE==0
   if (pcSlice->getSPS()->getSpsNext().getIBCMode())
   {
     pcSlice->getPic()->longTerm = false;
   }
+#endif
   m_uiSliceSegmentIdx++;
 
   return false;
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 8e1725797c..fd44a0cda5 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -1748,10 +1748,21 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
         }
       }
     }
+
+#if IBC_SEPERATE_MODE 
+    if (!pcSlice->isIntra() || sps->getSpsNext().getIBCMode())
+    {
+      READ_UVLC(uiCode, "six_minus_max_num_merge_cand");
+      pcSlice->setMaxNumMergeCand(MRG_MAX_NUM_CANDS - uiCode);
+    }
+#endif
+
     if (!pcSlice->isIntra())
     {
+#if IBC_SEPERATE_MODE==0
       READ_UVLC(uiCode, "six_minus_max_num_merge_cand");
       pcSlice->setMaxNumMergeCand(MRG_MAX_NUM_CANDS - uiCode);
+#endif
 
       if ( sps->getSBTMVPEnabledFlag() && !sps->getSpsNext().getUseAffine() ) // ATMVP only
       {
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index 862ed98359..7f37a079a5 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -713,7 +713,11 @@ void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, C
   }
 
   // skip flag
+#if IBC_SEPERATE_MODE
+  if ((!cs.slice->isIntra() || cs.slice->getSPS()->getSpsNext().getIBCMode()) && cu.Y().valid())
+#else
   if (!cs.slice->isIntra() && cu.Y().valid())
+#endif
   {
     cu_skip_flag( cu );
   }
@@ -766,19 +770,123 @@ void CABACWriter::cu_transquant_bypass_flag( const CodingUnit& cu )
 void CABACWriter::cu_skip_flag( const CodingUnit& cu )
 {
   unsigned ctxId = DeriveCtx::CtxSkipFlag( cu );
+
+#if IBC_SEPERATE_MODE
+#if IBC_SEPERATE_MODE_FIX
+  if (cu.slice->isIntra() && cu.cs->slice->getSPS()->getSpsNext().getIBCMode())
+#else
+  if (cu.slice->isIntra())
+#endif
+  {
+    if (cu.lwidth() > IBC_MAX_CAND_SIZE || cu.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip
+    {
+    }
+    else
+    {
+      m_BinEncoder.encodeBin((cu.skip), Ctx::SkipFlag(ctxId));
+    }
+    DTRACE(g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, cu.skip ? 1 : 0);
+    return;
+  }
+#endif
+
   m_BinEncoder.encodeBin( ( cu.skip ), Ctx::SkipFlag( ctxId ) );
 
   DTRACE( g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, cu.skip ? 1 : 0 );
+#if IBC_SEPERATE_MODE
+#if IBC_SEPERATE_MODE_FIX
+  if (cu.skip && cu.cs->slice->getSPS()->getSpsNext().getIBCMode())
+#else
+  if (cu.skip)
+#endif
+  {
+    if (cu.lwidth() > IBC_MAX_CAND_SIZE || cu.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip
+    {
+
+    }
+    else
+    {
+      unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu);
+      m_BinEncoder.encodeBin(CU::isIBC(cu) ? 1 : 0, Ctx::IBCFlag(ctxidx));
+      DTRACE(g_trace_ctx, D_SYNTAX, "ibc() ctx=%d cu.predMode=%d\n", ctxidx, cu.predMode);
+    }
+
+    if (CU::isInter(cu))
+    {
+      m_BinEncoder.encodeBin(cu.mmvdSkip, Ctx::MmvdFlag(0));
+      DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_cu_skip_flag() ctx=%d mmvd_skip=%d\n", 0, cu.mmvdSkip ? 1 : 0);
+    }
+  }
+#if IBC_SEPERATE_MODE_FIX
+  if (cu.skip && !cu.cs->slice->getSPS()->getSpsNext().getIBCMode())
+  {
+    m_BinEncoder.encodeBin(cu.mmvdSkip, Ctx::MmvdFlag(0));
+    DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_cu_skip_flag() ctx=%d mmvd_skip=%d\n", 0, cu.mmvdSkip ? 1 : 0);
+  }
+#endif
+#else
   if (cu.skip)
   {
     m_BinEncoder.encodeBin(cu.mmvdSkip, Ctx::MmvdFlag(0));
     DTRACE(g_trace_ctx, D_SYNTAX, "mmvd_cu_skip_flag() ctx=%d mmvd_skip=%d\n", 0, cu.mmvdSkip ? 1 : 0);
   }
+#endif
 }
 
 
 void CABACWriter::pred_mode( const CodingUnit& cu )
 {
+#if IBC_SEPERATE_MODE_FIX
+  if (cu.cs->slice->getSPS()->getSpsNext().getIBCMode())
+  {
+#endif
+#if IBC_SEPERATE_MODE//Todo : check ctx
+    if (cu.cs->slice->isIntra())
+    {
+      if (cu.lwidth() > IBC_MAX_CAND_SIZE || cu.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip
+      {
+      }
+      else
+      {
+        unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu);
+        m_BinEncoder.encodeBin(CU::isIBC(cu), Ctx::IBCFlag(ctxidx));
+      }
+    }
+    else
+    {
+#if JVET_M0502_PRED_MODE_CTX
+      m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)));
+#else
+      m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode());
+#endif
+      if (!CU::isIntra(cu))
+      {
+        if (cu.lwidth() > IBC_MAX_CAND_SIZE || cu.lheight() > IBC_MAX_CAND_SIZE) // currently only check 32x32 and below block for ibc merge/skip
+        {
+        }
+        else
+        {
+          unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu);
+          m_BinEncoder.encodeBin(CU::isIBC(cu), Ctx::IBCFlag(ctxidx));
+        }
+      }
+    }
+#if IBC_SEPERATE_MODE_FIX
+  }
+  else
+  {
+    if (cu.cs->slice->isIntra())
+    {
+      return;
+    }
+#if JVET_M0502_PRED_MODE_CTX
+    m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)));
+#else
+    m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode());
+#endif
+  }
+#endif
+#else
   if( cu.cs->slice->isIntra() )
   {
     return;
@@ -788,6 +896,7 @@ void CABACWriter::pred_mode( const CodingUnit& cu )
 #else
   m_BinEncoder.encodeBin( ( CU::isIntra( cu ) ), Ctx::PredMode() );
 #endif
+#endif
 }
 
 void CABACWriter::pcm_data( const CodingUnit& cu, Partitioner& partitioner  )
@@ -1221,7 +1330,11 @@ void CABACWriter::intra_chroma_pred_mode( const PredictionUnit& pu )
 
 void CABACWriter::cu_residual( const CodingUnit& cu, Partitioner& partitioner, CUCtx& cuCtx )
 {
+#if IBC_SEPERATE_MODE
+  if (!CU::isIntra(cu))
+#else
   if( CU::isInter( cu ) )
+#endif
   {
     PredictionUnit& pu = *cu.firstPU;
     if( !pu.mergeFlag )
@@ -1310,6 +1423,13 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu )
   }
   if( pu.mergeFlag )
   {
+#if IBC_SEPERATE_MODE
+    if (CU::isIBC(*pu.cu))
+    {
+      merge_idx(pu);
+      return;
+    }
+#endif
     subblock_merge_flag( *pu.cu );
     MHIntra_flag( pu );
     if ( pu.mhIntraFlag )
@@ -1324,6 +1444,14 @@ void CABACWriter::prediction_unit( const PredictionUnit& pu )
     else
     merge_idx    ( pu );
   }
+#if IBC_SEPERATE_MODE
+  else if (CU::isIBC(*pu.cu))
+  {
+    ref_idx(pu, REF_PIC_LIST_0);
+    mvd_coding(pu.mvd[REF_PIC_LIST_0], pu.cu->imv);
+    mvp_flag(pu, REF_PIC_LIST_0);
+  }
+#endif
   else
   {
     inter_pred_idc( pu );
@@ -1436,6 +1564,14 @@ void CABACWriter::merge_flag( const PredictionUnit& pu )
   m_BinEncoder.encodeBin( pu.mergeFlag, Ctx::MergeFlag() );
 
   DTRACE( g_trace_ctx, D_SYNTAX, "merge_flag() merge=%d pos=(%d,%d) size=%dx%d\n", pu.mergeFlag ? 1 : 0, pu.lumaPos().x, pu.lumaPos().y, pu.lumaSize().width, pu.lumaSize().height );
+  
+#if IBC_SEPERATE_MODE
+  if (pu.mergeFlag && CU::isIBC(*pu.cu))
+  {
+    return;
+  }
+#endif
+
   if (pu.mergeFlag)
   {
     m_BinEncoder.encodeBin(pu.mmvdMergeFlag, Ctx::MmvdFlag(0));
@@ -1459,7 +1595,11 @@ void CABACWriter::imv_mode( const CodingUnit& cu )
   }
 
   unsigned ctxId = DeriveCtx::CtxIMVFlag( cu );
+#if IBC_SEPERATE_MODE
+  if (CU::isIBC(cu) == false)
+#else
   if (!(cu.firstPU->interDir == 1 && cu.cs->slice->getRefPic(REF_PIC_LIST_0, cu.firstPU->refIdx[REF_PIC_LIST_0])->getPOC() == cu.cs->slice->getPOC())) // the first bin of IMV flag does need to be signaled in IBC block
+#endif
     m_BinEncoder.encodeBin( ( cu.imv > 0 ), Ctx::ImvFlag( ctxId ) );
   DTRACE( g_trace_ctx, D_SYNTAX, "imv_mode() value=%d ctx=%d\n", (cu.imv > 0), ctxId );
 
@@ -1651,6 +1791,15 @@ void CABACWriter::ref_idx( const PredictionUnit& pu, RefPicList eRefList )
 #endif
 
   int numRef  = pu.cs->slice->getNumRefIdx(eRefList);
+
+#if IBC_SEPERATE_MODE
+  if (eRefList == REF_PIC_LIST_0 && pu.cs->sps->getSpsNext().getIBCMode())
+  {
+    if (CU::isIBC(*pu.cu))
+      return;
+  }
+#endif
+
   if( numRef <= 1 )
   {
     return;
@@ -2248,6 +2397,9 @@ void CABACWriter::mts_coding( const TransformUnit& tu, ComponentID compID )
   const bool  tsAllowed = TU::isTSAllowed ( tu, compID );
   const bool mtsAllowed = TU::isMTSAllowed( tu, compID );
 
+#if IBC_SEPERATE_MODE//Todo : check
+#endif
+
   if( !mtsAllowed && !tsAllowed ) return;
 
   int symbol  = 0;
@@ -2325,7 +2477,11 @@ void CABACWriter::emt_cu_flag( const CodingUnit& cu )
 {
   const CodingStructure& cs = *cu.cs;
 
+#if IBC_SEPERATE_MODE
+  if (!((cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra(cu)) || (cs.sps->getSpsNext().getUseInterEMT() && !CU::isIntra(cu))) || isChroma(cu.chType))
+#else
   if( !( ( cs.sps->getSpsNext().getUseIntraEMT() && CU::isIntra( cu ) ) || ( cs.sps->getSpsNext().getUseInterEMT() && CU::isInter( cu ) ) ) || isChroma( cu.chType ) )
+#endif
   {
     return;
   }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 363af63c23..b21bcecc28 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -103,6 +103,22 @@ void EncCu::create( EncCfg* encCfg )
         m_pTempMotLUTs[w][h] = new LutMotionCand ;
         m_pBestMotLUTs[w][h] = new LutMotionCand ;
         m_pSplitTempMotLUTs[w][h] = new LutMotionCand;
+#if IBC_SEPERATE_MODE && IBC_SEPERATE_MODE_REDUCTION==0
+        m_pSplitTempMotLUTs[w][h]->currCnt = 0;
+        m_pSplitTempMotLUTs[w][h]->currCntIBC = 0;
+        m_pSplitTempMotLUTs[w][h]->motionCand = nullptr;
+        m_pSplitTempMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2];
+
+        m_pTempMotLUTs[w][h]->currCnt = 0;
+        m_pTempMotLUTs[w][h]->currCntIBC = 0;
+        m_pTempMotLUTs[w][h]->motionCand = nullptr;
+        m_pTempMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2];
+
+        m_pBestMotLUTs[w][h]->currCnt = 0;
+        m_pBestMotLUTs[w][h]->currCntIBC = 0;
+        m_pBestMotLUTs[w][h]->motionCand = nullptr;
+        m_pBestMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS * 2];
+#else
         m_pSplitTempMotLUTs[w][h]->currCnt = 0;
         m_pSplitTempMotLUTs[w][h]->motionCand = nullptr;
         m_pSplitTempMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS];
@@ -114,6 +130,7 @@ void EncCu::create( EncCfg* encCfg )
         m_pBestMotLUTs[w][h]->currCnt = 0;
         m_pBestMotLUTs[w][h]->motionCand = nullptr;
         m_pBestMotLUTs[w][h]->motionCand = new MotionInfo[MAX_NUM_HMVP_CANDS];
+#endif
       }
       else
       {
@@ -343,7 +360,11 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign
       m_ctuIbcSearchRangeX >>= 1;
       m_ctuIbcSearchRangeY >>= 1;
     }
+#if IBC_SEPERATE_MODE
+    if (cs.slice->getNumRefIdx(REF_PIC_LIST_0) > 0)
+#else
     if (cs.slice->getNumRefIdx(REF_PIC_LIST_0) > 1)
+#endif
     {
       m_ctuIbcSearchRangeX >>= 1;
       m_ctuIbcSearchRangeY >>= 1;
@@ -620,7 +641,11 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par
   const unsigned wIdx = gp_sizeIdxInfo->idxFrom( partitioner.currArea().lwidth()  );
 
   const UnitArea currCsArea = clipArea( CS::getArea( *bestCS, bestCS->area, partitioner.chType ), *tempCS->picture );
+#if IBC_SEPERATE_MODE 
+  if (m_pImvTempCS && (!slice.isIntra() || slice.getSPS()->getSpsNext().getIBCMode()))
+#else
   if( m_pImvTempCS && !slice.isIntra() )
+#endif
   {
     tempCS->initSubStructure( *m_pImvTempCS[wIdx], partitioner.chType, partitioner.currArea(), false );
   }
@@ -645,7 +670,11 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par
     m_modeCtrl->finishCULevel( partitioner );
     return;
   }
+#if IBC_SEPERATE_MODE
+  if ((!slice.isIntra() || slice.getSPS()->getSpsNext().getIBCMode())
+#else
   if (!slice.isIntra()
+#endif
     && tempCS->chType == CHANNEL_TYPE_LUMA
     )
   {
@@ -785,9 +814,17 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par
 
   // QP from last processed CU for further processing
   bestCS->prevQP[partitioner.chType] = bestCS->cus.back()->qp;
+#if IBC_SEPERATE_MODE
+  if ((!slice.isIntra() || slice.getSPS()->getSpsNext().getIBCMode())
+#else
   if (!slice.isIntra() 
+#endif
     && bestCS->chType == CHANNEL_TYPE_LUMA
+#if IBC_SEPERATE_MODE
+    && bestCS->cus.size() == 1 && (bestCS->cus.back()->predMode == MODE_INTER || bestCS->cus.back()->predMode == MODE_IBC)
+#else
     && bestCS->cus.size() == 1 && bestCS->cus.back()->predMode == MODE_INTER 
+#endif
     && bestCS->area.Y() == (*bestCS->cus.back()).Y()
     )
   {
@@ -1347,7 +1384,11 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS,
   if (isAffMVInfoSaved)
     m_pcInterSearch->addAffMVInfo(tmpMVInfo);
 
+#if IBC_SEPERATE_MODE
+  if ((!slice.isIntra() || slice.getSPS()->getSpsNext().getIBCMode())
+#else
   if (!slice.isIntra()
+#endif
     && tempCS->chType == CHANNEL_TYPE_LUMA
     )
   {
@@ -1467,7 +1508,11 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
       m_CABACEstimator->cu_transquant_bypass_flag( cu );
     }
 
+#if IBC_SEPERATE_MODE
+    if ((!cu.cs->slice->isIntra() || cu.cs->slice->getSPS()->getSpsNext().getIBCMode())
+#else
     if( !cu.cs->slice->isIntra() 
+#endif
       && cu.Y().valid()
       )
     {
@@ -1553,7 +1598,11 @@ void EncCu::xCheckIntraPCM(CodingStructure *&tempCS, CodingStructure *&bestCS, P
     m_CABACEstimator->cu_transquant_bypass_flag( cu );
   }
 
+#if IBC_SEPERATE_MODE
+  if ((!cu.cs->slice->isIntra() || cu.cs->slice->getSPS()->getSpsNext().getIBCMode())
+#else
   if( !cu.cs->slice->isIntra() 
+#endif
     && cu.Y().valid()
     )
   {
@@ -1829,16 +1878,20 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       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) );
+#if IBC_SEPERATE_MODE==0
       uint32_t ibcCand = 0;
       uint32_t numValidMv = mergeCtx.numValidMergeCand;
+#endif
       for( uint32_t uiMergeCand = 0; uiMergeCand < mergeCtx.numValidMergeCand; uiMergeCand++ )
       {
+#if IBC_SEPERATE_MODE==0
         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())
         {
           ibcCand++;
           numValidMv--;
           continue;
         }
+#endif
         mergeCtx.setMergeInfo( pu, uiMergeCand );
 
         PU::spanMotionInfo( pu, mergeCtx );
@@ -1877,13 +1930,18 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
             swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);
           }
         }
+#if IBC_SEPERATE_MODE==0
         CHECK(std::min(uiMergeCand + 1 - ibcCand, uiNumMrgSATDCand) != RdModeList.size(), "");
+#else
+        CHECK(std::min(uiMergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), "");
+#endif
       }
+#if IBC_SEPERATE_MODE==0
       if (numValidMv < uiNumMrgSATDCand)
         uiNumMrgSATDCand = numValidMv;
       if (numValidMv == 0)
         return;
-
+#endif
 
       if (isIntrainterEnabled)
       {
@@ -1900,11 +1958,19 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 
         // save the to-be-tested merge candidates
         uint32_t MHIntraMergeCand[NUM_MRG_SATD_CAND];
+#if IBC_SEPERATE_MODE==0
         for (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, (const int) uiNumMrgSATDCand); mergeCnt++)
+#else
+        for (uint32_t mergeCnt = 0; mergeCnt < NUM_MRG_SATD_CAND; mergeCnt++)
+#endif
         {
           MHIntraMergeCand[mergeCnt] = RdModeList[mergeCnt];
         }
+#if IBC_SEPERATE_MODE==0
         for (uint32_t mergeCnt = 0; mergeCnt < std::min( std::min(NUM_MRG_SATD_CAND, (const int)uiNumMrgSATDCand), 4); mergeCnt++)
+#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);
@@ -2096,12 +2162,13 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
     {
       uint32_t uiMergeCand = RdModeList[uiMrgHADIdx];
 
-
+#if IBC_SEPERATE_MODE==0
       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;
         }
+#endif
 
       if (uiNoResidualPass != 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)) // intrainter does not support skip mode
       {
@@ -2784,8 +2851,12 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
     // first get merge candidates
     CodingUnit cu(tempCS->area);
     cu.cs = tempCS;
+#if IBC_SEPERATE_MODE
+    cu.predMode = MODE_IBC;
+#else
     cu.predMode = MODE_INTER;
     cu.ibc = true;
+#endif
     cu.slice = tempCS->slice;
 #if HEVC_TILES_WPP
     cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
@@ -2800,9 +2871,13 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
     pu.shareParentPos = tempCS->sharedBndPos;
     pu.shareParentSize = tempCS->sharedBndSize;
 #endif
+#if IBC_SEPERATE_FUNCTION//Todo : check sharelist
+    PU::getIBCMergeCandidates(pu, mergeCtx);
+#else
     PU::getInterMergeCandidates(pu, mergeCtx
       , 0
     );
+#endif
   }
 
   int candHasNoResidual[MRG_MAX_NUM_CANDS];
@@ -2833,8 +2908,12 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
 #endif
       cu.skip = false;
+#if IBC_SEPERATE_MODE
+      cu.predMode = MODE_IBC;
+#else
       cu.predMode = MODE_INTER;
       cu.ibc = true;
+#endif
       cu.transQuantBypass = encTestMode.lossless;
       cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
       cu.qp = encTestMode.qp;
@@ -2853,6 +2932,7 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       int numValidBv = mergeCtx.numValidMergeCand;
       for (unsigned int mergeCand = 0; mergeCand < mergeCtx.numValidMergeCand; mergeCand++)
       {
+#if IBC_SEPERATE_MODE==0
         if (mergeCtx.interDirNeighbours[mergeCand] != 1)
         {
           numValidBv--;
@@ -2863,6 +2943,7 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
           numValidBv--;
           continue;
         }
+#endif
         mergeCtx.setMergeInfo(pu, mergeCand); // set bv info in merge mode
         const int cuPelX = pu.Y().x;
         const int cuPelY = pu.Y().y;
@@ -2932,6 +3013,7 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
     for (unsigned int mrgHADIdx = 0; mrgHADIdx < numMrgSATDCand; mrgHADIdx++)
     {
       unsigned int mergeCand = RdModeList[mrgHADIdx];
+#if IBC_SEPERATE_MODE==0
       if (mergeCtx.interDirNeighbours[mergeCand] != 1)
       {
         continue;
@@ -2940,6 +3022,7 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
       {
         continue;
       }
+#endif
       if (!(numResidualPass == 1 && candHasNoResidual[mergeCand] == 1))
       {
         if (!(bestIsSkip && (numResidualPass == 0)))
@@ -2970,8 +3053,12 @@ void EncCu::xCheckRDCostIBCModeMerge2Nx2N(CodingStructure *&tempCS, CodingStruct
             cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
 #endif
             cu.skip = false;
+#if IBC_SEPERATE_MODE
+            cu.predMode = MODE_IBC;
+#else
             cu.predMode = MODE_INTER;
             cu.ibc = true;
+#endif
             cu.transQuantBypass = encTestMode.lossless;
             cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
             cu.qp = encTestMode.qp;
@@ -3048,11 +3135,17 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
     cu.tileIdx = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
 #endif
     cu.skip = false;
+#if IBC_SEPERATE_MODE
+    cu.predMode = MODE_IBC;
+#else
     cu.predMode = MODE_INTER;
+#endif
     cu.transQuantBypass = encTestMode.lossless;
     cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
     cu.qp = encTestMode.qp;
+#if IBC_SEPERATE_MODE==0
     cu.ibc = true;
+#endif
     cu.imv = 0;
 
     CU::addPUs(cu);
@@ -3065,8 +3158,11 @@ void EncCu::xCheckRDCostIBCMode(CodingStructure *&tempCS, CodingStructure *&best
     pu.intraDir[1] = PLANAR_IDX; // set intra pred for ibc block
 
     pu.interDir = 1; // use list 0 for IBC mode
+#if IBC_SEPERATE_MODE 
+    pu.refIdx[REF_PIC_LIST_0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0); // last idx in the list
+#else
     pu.refIdx[REF_PIC_LIST_0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0) - 1; // last idx in the list
-
+#endif
 
     if (partitioner.chType == CHANNEL_TYPE_LUMA)
     {
diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp
index bc863bb6c7..d99bd39b2f 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -1456,10 +1456,12 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
     {
       pcSlice->setSliceType(I_SLICE);
     }
+#if IBC_SEPERATE_MODE ==0
     if (pcSlice->getSliceType() == I_SLICE && pcSlice->getSPS()->getSpsNext().getIBCMode())
     {
       pcSlice->setSliceType(P_SLICE);
     }
+#endif
     // Set the nal unit type
     pcSlice->setNalUnitType(getNalUnitType(pocCurr, m_iLastIDR, isField));
     if(pcSlice->getTemporalLayerNonReferenceFlag())
@@ -1630,6 +1632,7 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
     if (pcPic->cs->sps->getSpsNext().getUseCompositeRef() && getPrepareLTRef()) {
       arrangeCompositeReference(pcSlice, rcListPic, pocCurr);
     }
+#if IBC_SEPERATE_MODE==0
     if (pcSlice->getSPS()->getSpsNext().getIBCMode())
     {
       if (m_pcCfg->getIntraPeriod() > 0 && pcSlice->getPOC() % m_pcCfg->getIntraPeriod() == 0)
@@ -1640,6 +1643,7 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
 
       pcSlice->setNumRefIdx(REF_PIC_LIST_0, pcSlice->getNumRefIdx(REF_PIC_LIST_0) + 1);
     }
+#endif
     //  Set reference list
     pcSlice->setRefPicList ( rcListPic );
 
@@ -1696,10 +1700,12 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
     {
       pcSlice->setSliceType ( P_SLICE );
     }
+#if IBC_SEPERATE_MODE==0
     if (pcSlice->getSPS()->getSpsNext().getIBCMode() && pcSlice->getNumRefIdx(REF_PIC_LIST_0) == 1)
     {
       m_pcSliceEncoder->setEncCABACTableIdx(P_SLICE);
     }
+#endif
     xUpdateRasInit( pcSlice );
 
     // Do decoding refresh marking if any
@@ -1800,6 +1806,7 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
     bool bGPBcheck=false;
     if ( pcSlice->getSliceType() == B_SLICE)
     {
+#if IBC_SEPERATE_MODE==0
       if (pcSlice->getSPS()->getSpsNext().getIBCMode())
       {
         if (pcSlice->getNumRefIdx(RefPicList(0)) - 1 == pcSlice->getNumRefIdx(RefPicList(1)))
@@ -1816,6 +1823,7 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
         }
       }
       else
+#endif
       if ( pcSlice->getNumRefIdx(RefPicList( 0 ) ) == pcSlice->getNumRefIdx(RefPicList( 1 ) ) )
       {
         bGPBcheck=true;
@@ -2498,7 +2506,9 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
     DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 0 ) ) );
 
     pcPic->reconstructed = true;
+#if IBC_SEPERATE_MODE ==0
     pcPic->longTerm = false;
+#endif
     m_bFirst = false;
     m_iNumPicCoded++;
     if (!(pcPic->cs->sps->getSpsNext().getUseCompositeRef() && isEncodeLtRef))
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index 56f49fc862..28fe9244e6 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1395,11 +1395,13 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps)
     }
   }
   CHECK(!(bestPos <= 15), "Unspecified error");
+#if IBC_SEPERATE_MODE==0
   if (sps.getSpsNext().getIBCMode())
   {
     pps.setNumRefIdxL0DefaultActive(bestPos + 1);
   }
   else
+#endif
     pps.setNumRefIdxL0DefaultActive(bestPos);
   pps.setNumRefIdxL1DefaultActive(bestPos);
   pps.setTransquantBypassEnabledFlag(getTransquantBypassEnabledFlag());
diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp
index 5c9aeb9b77..7aa24eb395 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.cpp
+++ b/source/Lib/EncoderLib/EncModeCtrl.cpp
@@ -801,7 +801,11 @@ bool BestEncInfoCache::isValid( const CodingStructure& cs, const Partitioner& pa
     , encInfo.pu, (cs.picture->Y().width), (cs.picture->Y().height)
 #endif
 ) 
+#if IBC_SEPERATE_MODE
+    || CU::isIBC(encInfo.cu)
+#else
     || encInfo.cu.ibc
+#endif
     )
   {
     return false;
@@ -1280,7 +1284,11 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
       return false;
     }
 
+#if IBC_SEPERATE_MODE
+    if (m_pcEncCfg->getUsePbIntraFast() && (!cs.slice->isIntra() || cs.slice->getSPS()->getSpsNext().getIBCMode()) && !interHadActive(cuECtx) && cuECtx.bestCU && !CU::isIntra(*cuECtx.bestCU))
+#else
     if( m_pcEncCfg->getUsePbIntraFast() && !cs.slice->isIntra() && !interHadActive( cuECtx ) && cuECtx.bestCU && CU::isInter( *cuECtx.bestCU ) )
+#endif
     {
       return false;
     }
@@ -1291,7 +1299,11 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
     CHECK( !slice.isIntra() && !cuECtx.bestTU, "No possible non-intra encoding for a P- or B-slice found" );
 
     if( !( slice.isIRAP() || bestMode.type == ETM_INTRA || 
-          ( ( !m_pcEncCfg->getDisableIntraPUsInInterSlices() ) && !relatedCU.isInter && (
+#if IBC_SEPERATE_MODE
+      ((!m_pcEncCfg->getDisableIntraPUsInInterSlices()) && (!relatedCU.isInter || !relatedCU.isIBC) && (
+#else    
+      ( ( !m_pcEncCfg->getDisableIntraPUsInInterSlices() ) && !relatedCU.isInter && (
+#endif
                                          ( cuECtx.bestTU->cbf[0] != 0 ) ||
            ( ( numComp > COMPONENT_Cb ) && cuECtx.bestTU->cbf[1] != 0 ) ||
            ( ( numComp > COMPONENT_Cr ) && cuECtx.bestTU->cbf[2] != 0 )  // avoid very complex intra if it is unlikely
@@ -1313,7 +1325,11 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
       if( !cs.slice->isIRAP() && m_pcEncCfg->getUsePbIntraFast() )
       {
         CodingUnit* bestCU = cuECtx.bestCU;
+#if IBC_SEPERATE_MODE
+        if (bestCU && !CU::isIntra(*bestCU))
+#else
         if( bestCU && CU::isInter( *bestCU ) )
+#endif
         {
           DistParam distParam;
           const bool useHad = !bestCU->transQuantBypass;
@@ -1407,7 +1423,11 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
     //////////////////////////////////////////////////////////////////////////
     int skipScore = 0;
 
+#if IBC_SEPERATE_MODE 
+    if ((!slice.isIntra() || slice.getSPS()->getSpsNext().getIBCMode()) && cuECtx.get<bool>(IS_BEST_NOSPLIT_SKIP))
+#else
     if( !slice.isIntra() && cuECtx.get<bool>( IS_BEST_NOSPLIT_SKIP ) )
+#endif
     {
       for( int i = 2; i < m_ComprCUCtxList.size(); i++ )
       {
@@ -1502,6 +1522,15 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
             const CodingUnit *cuBR = bestCS->cus.back();
             unsigned height        = partitioner.currArea().lumaSize().height;
 
+#if IBC_SEPERATE_MODE
+            if (bestCU && ((bestCU->btDepth == 0 && maxBTD >= ((slice.isIntra() && !slice.getSPS()->getSpsNext().getIBCMode()) ? 3 : 2))
+              || (bestCU->btDepth == 1 && cuBR && cuBR->btDepth == 1 && maxBTD >= ((slice.isIntra() && !slice.getSPS()->getSpsNext().getIBCMode()) ? 4 : 3)))
+              && (width <= MAX_TU_SIZE_FOR_PROFILE && height <= MAX_TU_SIZE_FOR_PROFILE)
+              && cuECtx.get<bool>(DID_HORZ_SPLIT) && cuECtx.get<bool>(DID_VERT_SPLIT))
+            {
+              return false;
+            }
+#else
             if( bestCU && ( ( bestCU->btDepth == 0 &&                               maxBTD >= ( slice.isIntra() ? 3 : 2 ) )
                          || ( bestCU->btDepth == 1 && cuBR && cuBR->btDepth == 1 && maxBTD >= ( slice.isIntra() ? 4 : 3 ) ) )
                        && ( width <= MAX_TU_SIZE_FOR_PROFILE && height <= MAX_TU_SIZE_FOR_PROFILE )
@@ -1509,6 +1538,7 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
             {
               return false;
             }
+#endif
           }
           if( m_pcEncCfg->getUseEarlyCU() && bestCS->cost != MAX_DOUBLE && bestCU && bestCU->skip )
           {
@@ -1613,6 +1643,15 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
 #endif
           relatedCU.GBiIdx    = bestCU->GBiIdx;
         }
+#if IBC_SEPERATE_MODE//Todo : macro hm_code_cu_info
+        else if (CU::isIBC(*bestCU))
+        {
+          relatedCU.isIBC = true;
+#if HM_CODED_CU_INFO
+          relatedCU.isSkip |= bestCU->skip;
+#endif
+        }
+#endif
         else if( CU::isIntra( *bestCU ) )
         {
           relatedCU.isIntra   = true;
diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h
index 422e4c8084..faf84491ff 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.h
+++ b/source/Lib/EncoderLib/EncModeCtrl.h
@@ -327,6 +327,9 @@ struct CodedCUInfo
   bool isIntra;
   bool isSkip;
   bool isMMVDSkip;
+#if IBC_SEPERATE_MODE
+  bool isIBC;
+#endif
   bool validMv[NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS];
   Mv   saveMv [NUM_REF_PIC_LIST_01][MAX_STORED_CU_INFO_REFS];
 
diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp
index 73b9cc08af..1c73d78b05 100644
--- a/source/Lib/EncoderLib/EncSlice.cpp
+++ b/source/Lib/EncoderLib/EncSlice.cpp
@@ -536,7 +536,11 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr
  #endif
   if(rpcSlice->getPPS()->getSliceChromaQpFlag())
   {
+#if IBC_SEPERATE_MODE
+    const bool bUseIntraOrPeriodicOffset = (rpcSlice->isIntra() && !rpcSlice->getSPS()->getSpsNext().getIBCMode()) || (m_pcCfg->getSliceChromaOffsetQpPeriodicity() > 0 && (rpcSlice->getPOC() % m_pcCfg->getSliceChromaOffsetQpPeriodicity()) == 0);
+#else
     const bool bUseIntraOrPeriodicOffset = rpcSlice->isIntra() || (m_pcCfg->getSliceChromaOffsetQpPeriodicity() > 0 && (rpcSlice->getPOC() % m_pcCfg->getSliceChromaOffsetQpPeriodicity()) == 0);
+#endif
     int cbQP = bUseIntraOrPeriodicOffset ? m_pcCfg->getSliceChromaOffsetQpIntraOrPeriodic(false) : m_pcCfg->getGOPEntry(iGOPid).m_CbQPoffset;
     int crQP = bUseIntraOrPeriodicOffset ? m_pcCfg->getSliceChromaOffsetQpIntraOrPeriodic(true)  : m_pcCfg->getGOPEntry(iGOPid).m_CrQPoffset;
 
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index 81ac4b3378..7d7d6717d6 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -762,7 +762,11 @@ int InterSearch::xIBCSearchMVChromaRefine(PredictionUnit& pu,
     pu.mv[0] = cMVCand[cand];
     pu.mv[0].changePrecision(MV_PRECISION_INT, MV_PRECISION_INTERNAL);
     pu.interDir = 1;
+#if IBC_SEPERATE_MODE
+    pu.refIdx[0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0); // last idx in the list
+#else
     pu.refIdx[0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0) - 1; // last idx in the list
+#endif
 
     PelUnitBuf predBufTmp = m_tmpPredStorage[REF_PIC_LIST_0].getBuf(UnitAreaRelative(*pu.cu, pu));
     motionCompensation(pu, predBufTmp, REF_PIC_LIST_0);
@@ -1300,13 +1304,20 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
     /// ibc search
     pu.cu->imv = 2;
     AMVPInfo amvpInfo4Pel;
+#if IBC_SEPERATE_FUNCTION
+    PU::fillIBCMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0], amvpInfo4Pel);
+#else
     PU::fillMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0], amvpInfo4Pel);
-
+#endif
 
     pu.cu->imv = 0;// (Int)cu.cs->sps->getSpsNext().getUseIMV(); // set as IMV=0 initially
     Mv    cMv, cMvPred[2];
     AMVPInfo amvpInfo;
+#if IBC_SEPERATE_FUNCTION
+    PU::fillIBCMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0], amvpInfo);
+#else
     PU::fillMvpCand(pu, REF_PIC_LIST_0, pu.refIdx[REF_PIC_LIST_0], amvpInfo);
+#endif
     cMvPred[0].set(amvpInfo.mvCand[0].getHor() >> (2), amvpInfo.mvCand[0].getVer() >> (2)); // store in full pel accuracy, shift before use in search
     cMvPred[1].set(amvpInfo.mvCand[1].getHor() >> (2), amvpInfo.mvCand[1].getVer() >> (2));
 
@@ -1403,7 +1414,11 @@ bool InterSearch::predIBCSearch(CodingUnit& cu, Partitioner& partitioner, const
     if (!cu.cs->sps->getSpsNext().getUseIMV())
       pu.mvd[REF_PIC_LIST_0] >>= (2);
 
+#if IBC_SEPERATE_MODE
+    pu.refIdx[REF_PIC_LIST_0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0);
+#else
     pu.refIdx[REF_PIC_LIST_0] = pu.cs->slice->getNumRefIdx(REF_PIC_LIST_0) - 1;
+#endif
     pu.mv[REF_PIC_LIST_0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
 
     m_ctuRecord[cu.lumaPos()][cu.lumaSize()].bvRecord[pu.bv] = cost;
@@ -1587,12 +1602,16 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
       for ( int iRefList = 0; iRefList < iNumPredDir; iRefList++ )
       {
         RefPicList  eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );
+#if IBC_SEPERATE_MODE==0
         int refPicNumber = cs.slice->getNumRefIdx(eRefPicList);
         if (cs.slice->getSPS()->getSpsNext().getIBCMode() && eRefPicList == REF_PIC_LIST_0)
         {
           refPicNumber--;
         }
         for (int iRefIdxTemp = 0; iRefIdxTemp < refPicNumber; iRefIdxTemp++)
+#else
+        for (int iRefIdxTemp = 0; iRefIdxTemp < cs.slice->getNumRefIdx(eRefPicList); iRefIdxTemp++)
+#endif
         {
           uiBitsTemp = uiMbBits[iRefList];
           if ( cs.slice->getNumRefIdx(eRefPicList) > 1 )
@@ -1794,10 +1813,12 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
 
           iRefStart = 0;
           iRefEnd   = cs.slice->getNumRefIdx(eRefPicList)-1;
+#if IBC_SEPERATE_MODE==0
           if (cs.slice->getSPS()->getSpsNext().getIBCMode() && eRefPicList == REF_PIC_LIST_0)
           {
             iRefEnd--;
           }
+#endif
           for (int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++)
           {
             if( m_pcEncCfg->getUseGBiFast() && (gbiIdx != GBI_DEFAULT)
@@ -2055,6 +2076,11 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
         cu.GBiIdx = GBI_DEFAULT; // Reset to default for the Non-NormalMC modes.
       }
 
+#if IBC_SEPERATE_MODE//Todo : no cu.partsize
+      //no mergeestimation
+      //xMergeEstimation(pu, origBuf, puIdx, uiMRGIndex, uiMRGCost, mergeCtx);
+#endif
+
     uiHevcCost = ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1] ) ? uiCostBi : ( ( uiCost[0] <= uiCost[1] ) ? uiCost[0] : uiCost[1] );
     if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getSpsNext().getUseAffine() && cu.imv == 0
       && (gbiIdx == GBI_DEFAULT || m_affineModeSelected || !m_pcEncCfg->getUseGBiFast())
@@ -3493,12 +3519,16 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
   for ( int iRefList = 0; iRefList < iNumPredDir; iRefList++ )
   {
     RefPicList  eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );
+#if IBC_SEPERATE_MODE==0
     int refPicNumber = slice.getNumRefIdx(eRefPicList);
     if (slice.getSPS()->getSpsNext().getIBCMode() && eRefPicList == REF_PIC_LIST_0)
     {
       refPicNumber--;
     }
     for (int iRefIdxTemp = 0; iRefIdxTemp < refPicNumber; iRefIdxTemp++)
+#else
+    for (int iRefIdxTemp = 0; iRefIdxTemp < slice.getNumRefIdx(eRefPicList); iRefIdxTemp++)
+#endif
     {
       // Get RefIdx bits
       uiBitsTemp = uiMbBits[iRefList];
@@ -3876,10 +3906,12 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
 
       iRefStart = 0;
       iRefEnd   = slice.getNumRefIdx(eRefPicList) - 1;
+#if IBC_SEPERATE_MODE==0
       if (slice.getSPS()->getSpsNext().getIBCMode() && eRefPicList == REF_PIC_LIST_0)
       {
         iRefEnd--;
       }
+#endif
       for ( int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++ )
       {
         if ( pu.cu->affineType == AFFINEMODEL_6PARAM && refIdx4Para[iRefList] != iRefIdxTemp )
@@ -5584,6 +5616,14 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa
     PredictionUnit &pu = *cs.getPU( partitioner.chType );
 
     m_CABACEstimator->cu_skip_flag  ( cu );
+#if IBC_SEPERATE_MODE
+    if (CU::isIBC(cu))
+    {
+      m_CABACEstimator->merge_idx(pu);
+    }
+    else
+    {
+#endif
     m_CABACEstimator->subblock_merge_flag( cu );
     m_CABACEstimator->triangle_mode ( cu );
     if (cu.mmvdSkip)
@@ -5592,7 +5632,9 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa
     }
     else
     m_CABACEstimator->merge_idx     ( pu );
-
+#if IBC_SEPERATE_MODE
+    }
+#endif
 
     cs.dist     = distortion;
     cs.fracBits = m_CABACEstimator->getEstFracBits();
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index ac23b0a313..cddf799dce 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -1012,7 +1012,11 @@ void IntraSearch::xEncIntraHeader(CodingStructure &cs, Partitioner &partitioner,
     // CU header
     if( isFirst )
     {
+#if IBC_SEPERATE_MODE 
+      if ((!cs.slice->isIntra() || cs.slice->getSPS()->getSpsNext().getIBCMode())
+#else
       if( !cs.slice->isIntra() 
+#endif
         && cu.Y().valid()
         )
       {
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 34a8b308db..22fddc7411 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -1265,10 +1265,19 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
         }
       }
     }
+#if IBC_SEPERATE_MODE 
+    if (!cs.slice->isIntra() || cs.slice->getSPS()->getSpsNext().getIBCMode())
+    {
+      CHECK(pcSlice->getMaxNumMergeCand() > MRG_MAX_NUM_CANDS, "More merge candidates signalled than supported");
+      WRITE_UVLC(MRG_MAX_NUM_CANDS - pcSlice->getMaxNumMergeCand(), "six_minus_max_num_merge_cand");
+    }
+#endif
     if( !pcSlice->isIntra() )
     {
+#if IBC_SEPERATE_MODE==0
       CHECK( pcSlice->getMaxNumMergeCand() > MRG_MAX_NUM_CANDS, "More merge candidates signalled than supported" );
       WRITE_UVLC( MRG_MAX_NUM_CANDS - pcSlice->getMaxNumMergeCand(), "six_minus_max_num_merge_cand" );
+#endif
 
       if ( pcSlice->getSPS()->getSBTMVPEnabledFlag() && !pcSlice->getSPS()->getSpsNext().getUseAffine() ) // ATMVP only
       {
-- 
GitLab